Browse Source

android: Game data cache

nce_cpp
Charles Lombardo 3 years ago
committed by bunnei
parent
commit
710e19a4bb
  1. 2
      src/android/app/build.gradle.kts
  2. 1
      src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt
  3. 14
      src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt
  4. 28
      src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt
  5. 11
      src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt
  6. 1
      src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt
  7. 21
      src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt
  8. 2
      src/android/app/src/main/res/layout/fragment_games.xml

2
src/android/app/build.gradle.kts

@ -2,6 +2,7 @@ plugins {
id("com.android.application") id("com.android.application")
id("org.jetbrains.kotlin.android") id("org.jetbrains.kotlin.android")
id("kotlin-parcelize") id("kotlin-parcelize")
kotlin("plugin.serialization") version "1.8.21"
} }
/** /**
@ -164,6 +165,7 @@ dependencies {
implementation("androidx.navigation:navigation-fragment-ktx:2.5.3") implementation("androidx.navigation:navigation-fragment-ktx:2.5.3")
implementation("androidx.navigation:navigation-ui-ktx:2.5.3") implementation("androidx.navigation:navigation-ui-ktx:2.5.3")
implementation("info.debatty:java-string-similarity:2.0.0") implementation("info.debatty:java-string-similarity:2.0.0")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0")
} }
fun getVersion(): String { fun getVersion(): String {

1
src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt

@ -100,7 +100,6 @@ class GameAdapter(private val activity: AppCompatActivity) :
return oldItem.gameId == newItem.gameId return oldItem.gameId == newItem.gameId
} }
@SuppressLint("DiffUtilEquals")
override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean { override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean {
return oldItem == newItem return oldItem == newItem
} }

14
src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt

@ -5,9 +5,11 @@ package org.yuzu.yuzu_emu.model
import android.os.Parcelable import android.os.Parcelable
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import kotlinx.serialization.Serializable
import java.util.HashSet import java.util.HashSet
@Parcelize @Parcelize
@Serializable
class Game( class Game(
val title: String, val title: String,
val description: String, val description: String,
@ -19,6 +21,18 @@ class Game(
val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime" val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime"
val keyLastPlayedTime get() = "${gameId}_LastPlayed" val keyLastPlayedTime get() = "${gameId}_LastPlayed"
override fun equals(other: Any?): Boolean {
if (other !is Game)
return false
return title == other.title
&& description == other.description
&& regions == other.regions
&& path == other.path
&& gameId == other.gameId
&& company == other.company
}
companion object { companion object {
val extensions: Set<String> = HashSet( val extensions: Set<String> = HashSet(
listOf(".xci", ".nsp", ".nca", ".nro") listOf(".xci", ".nsp", ".nca", ".nro")

28
src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt

@ -7,11 +7,16 @@ import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope import androidx.lifecycle.viewModelScope
import androidx.preference.PreferenceManager
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.utils.GameHelper import org.yuzu.yuzu_emu.utils.GameHelper
import java.util.Locale
class GamesViewModel : ViewModel() { class GamesViewModel : ViewModel() {
private val _games = MutableLiveData<List<Game>>(emptyList()) private val _games = MutableLiveData<List<Game>>(emptyList())
@ -33,9 +38,30 @@ class GamesViewModel : ViewModel() {
val searchFocused: LiveData<Boolean> get() = _searchFocused val searchFocused: LiveData<Boolean> get() = _searchFocused
init { init {
// Retrieve list of cached games
val storedGames = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext)
.getStringSet(GameHelper.KEY_GAMES, emptySet())
if (storedGames!!.isNotEmpty()) {
val deserializedGames = mutableSetOf<Game>()
storedGames.forEach {
deserializedGames.add(Json.decodeFromString(it))
}
setGames(deserializedGames.toList())
}
reloadGames(false) reloadGames(false)
} }
fun setGames(games: List<Game>) {
val sortedList = games.sortedWith(
compareBy(
{ it.title.lowercase(Locale.getDefault()) },
{ it.path }
)
)
_games.postValue(sortedList)
}
fun setSearchedGames(games: List<Game>) { fun setSearchedGames(games: List<Game>) {
_searchedGames.postValue(games) _searchedGames.postValue(games)
} }
@ -60,7 +86,7 @@ class GamesViewModel : ViewModel() {
viewModelScope.launch { viewModelScope.launch {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
NativeLibrary.resetRomMetadata() NativeLibrary.resetRomMetadata()
_games.postValue(GameHelper.getGames())
setGames(GameHelper.getGames())
_isReloading.postValue(false) _isReloading.postValue(false)
if (directoryChanged) { if (directoryChanged) {

11
src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt

@ -20,10 +20,8 @@ import org.yuzu.yuzu_emu.R
import org.yuzu.yuzu_emu.adapters.GameAdapter import org.yuzu.yuzu_emu.adapters.GameAdapter
import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding
import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager
import org.yuzu.yuzu_emu.model.Game
import org.yuzu.yuzu_emu.model.GamesViewModel import org.yuzu.yuzu_emu.model.GamesViewModel
import org.yuzu.yuzu_emu.model.HomeViewModel import org.yuzu.yuzu_emu.model.HomeViewModel
import java.util.Locale
class GamesFragment : Fragment() { class GamesFragment : Fragment() {
private var _binding: FragmentGamesBinding? = null private var _binding: FragmentGamesBinding? = null
@ -81,7 +79,7 @@ class GamesFragment : Fragment() {
binding.swipeRefresh.isRefreshing = isReloading binding.swipeRefresh.isRefreshing = isReloading
} }
gamesViewModel.games.observe(viewLifecycleOwner) { gamesViewModel.games.observe(viewLifecycleOwner) {
submitGamesList(it)
(binding.gridGames.adapter as GameAdapter).submitList(it)
if (it.isEmpty()) { if (it.isEmpty()) {
binding.noticeText.visibility = View.VISIBLE binding.noticeText.visibility = View.VISIBLE
} else { } else {
@ -91,7 +89,7 @@ class GamesFragment : Fragment() {
gamesViewModel.shouldSwapData.observe(viewLifecycleOwner) { shouldSwapData -> gamesViewModel.shouldSwapData.observe(viewLifecycleOwner) { shouldSwapData ->
if (shouldSwapData) { if (shouldSwapData) {
submitGamesList(gamesViewModel.games.value!!)
(binding.gridGames.adapter as GameAdapter).submitList(gamesViewModel.games.value!!)
gamesViewModel.setShouldSwapData(false) gamesViewModel.setShouldSwapData(false)
} }
} }
@ -115,11 +113,6 @@ class GamesFragment : Fragment() {
} }
} }
private fun submitGamesList(gameList: List<Game>) {
val sortedList = gameList.sortedBy { it.title.lowercase(Locale.getDefault()) }
(binding.gridGames.adapter as GameAdapter).submitList(sortedList)
}
override fun onDestroyView() { override fun onDestroyView() {
super.onDestroyView() super.onDestroyView()
_binding = null _binding = null

1
src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/main/MainActivity.kt

@ -25,7 +25,6 @@ import androidx.navigation.ui.setupWithNavController
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import com.google.android.material.color.MaterialColors import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.elevation.ElevationOverlayProvider
import com.google.android.material.navigation.NavigationBarView import com.google.android.material.navigation.NavigationBarView
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch

21
src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt

@ -6,19 +6,22 @@ package org.yuzu.yuzu_emu.utils
import android.content.SharedPreferences import android.content.SharedPreferences
import android.net.Uri import android.net.Uri
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json
import org.yuzu.yuzu_emu.NativeLibrary import org.yuzu.yuzu_emu.NativeLibrary
import org.yuzu.yuzu_emu.YuzuApplication import org.yuzu.yuzu_emu.YuzuApplication
import org.yuzu.yuzu_emu.model.Game import org.yuzu.yuzu_emu.model.Game
import java.util.* import java.util.*
import kotlin.collections.ArrayList
object GameHelper { object GameHelper {
const val KEY_GAME_PATH = "game_path" const val KEY_GAME_PATH = "game_path"
const val KEY_GAMES = "Games"
private lateinit var preferences: SharedPreferences private lateinit var preferences: SharedPreferences
fun getGames(): ArrayList<Game> {
val games = ArrayList<Game>()
fun getGames(): List<Game> {
val games = mutableListOf<Game>()
val context = YuzuApplication.appContext val context = YuzuApplication.appContext
val gamesDir = val gamesDir =
PreferenceManager.getDefaultSharedPreferences(context).getString(KEY_GAME_PATH, "") PreferenceManager.getDefaultSharedPreferences(context).getString(KEY_GAME_PATH, "")
@ -44,7 +47,17 @@ object GameHelper {
} }
} }
return games
// Cache list of games found on disk
val serializedGames = mutableSetOf<String>()
games.forEach {
serializedGames.add(Json.encodeToString(it))
}
preferences.edit()
.remove(KEY_GAMES)
.putStringSet(KEY_GAMES, serializedGames)
.apply()
return games.toList()
} }
private fun getGame(filePath: String): Game { private fun getGame(filePath: String): Game {

2
src/android/app/src/main/res/layout/fragment_games.xml

@ -20,7 +20,7 @@
android:gravity="center" android:gravity="center"
android:padding="@dimen/spacing_large" android:padding="@dimen/spacing_large"
android:text="@string/empty_gamelist" android:text="@string/empty_gamelist"
tools:visibility="gone" />
android:visibility="gone" />
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/grid_games" android:id="@+id/grid_games"

Loading…
Cancel
Save