diff options
| author | 2023-05-02 05:58:03 -0400 | |
|---|---|---|
| committer | 2023-06-03 00:05:59 -0700 | |
| commit | 65dc35a1a5484f5e7b9a0770fa5b536782a87fbe (patch) | |
| tree | 06d54d383ab12ae3d3ddbc84c5ee0bc8b8c16fcc /src/android/app | |
| parent | android: Update to Kotlin 1.8.21 (diff) | |
| download | yuzu-65dc35a1a5484f5e7b9a0770fa5b536782a87fbe.tar.gz yuzu-65dc35a1a5484f5e7b9a0770fa5b536782a87fbe.tar.xz yuzu-65dc35a1a5484f5e7b9a0770fa5b536782a87fbe.zip | |
android: Game data cache
Diffstat (limited to 'src/android/app')
8 files changed, 63 insertions, 17 deletions
diff --git a/src/android/app/build.gradle.kts b/src/android/app/build.gradle.kts index ea13b6d0e..a9790b200 100644 --- a/src/android/app/build.gradle.kts +++ b/src/android/app/build.gradle.kts | |||
| @@ -2,6 +2,7 @@ plugins { | |||
| 2 | id("com.android.application") | 2 | id("com.android.application") |
| 3 | id("org.jetbrains.kotlin.android") | 3 | id("org.jetbrains.kotlin.android") |
| 4 | id("kotlin-parcelize") | 4 | id("kotlin-parcelize") |
| 5 | kotlin("plugin.serialization") version "1.8.21" | ||
| 5 | } | 6 | } |
| 6 | 7 | ||
| 7 | /** | 8 | /** |
| @@ -164,6 +165,7 @@ dependencies { | |||
| 164 | implementation("androidx.navigation:navigation-fragment-ktx:2.5.3") | 165 | implementation("androidx.navigation:navigation-fragment-ktx:2.5.3") |
| 165 | implementation("androidx.navigation:navigation-ui-ktx:2.5.3") | 166 | implementation("androidx.navigation:navigation-ui-ktx:2.5.3") |
| 166 | implementation("info.debatty:java-string-similarity:2.0.0") | 167 | implementation("info.debatty:java-string-similarity:2.0.0") |
| 168 | implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.5.0") | ||
| 167 | } | 169 | } |
| 168 | 170 | ||
| 169 | fun getVersion(): String { | 171 | fun getVersion(): String { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt index b9f975e2b..a9653475f 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/adapters/GameAdapter.kt | |||
| @@ -100,7 +100,6 @@ class GameAdapter(private val activity: AppCompatActivity) : | |||
| 100 | return oldItem.gameId == newItem.gameId | 100 | return oldItem.gameId == newItem.gameId |
| 101 | } | 101 | } |
| 102 | 102 | ||
| 103 | @SuppressLint("DiffUtilEquals") | ||
| 104 | override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean { | 103 | override fun areContentsTheSame(oldItem: Game, newItem: Game): Boolean { |
| 105 | return oldItem == newItem | 104 | return oldItem == newItem |
| 106 | } | 105 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt index c5cde9d05..2a17653b2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/Game.kt | |||
| @@ -5,9 +5,11 @@ package org.yuzu.yuzu_emu.model | |||
| 5 | 5 | ||
| 6 | import android.os.Parcelable | 6 | import android.os.Parcelable |
| 7 | import kotlinx.parcelize.Parcelize | 7 | import kotlinx.parcelize.Parcelize |
| 8 | import kotlinx.serialization.Serializable | ||
| 8 | import java.util.HashSet | 9 | import java.util.HashSet |
| 9 | 10 | ||
| 10 | @Parcelize | 11 | @Parcelize |
| 12 | @Serializable | ||
| 11 | class Game( | 13 | class Game( |
| 12 | val title: String, | 14 | val title: String, |
| 13 | val description: String, | 15 | val description: String, |
| @@ -19,6 +21,18 @@ class Game( | |||
| 19 | val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime" | 21 | val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime" |
| 20 | val keyLastPlayedTime get() = "${gameId}_LastPlayed" | 22 | val keyLastPlayedTime get() = "${gameId}_LastPlayed" |
| 21 | 23 | ||
| 24 | override fun equals(other: Any?): Boolean { | ||
| 25 | if (other !is Game) | ||
| 26 | return false | ||
| 27 | |||
| 28 | return title == other.title | ||
| 29 | && description == other.description | ||
| 30 | && regions == other.regions | ||
| 31 | && path == other.path | ||
| 32 | && gameId == other.gameId | ||
| 33 | && company == other.company | ||
| 34 | } | ||
| 35 | |||
| 22 | companion object { | 36 | companion object { |
| 23 | val extensions: Set<String> = HashSet( | 37 | val extensions: Set<String> = HashSet( |
| 24 | listOf(".xci", ".nsp", ".nca", ".nro") | 38 | listOf(".xci", ".nsp", ".nca", ".nro") |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt index 1d0846b08..5a35b14c9 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/model/GamesViewModel.kt | |||
| @@ -7,11 +7,16 @@ import androidx.lifecycle.LiveData | |||
| 7 | import androidx.lifecycle.MutableLiveData | 7 | import androidx.lifecycle.MutableLiveData |
| 8 | import androidx.lifecycle.ViewModel | 8 | import androidx.lifecycle.ViewModel |
| 9 | import androidx.lifecycle.viewModelScope | 9 | import androidx.lifecycle.viewModelScope |
| 10 | import androidx.preference.PreferenceManager | ||
| 10 | import kotlinx.coroutines.Dispatchers | 11 | import kotlinx.coroutines.Dispatchers |
| 11 | import kotlinx.coroutines.launch | 12 | import kotlinx.coroutines.launch |
| 12 | import kotlinx.coroutines.withContext | 13 | import kotlinx.coroutines.withContext |
| 14 | import kotlinx.serialization.decodeFromString | ||
| 15 | import kotlinx.serialization.json.Json | ||
| 13 | import org.yuzu.yuzu_emu.NativeLibrary | 16 | import org.yuzu.yuzu_emu.NativeLibrary |
| 17 | import org.yuzu.yuzu_emu.YuzuApplication | ||
| 14 | import org.yuzu.yuzu_emu.utils.GameHelper | 18 | import org.yuzu.yuzu_emu.utils.GameHelper |
| 19 | import java.util.Locale | ||
| 15 | 20 | ||
| 16 | class GamesViewModel : ViewModel() { | 21 | class GamesViewModel : ViewModel() { |
| 17 | private val _games = MutableLiveData<List<Game>>(emptyList()) | 22 | private val _games = MutableLiveData<List<Game>>(emptyList()) |
| @@ -33,9 +38,30 @@ class GamesViewModel : ViewModel() { | |||
| 33 | val searchFocused: LiveData<Boolean> get() = _searchFocused | 38 | val searchFocused: LiveData<Boolean> get() = _searchFocused |
| 34 | 39 | ||
| 35 | init { | 40 | init { |
| 41 | // Retrieve list of cached games | ||
| 42 | val storedGames = PreferenceManager.getDefaultSharedPreferences(YuzuApplication.appContext) | ||
| 43 | .getStringSet(GameHelper.KEY_GAMES, emptySet()) | ||
| 44 | if (storedGames!!.isNotEmpty()) { | ||
| 45 | val deserializedGames = mutableSetOf<Game>() | ||
| 46 | storedGames.forEach { | ||
| 47 | deserializedGames.add(Json.decodeFromString(it)) | ||
| 48 | } | ||
| 49 | setGames(deserializedGames.toList()) | ||
| 50 | } | ||
| 36 | reloadGames(false) | 51 | reloadGames(false) |
| 37 | } | 52 | } |
| 38 | 53 | ||
| 54 | fun setGames(games: List<Game>) { | ||
| 55 | val sortedList = games.sortedWith( | ||
| 56 | compareBy( | ||
| 57 | { it.title.lowercase(Locale.getDefault()) }, | ||
| 58 | { it.path } | ||
| 59 | ) | ||
| 60 | ) | ||
| 61 | |||
| 62 | _games.postValue(sortedList) | ||
| 63 | } | ||
| 64 | |||
| 39 | fun setSearchedGames(games: List<Game>) { | 65 | fun setSearchedGames(games: List<Game>) { |
| 40 | _searchedGames.postValue(games) | 66 | _searchedGames.postValue(games) |
| 41 | } | 67 | } |
| @@ -60,7 +86,7 @@ class GamesViewModel : ViewModel() { | |||
| 60 | viewModelScope.launch { | 86 | viewModelScope.launch { |
| 61 | withContext(Dispatchers.IO) { | 87 | withContext(Dispatchers.IO) { |
| 62 | NativeLibrary.resetRomMetadata() | 88 | NativeLibrary.resetRomMetadata() |
| 63 | _games.postValue(GameHelper.getGames()) | 89 | setGames(GameHelper.getGames()) |
| 64 | _isReloading.postValue(false) | 90 | _isReloading.postValue(false) |
| 65 | 91 | ||
| 66 | if (directoryChanged) { | 92 | if (directoryChanged) { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt index 07d0cd3d8..afabfb2b9 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/ui/GamesFragment.kt | |||
| @@ -20,10 +20,8 @@ import org.yuzu.yuzu_emu.R | |||
| 20 | import org.yuzu.yuzu_emu.adapters.GameAdapter | 20 | import org.yuzu.yuzu_emu.adapters.GameAdapter |
| 21 | import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding | 21 | import org.yuzu.yuzu_emu.databinding.FragmentGamesBinding |
| 22 | import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager | 22 | import org.yuzu.yuzu_emu.layout.AutofitGridLayoutManager |
| 23 | import org.yuzu.yuzu_emu.model.Game | ||
| 24 | import org.yuzu.yuzu_emu.model.GamesViewModel | 23 | import org.yuzu.yuzu_emu.model.GamesViewModel |
| 25 | import org.yuzu.yuzu_emu.model.HomeViewModel | 24 | import org.yuzu.yuzu_emu.model.HomeViewModel |
| 26 | import java.util.Locale | ||
| 27 | 25 | ||
| 28 | class GamesFragment : Fragment() { | 26 | class GamesFragment : Fragment() { |
| 29 | private var _binding: FragmentGamesBinding? = null | 27 | private var _binding: FragmentGamesBinding? = null |
| @@ -81,7 +79,7 @@ class GamesFragment : Fragment() { | |||
| 81 | binding.swipeRefresh.isRefreshing = isReloading | 79 | binding.swipeRefresh.isRefreshing = isReloading |
| 82 | } | 80 | } |
| 83 | gamesViewModel.games.observe(viewLifecycleOwner) { | 81 | gamesViewModel.games.observe(viewLifecycleOwner) { |
| 84 | submitGamesList(it) | 82 | (binding.gridGames.adapter as GameAdapter).submitList(it) |
| 85 | if (it.isEmpty()) { | 83 | if (it.isEmpty()) { |
| 86 | binding.noticeText.visibility = View.VISIBLE | 84 | binding.noticeText.visibility = View.VISIBLE |
| 87 | } else { | 85 | } else { |
| @@ -91,7 +89,7 @@ class GamesFragment : Fragment() { | |||
| 91 | 89 | ||
| 92 | gamesViewModel.shouldSwapData.observe(viewLifecycleOwner) { shouldSwapData -> | 90 | gamesViewModel.shouldSwapData.observe(viewLifecycleOwner) { shouldSwapData -> |
| 93 | if (shouldSwapData) { | 91 | if (shouldSwapData) { |
| 94 | submitGamesList(gamesViewModel.games.value!!) | 92 | (binding.gridGames.adapter as GameAdapter).submitList(gamesViewModel.games.value!!) |
| 95 | gamesViewModel.setShouldSwapData(false) | 93 | gamesViewModel.setShouldSwapData(false) |
| 96 | } | 94 | } |
| 97 | } | 95 | } |
| @@ -115,11 +113,6 @@ class GamesFragment : Fragment() { | |||
| 115 | } | 113 | } |
| 116 | } | 114 | } |
| 117 | 115 | ||
| 118 | private fun submitGamesList(gameList: List<Game>) { | ||
| 119 | val sortedList = gameList.sortedBy { it.title.lowercase(Locale.getDefault()) } | ||
| 120 | (binding.gridGames.adapter as GameAdapter).submitList(sortedList) | ||
| 121 | } | ||
| 122 | |||
| 123 | override fun onDestroyView() { | 116 | override fun onDestroyView() { |
| 124 | super.onDestroyView() | 117 | super.onDestroyView() |
| 125 | _binding = null | 118 | _binding = null |
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 b2499168e..f8f275b41 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 | |||
| @@ -25,7 +25,6 @@ import androidx.navigation.ui.setupWithNavController | |||
| 25 | import androidx.preference.PreferenceManager | 25 | import androidx.preference.PreferenceManager |
| 26 | import com.google.android.material.color.MaterialColors | 26 | import com.google.android.material.color.MaterialColors |
| 27 | import com.google.android.material.dialog.MaterialAlertDialogBuilder | 27 | import com.google.android.material.dialog.MaterialAlertDialogBuilder |
| 28 | import com.google.android.material.elevation.ElevationOverlayProvider | ||
| 29 | import com.google.android.material.navigation.NavigationBarView | 28 | import com.google.android.material.navigation.NavigationBarView |
| 30 | import kotlinx.coroutines.Dispatchers | 29 | import kotlinx.coroutines.Dispatchers |
| 31 | import kotlinx.coroutines.launch | 30 | import kotlinx.coroutines.launch |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt index 9dd43343f..ba6b5783e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/GameHelper.kt | |||
| @@ -6,19 +6,22 @@ package org.yuzu.yuzu_emu.utils | |||
| 6 | import android.content.SharedPreferences | 6 | import android.content.SharedPreferences |
| 7 | import android.net.Uri | 7 | import android.net.Uri |
| 8 | import androidx.preference.PreferenceManager | 8 | import androidx.preference.PreferenceManager |
| 9 | import kotlinx.serialization.decodeFromString | ||
| 10 | import kotlinx.serialization.encodeToString | ||
| 11 | import kotlinx.serialization.json.Json | ||
| 9 | import org.yuzu.yuzu_emu.NativeLibrary | 12 | import org.yuzu.yuzu_emu.NativeLibrary |
| 10 | import org.yuzu.yuzu_emu.YuzuApplication | 13 | import org.yuzu.yuzu_emu.YuzuApplication |
| 11 | import org.yuzu.yuzu_emu.model.Game | 14 | import org.yuzu.yuzu_emu.model.Game |
| 12 | import java.util.* | 15 | import java.util.* |
| 13 | import kotlin.collections.ArrayList | ||
| 14 | 16 | ||
| 15 | object GameHelper { | 17 | object GameHelper { |
| 16 | const val KEY_GAME_PATH = "game_path" | 18 | const val KEY_GAME_PATH = "game_path" |
| 19 | const val KEY_GAMES = "Games" | ||
| 17 | 20 | ||
| 18 | private lateinit var preferences: SharedPreferences | 21 | private lateinit var preferences: SharedPreferences |
| 19 | 22 | ||
| 20 | fun getGames(): ArrayList<Game> { | 23 | fun getGames(): List<Game> { |
| 21 | val games = ArrayList<Game>() | 24 | val games = mutableListOf<Game>() |
| 22 | val context = YuzuApplication.appContext | 25 | val context = YuzuApplication.appContext |
| 23 | val gamesDir = | 26 | val gamesDir = |
| 24 | PreferenceManager.getDefaultSharedPreferences(context).getString(KEY_GAME_PATH, "") | 27 | PreferenceManager.getDefaultSharedPreferences(context).getString(KEY_GAME_PATH, "") |
| @@ -44,7 +47,17 @@ object GameHelper { | |||
| 44 | } | 47 | } |
| 45 | } | 48 | } |
| 46 | 49 | ||
| 47 | return games | 50 | // Cache list of games found on disk |
| 51 | val serializedGames = mutableSetOf<String>() | ||
| 52 | games.forEach { | ||
| 53 | serializedGames.add(Json.encodeToString(it)) | ||
| 54 | } | ||
| 55 | preferences.edit() | ||
| 56 | .remove(KEY_GAMES) | ||
| 57 | .putStringSet(KEY_GAMES, serializedGames) | ||
| 58 | .apply() | ||
| 59 | |||
| 60 | return games.toList() | ||
| 48 | } | 61 | } |
| 49 | 62 | ||
| 50 | private fun getGame(filePath: String): Game { | 63 | private fun getGame(filePath: String): Game { |
diff --git a/src/android/app/src/main/res/layout/fragment_games.xml b/src/android/app/src/main/res/layout/fragment_games.xml index 8b6d0b3b6..a0568668a 100644 --- a/src/android/app/src/main/res/layout/fragment_games.xml +++ b/src/android/app/src/main/res/layout/fragment_games.xml | |||
| @@ -20,7 +20,7 @@ | |||
| 20 | android:gravity="center" | 20 | android:gravity="center" |
| 21 | android:padding="@dimen/spacing_large" | 21 | android:padding="@dimen/spacing_large" |
| 22 | android:text="@string/empty_gamelist" | 22 | android:text="@string/empty_gamelist" |
| 23 | tools:visibility="gone" /> | 23 | android:visibility="gone" /> |
| 24 | 24 | ||
| 25 | <androidx.recyclerview.widget.RecyclerView | 25 | <androidx.recyclerview.widget.RecyclerView |
| 26 | android:id="@+id/grid_games" | 26 | android:id="@+id/grid_games" |