aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt55
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt118
-rw-r--r--src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt8
3 files changed, 117 insertions, 64 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt
index 06105d2702..14d69cb384 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/fetcher/DriverGroupAdapter.kt
@@ -1,3 +1,6 @@
+// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
package org.yuzu.yuzu_emu.features.fetcher
import android.annotation.SuppressLint
@@ -17,7 +20,9 @@ import androidx.transition.TransitionManager
import androidx.transition.TransitionSet
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
import org.yuzu.yuzu_emu.model.DriverViewModel
class DriverGroupAdapter(
@@ -25,43 +30,61 @@ class DriverGroupAdapter(
private val driverViewModel: DriverViewModel
) : RecyclerView.Adapter<DriverGroupAdapter.DriverGroupViewHolder>() {
private var driverGroups: List<DriverGroup> = emptyList()
+ private val adapterJobs = mutableMapOf<Int, Job>()
inner class DriverGroupViewHolder(
private val binding: ItemDriverGroupBinding
) : RecyclerView.ViewHolder(binding.root) {
fun bind(group: DriverGroup) {
+ binding.textGroupName.text = group.name
+
+ if (binding.recyclerReleases.layoutManager == null) {
+ binding.recyclerReleases.layoutManager = LinearLayoutManager(activity)
+ binding.recyclerReleases.addItemDecoration(
+ SpacingItemDecoration(
+ (activity.resources.displayMetrics.density * 8).toInt()
+ )
+ )
+ }
+
val onClick = {
+ adapterJobs[bindingAdapterPosition]?.cancel()
+
TransitionManager.beginDelayedTransition(
binding.root,
TransitionSet().addTransition(Fade()).addTransition(ChangeBounds())
.setDuration(200)
)
- val isVisible = binding.recyclerReleases.isVisible
- binding.recyclerReleases.visibility = if (isVisible) View.GONE else View.VISIBLE
- binding.imageDropdownArrow.rotation = if (isVisible) 0f else 180f
+ val isVisible = binding.recyclerReleases.isVisible
if (!isVisible && binding.recyclerReleases.adapter == null) {
- CoroutineScope(Dispatchers.Main).launch {
- binding.recyclerReleases.layoutManager =
- LinearLayoutManager(binding.root.context)
- binding.recyclerReleases.adapter =
- ReleaseAdapter(group.releases, activity, driverViewModel)
-
- binding.recyclerReleases.addItemDecoration(
- SpacingItemDecoration(
- (activity.resources.displayMetrics.density * 8).toInt()
- )
- )
+ val job = CoroutineScope(Dispatchers.Main).launch {
+ // It prevents blocking the ui thread.
+ var adapter: ReleaseAdapter?
+
+ withContext(Dispatchers.IO) {
+ adapter = ReleaseAdapter(group.releases, activity, driverViewModel)
+ }
+
+ binding.recyclerReleases.adapter = adapter
}
+
+ adapterJobs[bindingAdapterPosition] = job
}
+
+ binding.recyclerReleases.visibility = if (isVisible) View.GONE else View.VISIBLE
+ binding.imageDropdownArrow.rotation = if (isVisible) 0f else 180f
}
- binding.textGroupName.text = group.name
binding.textGroupName.setOnClickListener { onClick() }
-
binding.imageDropdownArrow.setOnClickListener { onClick() }
}
+
+ fun clear() {
+ adapterJobs[bindingAdapterPosition]?.cancel()
+ adapterJobs.remove(bindingAdapterPosition)
+ }
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): DriverGroupViewHolder {
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt
index 7c6dc238e3..0c1e39d095 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/fragments/DriverFetcherFragment.kt
@@ -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
-import android.app.AlertDialog
import android.os.Bundle
import androidx.fragment.app.Fragment
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.model.DriverViewModel
import org.yuzu.yuzu_emu.utils.GpuDriverHelper
-import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.ViewUtils.updateMargins
import java.io.IOException
import java.net.URL
+import java.time.Instant
+import java.time.LocalDateTime
+import java.time.ZoneId
import kotlin.getValue
class DriverFetcherFragment : Fragment() {
@@ -49,17 +53,22 @@ class DriverFetcherFragment : Fragment() {
private val recommendedDriver: String
get() = driverMap.firstOrNull { adrenoModel in it.first }?.second ?: "Unsupported"
+ enum class SortMode {
+ Default, PublishTime,
+ }
+
private data class DriverRepo(
val name: String = "",
val path: String = "",
val sort: Int = 0,
- val useTagName: Boolean = false
+ val useTagName: Boolean = false,
+ val sortMode: SortMode = SortMode.Default,
)
private val repoList: List<DriverRepo> = listOf(
DriverRepo("Mr. Purple Turnip", "MrPurple666/purple-turnip", 0),
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),
)
@@ -78,7 +87,7 @@ class DriverFetcherFragment : Fragment() {
private lateinit var driverGroupAdapter: DriverGroupAdapter
private val driverViewModel: DriverViewModel by activityViewModels()
- fun parseAdrenoModel(): Int {
+ private fun parseAdrenoModel(): Int {
if (gpuModel == null) {
return 0
}
@@ -115,9 +124,8 @@ class DriverFetcherFragment : Fragment() {
}
override fun onCreateView(
- inflater: LayoutInflater, container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
+ inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
+ ): View {
_binding = FragmentDriverFetcherBinding.inflate(inflater)
binding.badgeRecommendedDriver.text = recommendedDriver
binding.badgeGpuModel.text = gpuModel
@@ -150,11 +158,12 @@ class DriverFetcherFragment : Fragment() {
val name = driver.name
val path = driver.path
val useTagName = driver.useTagName
+ val sortMode = driver.sortMode
val sort = driver.sort
+
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) {
var releases: ArrayList<Release>
@@ -165,28 +174,25 @@ class DriverFetcherFragment : Fragment() {
}
val body = response.body?.string() ?: return@withContext
- releases = Release.fromJsonArray(body, useTagName)
+ releases = Release.fromJsonArray(body, useTagName, sortMode)
}
} catch (e: Exception) {
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}")
.setPositiveButton(getString(R.string.ok)) { dialog, _ -> dialog.cancel() }
.show()
- releases = ArrayList<Release>()
+ releases = ArrayList()
}
}
- val driver = DriverGroup(
- name,
- releases,
- sort
+ val group = DriverGroup(
+ name, releases, sort
)
synchronized(driverGroups) {
- driverGroups.add(driver)
+ driverGroups.add(group)
driverGroups.sortBy {
it.sort
}
@@ -204,39 +210,41 @@ class DriverFetcherFragment : Fragment() {
}
}
- private fun setInsets() =
- ViewCompat.setOnApplyWindowInsetsListener(
- binding.root
- ) { _: View, windowInsets: WindowInsetsCompat ->
- val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
- val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
+ private fun setInsets() = ViewCompat.setOnApplyWindowInsetsListener(
+ binding.root
+ ) { _: View, windowInsets: WindowInsetsCompat ->
+ val barInsets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
+ val cutoutInsets = windowInsets.getInsets(WindowInsetsCompat.Type.displayCutout())
- val leftInsets = barInsets.left + cutoutInsets.left
- val rightInsets = barInsets.right + cutoutInsets.right
+ val leftInsets = barInsets.left + cutoutInsets.left
+ val rightInsets = barInsets.right + cutoutInsets.right
- binding.toolbarDrivers.updateMargins(left = leftInsets, right = rightInsets)
- binding.listDrivers.updateMargins(left = leftInsets, right = rightInsets)
+ binding.toolbarDrivers.updateMargins(left = leftInsets, right = rightInsets)
+ binding.listDrivers.updateMargins(left = leftInsets, right = rightInsets)
- binding.listDrivers.updatePadding(
- bottom = barInsets.bottom +
- resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab)
- )
+ binding.listDrivers.updatePadding(
+ bottom = barInsets.bottom + resources.getDimensionPixelSize(R.dimen.spacing_bottom_list_fab)
+ )
- windowInsets
- }
+ windowInsets
+ }
data class Artifact(val url: URL, val name: String)
data class Release(
var tagName: String = "",
+ var titleName: String = "",
var title: String = "",
var body: String = "",
- var artifacts: List<Artifact> = ArrayList<Artifact>(),
+ var artifacts: List<Artifact> = ArrayList(),
var prerelease: Boolean = false,
- var latest: Boolean = false
+ var latest: Boolean = false,
+ var publishTime: LocalDateTime = LocalDateTime.now(),
) {
companion object {
- fun fromJsonArray(jsonString: String, useTagName: Boolean): ArrayList<Release> {
+ fun fromJsonArray(
+ jsonString: String, useTagName: Boolean, sortMode: SortMode
+ ): ArrayList<Release> {
val mapper = jacksonObjectMapper()
try {
@@ -256,39 +264,55 @@ class DriverFetcherFragment : Fragment() {
}
releases.add(release)
+
+ println(release.publishTime)
}
}
+ when (sortMode) {
+ SortMode.PublishTime -> releases.sortByDescending {
+ it.publishTime
+ }
+
+ else -> {}
+ }
+
return releases
} catch (e: Exception) {
e.printStackTrace()
- return ArrayList<Release>()
+ return ArrayList()
}
}
- fun fromJson(node: JsonNode, useTagName: Boolean): Release {
+ private fun fromJson(node: JsonNode, useTagName: Boolean): Release {
try {
val tagName = node.get("tag_name").toString().removeSurrounding("\"")
val body = node.get("body").toString().removeSurrounding("\"")
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 artifacts = ArrayList<Artifact>()
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 name = node.get("name").toString().removeSurrounding("\"")
+ val name = subNode.get("name").toString().removeSurrounding("\"")
val artifact = Artifact(url, name)
artifacts.add(artifact)
}
}
- return Release(tagName, title, body, artifacts, prerelease)
+ return Release(tagName, titleName, title, body, artifacts, prerelease, false, localTime)
} catch (e: Exception) {
// TODO: handle malformed input.
e.printStackTrace()
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
index 3a9c5486a8..5177e78874 100644
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
@@ -335,7 +335,13 @@ class MainActivity : AppCompatActivity(), ThemeProvider {
Toast.LENGTH_SHORT
).show()
homeViewModel.setCheckKeys(true)
- homeViewModel.setCheckFirmware(true)
+
+ val firstTimeSetup = PreferenceManager.getDefaultSharedPreferences(applicationContext)
+ .getBoolean(Settings.PREF_FIRST_APP_LAUNCH, true)
+ if (!firstTimeSetup) {
+ homeViewModel.setCheckFirmware(true)
+ }
+
gamesViewModel.reloadGames(true)
return true
} else {