Improve the robustness of the ROMs auto-refresh feature

This commit is contained in:
lynxnb 2023-04-27 00:31:00 +02:00
parent e6efaf26bc
commit 24d4f5e3cd

View File

@ -4,18 +4,18 @@ import android.app.Application
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.util.Log import android.util.Log
import androidx.lifecycle.* import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import emu.skyline.loader.AppEntry import emu.skyline.loader.AppEntry
import emu.skyline.loader.RomFormat
import emu.skyline.utils.fromFile import emu.skyline.utils.fromFile
import emu.skyline.utils.toFile import emu.skyline.utils.toFile
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import java.io.File import java.io.File
import java.util.*
import javax.inject.Inject import javax.inject.Inject
sealed class MainState { sealed class MainState {
@ -42,7 +42,8 @@ class MainViewModel @Inject constructor(@ApplicationContext context : Context, p
* @param loadFromFile If this is false then trying to load cached adapter data is skipped entirely * @param loadFromFile If this is false then trying to load cached adapter data is skipped entirely
*/ */
fun loadRoms(context : Context, loadFromFile : Boolean, searchLocation : Uri, systemLanguage : Int) { fun loadRoms(context : Context, loadFromFile : Boolean, searchLocation : Uri, systemLanguage : Int) {
if (state == MainState.Loading) return if (state == MainState.Loading)
return
state = MainState.Loading state = MainState.Loading
val romsFile = File(getApplication<SkylineApplication>().filesDir.canonicalPath + "/roms.bin") val romsFile = File(getApplication<SkylineApplication>().filesDir.canonicalPath + "/roms.bin")
@ -51,6 +52,7 @@ class MainViewModel @Inject constructor(@ApplicationContext context : Context, p
if (loadFromFile && romsFile.exists()) { if (loadFromFile && romsFile.exists()) {
try { try {
state = MainState.Loaded(fromFile(romsFile)) state = MainState.Loaded(fromFile(romsFile))
checkRomHash(searchLocation, systemLanguage)
return@launch return@launch
} catch (e : Exception) { } catch (e : Exception) {
Log.w(TAG, "Ran into exception while loading: ${e.message}") Log.w(TAG, "Ran into exception while loading: ${e.message}")
@ -58,7 +60,6 @@ class MainViewModel @Inject constructor(@ApplicationContext context : Context, p
} }
state = if (searchLocation.toString().isEmpty()) { state = if (searchLocation.toString().isEmpty()) {
@Suppress("ReplaceWithEnumMap")
MainState.Loaded(ArrayList()) MainState.Loaded(ArrayList())
} else { } else {
try { try {
@ -74,18 +75,31 @@ class MainViewModel @Inject constructor(@ApplicationContext context : Context, p
} }
} }
/**
* Tracks whether an auto refresh is already in progress
*/
private var isAutoRefreshingRoms = false
/** /**
* This checks if the roms have changed since the last time they were loaded and if so it reloads them * This checks if the roms have changed since the last time they were loaded and if so it reloads them
*/ */
fun checkRomHash(searchLocation : Uri, systemLanguage : Int) { fun checkRomHash(searchLocation : Uri, systemLanguage : Int) {
if(state !is MainState.Loaded) return // Skip if an auto refresh is already in progress or if the state hasn't already loaded
CoroutineScope(Dispatchers.IO).launch { if (isAutoRefreshingRoms || state !is MainState.Loaded)
val currentHash = (state as MainState.Loaded).items.hashCode() return
isAutoRefreshingRoms = true
viewModelScope.launch(Dispatchers.IO) {
val currentHash = when (val currentState = state) {
is MainState.Loaded -> currentState.items.hashCode()
else -> 0
}
val romElements = romProvider.loadRoms(searchLocation, systemLanguage) val romElements = romProvider.loadRoms(searchLocation, systemLanguage)
val newHash = romElements.hashCode() val newHash = romElements.hashCode()
if (newHash != currentHash) { if (newHash != currentHash)
state = MainState.Loaded(romElements) state = MainState.Loaded(romElements)
}
isAutoRefreshingRoms = false
} }
} }
} }