|
|
@ -1,6 +1,8 @@ |
|
|
|
|
|
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project |
|
|
|
|
|
// SPDX-License-Identifier: GPL-3.0-or-later |
|
|
|
|
|
|
|
|
package org.yuzu.yuzu_emu.fragments |
|
|
package org.yuzu.yuzu_emu.fragments |
|
|
|
|
|
|
|
|
import android.app.AlertDialog |
|
|
|
|
|
import android.os.Bundle |
|
|
import android.os.Bundle |
|
|
import androidx.fragment.app.Fragment |
|
|
import androidx.fragment.app.Fragment |
|
|
import android.view.LayoutInflater |
|
|
import android.view.LayoutInflater |
|
|
@ -28,10 +30,12 @@ import org.yuzu.yuzu_emu.databinding.FragmentDriverFetcherBinding |
|
|
import org.yuzu.yuzu_emu.features.fetcher.DriverGroupAdapter |
|
|
import org.yuzu.yuzu_emu.features.fetcher.DriverGroupAdapter |
|
|
import org.yuzu.yuzu_emu.model.DriverViewModel |
|
|
import org.yuzu.yuzu_emu.model.DriverViewModel |
|
|
import org.yuzu.yuzu_emu.utils.GpuDriverHelper |
|
|
import org.yuzu.yuzu_emu.utils.GpuDriverHelper |
|
|
import org.yuzu.yuzu_emu.utils.Log |
|
|
|
|
|
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins |
|
|
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins |
|
|
import java.io.IOException |
|
|
import java.io.IOException |
|
|
import java.net.URL |
|
|
import java.net.URL |
|
|
|
|
|
import java.time.Instant |
|
|
|
|
|
import java.time.LocalDateTime |
|
|
|
|
|
import java.time.ZoneId |
|
|
import kotlin.getValue |
|
|
import kotlin.getValue |
|
|
|
|
|
|
|
|
class DriverFetcherFragment : Fragment() { |
|
|
class DriverFetcherFragment : Fragment() { |
|
|
@ -49,17 +53,22 @@ class DriverFetcherFragment : Fragment() { |
|
|
private val recommendedDriver: String |
|
|
private val recommendedDriver: String |
|
|
get() = driverMap.firstOrNull { adrenoModel in it.first }?.second ?: "Unsupported" |
|
|
get() = driverMap.firstOrNull { adrenoModel in it.first }?.second ?: "Unsupported" |
|
|
|
|
|
|
|
|
|
|
|
enum class SortMode { |
|
|
|
|
|
Default, PublishTime, |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private data class DriverRepo( |
|
|
private data class DriverRepo( |
|
|
val name: String = "", |
|
|
val name: String = "", |
|
|
val path: String = "", |
|
|
val path: String = "", |
|
|
val sort: Int = 0, |
|
|
val sort: Int = 0, |
|
|
val useTagName: Boolean = false |
|
|
|
|
|
|
|
|
val useTagName: Boolean = false, |
|
|
|
|
|
val sortMode: SortMode = SortMode.Default, |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
private val repoList: List<DriverRepo> = listOf( |
|
|
private val repoList: List<DriverRepo> = listOf( |
|
|
DriverRepo("Mr. Purple Turnip", "MrPurple666/purple-turnip", 0), |
|
|
DriverRepo("Mr. Purple Turnip", "MrPurple666/purple-turnip", 0), |
|
|
DriverRepo("GameHub Adreno 8xx", "crueter/GameHub-8Elite-Drivers", 1), |
|
|
DriverRepo("GameHub Adreno 8xx", "crueter/GameHub-8Elite-Drivers", 1), |
|
|
DriverRepo("KIMCHI Turnip", "K11MCH1/AdrenoToolsDrivers", 2, true), |
|
|
|
|
|
|
|
|
DriverRepo("KIMCHI Turnip", "K11MCH1/AdrenoToolsDrivers", 2, true, SortMode.PublishTime), |
|
|
DriverRepo("Weab-Chan Freedreno", "Weab-chan/freedreno_turnip-CI", 3), |
|
|
DriverRepo("Weab-Chan Freedreno", "Weab-chan/freedreno_turnip-CI", 3), |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
@ -78,7 +87,7 @@ class DriverFetcherFragment : Fragment() { |
|
|
private lateinit var driverGroupAdapter: DriverGroupAdapter |
|
|
private lateinit var driverGroupAdapter: DriverGroupAdapter |
|
|
private val driverViewModel: DriverViewModel by activityViewModels() |
|
|
private val driverViewModel: DriverViewModel by activityViewModels() |
|
|
|
|
|
|
|
|
fun parseAdrenoModel(): Int { |
|
|
|
|
|
|
|
|
private fun parseAdrenoModel(): Int { |
|
|
if (gpuModel == null) { |
|
|
if (gpuModel == null) { |
|
|
return 0 |
|
|
return 0 |
|
|
} |
|
|
} |
|
|
@ -115,9 +124,8 @@ class DriverFetcherFragment : Fragment() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
override fun onCreateView( |
|
|
override fun onCreateView( |
|
|
inflater: LayoutInflater, container: ViewGroup?, |
|
|
|
|
|
savedInstanceState: Bundle? |
|
|
|
|
|
): View? { |
|
|
|
|
|
|
|
|
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? |
|
|
|
|
|
): View { |
|
|
_binding = FragmentDriverFetcherBinding.inflate(inflater) |
|
|
_binding = FragmentDriverFetcherBinding.inflate(inflater) |
|
|
binding.badgeRecommendedDriver.text = recommendedDriver |
|
|
binding.badgeRecommendedDriver.text = recommendedDriver |
|
|
binding.badgeGpuModel.text = gpuModel |
|
|
binding.badgeGpuModel.text = gpuModel |
|
|
@ -150,11 +158,12 @@ class DriverFetcherFragment : Fragment() { |
|
|
val name = driver.name |
|
|
val name = driver.name |
|
|
val path = driver.path |
|
|
val path = driver.path |
|
|
val useTagName = driver.useTagName |
|
|
val useTagName = driver.useTagName |
|
|
|
|
|
val sortMode = driver.sortMode |
|
|
val sort = driver.sort |
|
|
val sort = driver.sort |
|
|
|
|
|
|
|
|
CoroutineScope(Dispatchers.Main).launch { |
|
|
CoroutineScope(Dispatchers.Main).launch { |
|
|
val request = Request.Builder() |
|
|
|
|
|
.url("https://api.github.com/repos/$path/releases") |
|
|
|
|
|
.build() |
|
|
|
|
|
|
|
|
val request = |
|
|
|
|
|
Request.Builder().url("https://api.github.com/repos/$path/releases").build() |
|
|
|
|
|
|
|
|
withContext(Dispatchers.IO) { |
|
|
withContext(Dispatchers.IO) { |
|
|
var releases: ArrayList<Release> |
|
|
var releases: ArrayList<Release> |
|
|
@ -165,28 +174,25 @@ class DriverFetcherFragment : Fragment() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
val body = response.body?.string() ?: return@withContext |
|
|
val body = response.body?.string() ?: return@withContext |
|
|
releases = Release.fromJsonArray(body, useTagName) |
|
|
|
|
|
|
|
|
releases = Release.fromJsonArray(body, useTagName, sortMode) |
|
|
} |
|
|
} |
|
|
} catch (e: Exception) { |
|
|
} catch (e: Exception) { |
|
|
withContext(Dispatchers.Main) { |
|
|
withContext(Dispatchers.Main) { |
|
|
MaterialAlertDialogBuilder(requireActivity().applicationContext) |
|
|
|
|
|
.setTitle(getString(R.string.error_during_fetch)) |
|
|
|
|
|
|
|
|
MaterialAlertDialogBuilder(requireActivity()).setTitle(getString(R.string.error_during_fetch)) |
|
|
.setMessage("${getString(R.string.failed_to_fetch)} ${name}:\n${e.message}") |
|
|
.setMessage("${getString(R.string.failed_to_fetch)} ${name}:\n${e.message}") |
|
|
.setPositiveButton(getString(R.string.ok)) { dialog, _ -> dialog.cancel() } |
|
|
.setPositiveButton(getString(R.string.ok)) { dialog, _ -> dialog.cancel() } |
|
|
.show() |
|
|
.show() |
|
|
|
|
|
|
|
|
releases = ArrayList<Release>() |
|
|
|
|
|
|
|
|
releases = ArrayList() |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
val driver = DriverGroup( |
|
|
|
|
|
name, |
|
|
|
|
|
releases, |
|
|
|
|
|
sort |
|
|
|
|
|
|
|
|
val group = DriverGroup( |
|
|
|
|
|
name, releases, sort |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
synchronized(driverGroups) { |
|
|
synchronized(driverGroups) { |
|
|
driverGroups.add(driver) |
|
|
|
|
|
|
|
|
driverGroups.add(group) |
|
|
driverGroups.sortBy { |
|
|
driverGroups.sortBy { |
|
|
it.sort |
|
|
it.sort |
|
|
} |
|
|
} |
|
|
@ -204,8 +210,7 @@ class DriverFetcherFragment : Fragment() { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private fun setInsets() = |
|
|
|
|
|
ViewCompat.setOnApplyWindowInsetsListener( |
|
|
|
|
|
|
|
|
private fun setInsets() = ViewCompat.setOnApplyWindowInsetsListener( |
|
|
binding.root |
|
|
binding.root |
|
|
) { _: View, windowInsets: WindowInsetsCompat -> |
|
|
) { _: View, windowInsets: WindowInsetsCompat -> |
|
|
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) |
|
|
val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars()) |
|
|
@ -218,8 +223,7 @@ class DriverFetcherFragment : Fragment() { |
|
|
binding.listDrivers.updateMargins(left = leftInsets, right = rightInsets) |
|
|
binding.listDrivers.updateMargins(left = leftInsets, right = rightInsets) |
|
|
|
|
|
|
|
|
binding.listDrivers.updatePadding( |
|
|
binding.listDrivers.updatePadding( |
|
|
bottom = barInsets.bottom + |
|
|
|
|
|
resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab) |
|
|
|
|
|
|
|
|
bottom = barInsets.bottom + resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab) |
|
|
) |
|
|
) |
|
|
|
|
|
|
|
|
windowInsets |
|
|
windowInsets |
|
|
@ -229,14 +233,18 @@ class DriverFetcherFragment : Fragment() { |
|
|
|
|
|
|
|
|
data class Release( |
|
|
data class Release( |
|
|
var tagName: String = "", |
|
|
var tagName: String = "", |
|
|
|
|
|
var titleName: String = "", |
|
|
var title: String = "", |
|
|
var title: String = "", |
|
|
var body: String = "", |
|
|
var body: String = "", |
|
|
var artifacts: List<Artifact> = ArrayList<Artifact>(), |
|
|
|
|
|
|
|
|
var artifacts: List<Artifact> = ArrayList(), |
|
|
var prerelease: Boolean = false, |
|
|
var prerelease: Boolean = false, |
|
|
var latest: Boolean = false |
|
|
|
|
|
|
|
|
var latest: Boolean = false, |
|
|
|
|
|
var publishTime: LocalDateTime = LocalDateTime.now(), |
|
|
) { |
|
|
) { |
|
|
companion object { |
|
|
companion object { |
|
|
fun fromJsonArray(jsonString: String, useTagName: Boolean): ArrayList<Release> { |
|
|
|
|
|
|
|
|
fun fromJsonArray( |
|
|
|
|
|
jsonString: String, useTagName: Boolean, sortMode: SortMode |
|
|
|
|
|
): ArrayList<Release> { |
|
|
val mapper = jacksonObjectMapper() |
|
|
val mapper = jacksonObjectMapper() |
|
|
|
|
|
|
|
|
try { |
|
|
try { |
|
|
@ -256,39 +264,55 @@ class DriverFetcherFragment : Fragment() { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
releases.add(release) |
|
|
releases.add(release) |
|
|
|
|
|
|
|
|
|
|
|
println(release.publishTime) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
when (sortMode) { |
|
|
|
|
|
SortMode.PublishTime -> releases.sortByDescending { |
|
|
|
|
|
it.publishTime |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
else -> {} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
return releases |
|
|
return releases |
|
|
} catch (e: Exception) { |
|
|
} catch (e: Exception) { |
|
|
e.printStackTrace() |
|
|
e.printStackTrace() |
|
|
return ArrayList<Release>() |
|
|
|
|
|
|
|
|
return ArrayList() |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
fun fromJson(node: JsonNode, useTagName: Boolean): Release { |
|
|
|
|
|
|
|
|
private fun fromJson(node: JsonNode, useTagName: Boolean): Release { |
|
|
try { |
|
|
try { |
|
|
val tagName = node.get("tag_name").toString().removeSurrounding("\"") |
|
|
val tagName = node.get("tag_name").toString().removeSurrounding("\"") |
|
|
val body = node.get("body").toString().removeSurrounding("\"") |
|
|
val body = node.get("body").toString().removeSurrounding("\"") |
|
|
val prerelease = node.get("prerelease").toString().toBoolean() |
|
|
val prerelease = node.get("prerelease").toString().toBoolean() |
|
|
val title = if (useTagName) tagName else node.get("name").toString().removeSurrounding("\"") |
|
|
|
|
|
|
|
|
val titleName = node.get("name").toString().removeSurrounding("\"") |
|
|
|
|
|
|
|
|
|
|
|
val published = node.get("published_at").toString().removeSurrounding("\"") |
|
|
|
|
|
val instantTime: Instant? = Instant.parse(published) |
|
|
|
|
|
val localTime = instantTime?.atZone(ZoneId.systemDefault())?.toLocalDateTime() ?: LocalDateTime.now() |
|
|
|
|
|
|
|
|
|
|
|
val title = if (useTagName) tagName else titleName |
|
|
|
|
|
|
|
|
val assets = node.get("assets") |
|
|
val assets = node.get("assets") |
|
|
val artifacts = ArrayList<Artifact>() |
|
|
val artifacts = ArrayList<Artifact>() |
|
|
if (assets?.isArray == true) { |
|
|
if (assets?.isArray == true) { |
|
|
assets.forEach { node -> |
|
|
|
|
|
val urlStr = |
|
|
|
|
|
node.get("browser_download_url").toString().removeSurrounding("\"") |
|
|
|
|
|
|
|
|
assets.forEach { subNode -> |
|
|
|
|
|
val urlStr = subNode.get("browser_download_url").toString() |
|
|
|
|
|
.removeSurrounding("\"") |
|
|
|
|
|
|
|
|
val url = URL(urlStr) |
|
|
val url = URL(urlStr) |
|
|
val name = node.get("name").toString().removeSurrounding("\"") |
|
|
|
|
|
|
|
|
val name = subNode.get("name").toString().removeSurrounding("\"") |
|
|
|
|
|
|
|
|
val artifact = Artifact(url, name) |
|
|
val artifact = Artifact(url, name) |
|
|
artifacts.add(artifact) |
|
|
artifacts.add(artifact) |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return Release(tagName, title, body, artifacts, prerelease) |
|
|
|
|
|
|
|
|
return Release(tagName, titleName, title, body, artifacts, prerelease, false, localTime) |
|
|
} catch (e: Exception) { |
|
|
} catch (e: Exception) { |
|
|
// TODO: handle malformed input. |
|
|
// TODO: handle malformed input. |
|
|
e.printStackTrace() |
|
|
e.printStackTrace() |
|
|
|