mirror of
https://git.ryujinx.app/projects/Kenji-NX.git
synced 2026-09-27 14:20:05 +02:00
Android fixes and features
* Jit cache eviction (fixes out of memory errors in some games) * Low power PPTC * Fix 'unknown' games displayed when using game folder with subfolders * Turn off NCE and PPTC by default
This commit is contained in:
@@ -16,6 +16,8 @@ interface KenjinxNativeJna : Library {
|
||||
vSyncMode: Int,
|
||||
enableDockedMode: Boolean,
|
||||
enablePptc: Boolean,
|
||||
enableLowPowerPptc: Boolean,
|
||||
enableJitCacheEviction: Boolean,
|
||||
enableInternetAccess: Boolean,
|
||||
enableFsIntegrityChecks: Boolean,
|
||||
fsGlobalAccessLogMode: Int,
|
||||
|
||||
@@ -248,4 +248,24 @@ class MainActivity : BaseActivity() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun shutdownAndRestart() {
|
||||
// Create an intent to restart the app
|
||||
val packageManager = packageManager
|
||||
val intent = packageManager.getLaunchIntentForPackage(packageName)
|
||||
val componentName = intent?.component
|
||||
val restartIntent = Intent.makeRestartActivityTask(componentName)
|
||||
|
||||
// Clean up resources if needed
|
||||
mainViewModel?.let {
|
||||
// Perform any critical cleanup
|
||||
it.performanceManager?.setTurboMode(false)
|
||||
}
|
||||
|
||||
// Start the new activity directly
|
||||
startActivity(restartIntent)
|
||||
|
||||
// Force immediate process termination
|
||||
Runtime.getRuntime().exit(0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,10 @@ class GameModel(var file: DocumentFile, val context: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun isUnknown() : Boolean {
|
||||
return (titleName == "Unknown")
|
||||
}
|
||||
|
||||
fun open(): Int {
|
||||
descriptor = context.contentResolver.openFileDescriptor(file.uri, "rw")
|
||||
|
||||
|
||||
@@ -107,6 +107,11 @@ class HomeViewModel(
|
||||
for(game in loadedCache)
|
||||
{
|
||||
game.getGameInfo()
|
||||
|
||||
if(game.isUnknown())
|
||||
{
|
||||
loadedCache.remove(game);
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
isLoading.value = false
|
||||
|
||||
@@ -179,6 +179,8 @@ class MainViewModel(val activity: MainActivity) {
|
||||
settings.vSyncMode.ordinal,
|
||||
settings.enableDocked,
|
||||
settings.enablePptc,
|
||||
settings.enableLowPowerPptc,
|
||||
settings.enableJitCacheEviction,
|
||||
false,
|
||||
settings.enableFsIntegrityChecks,
|
||||
settings.fsGlobalAccessLogMode,
|
||||
@@ -285,6 +287,8 @@ class MainViewModel(val activity: MainActivity) {
|
||||
settings.vSyncMode.ordinal,
|
||||
settings.enableDocked,
|
||||
settings.enablePptc,
|
||||
settings.enableLowPowerPptc,
|
||||
settings.enableJitCacheEviction,
|
||||
false,
|
||||
settings.enableFsIntegrityChecks,
|
||||
settings.fsGlobalAccessLogMode,
|
||||
|
||||
+7
-1
@@ -7,6 +7,8 @@ import androidx.preference.PreferenceManager
|
||||
class QuickSettings(val activity: Activity) {
|
||||
var ignoreMissingServices: Boolean
|
||||
var enablePptc: Boolean
|
||||
var enableLowPowerPptc: Boolean
|
||||
var enableJitCacheEviction: Boolean
|
||||
var enableFsIntegrityChecks: Boolean
|
||||
var fsGlobalAccessLogMode: Int
|
||||
var enableDocked: Boolean
|
||||
@@ -39,11 +41,13 @@ class QuickSettings(val activity: Activity) {
|
||||
|
||||
init {
|
||||
memoryManagerMode = MemoryManagerMode.values()[sharedPref.getInt("memoryManagerMode", MemoryManagerMode.HostMappedUnsafe.ordinal)]
|
||||
useNce = sharedPref.getBoolean("useNce", true)
|
||||
useNce = sharedPref.getBoolean("useNce", false)
|
||||
memoryConfiguration = MemoryConfiguration.values()[sharedPref.getInt("memoryConfiguration", MemoryConfiguration.MemoryConfiguration4GiB.ordinal)]
|
||||
vSyncMode = VSyncMode.values()[sharedPref.getInt("vSyncMode", VSyncMode.Switch.ordinal)]
|
||||
enableDocked = sharedPref.getBoolean("enableDocked", true)
|
||||
enablePptc = sharedPref.getBoolean("enablePptc", true)
|
||||
enableLowPowerPptc = sharedPref.getBoolean("enableLowPowerPptc", false)
|
||||
enableJitCacheEviction = sharedPref.getBoolean("enableJitCacheEviction", true)
|
||||
enableFsIntegrityChecks = sharedPref.getBoolean("enableFsIntegrityChecks", false)
|
||||
fsGlobalAccessLogMode = sharedPref.getInt("fsGlobalAccessLogMode", 0)
|
||||
ignoreMissingServices = sharedPref.getBoolean("ignoreMissingServices", false)
|
||||
@@ -78,6 +82,8 @@ class QuickSettings(val activity: Activity) {
|
||||
editor.putInt("vSyncMode", vSyncMode.ordinal)
|
||||
editor.putBoolean("enableDocked", enableDocked)
|
||||
editor.putBoolean("enablePptc", enablePptc)
|
||||
editor.putBoolean("enableLowPowerPptc", enableLowPowerPptc)
|
||||
editor.putBoolean("enableJitCacheEviction", enableJitCacheEviction)
|
||||
editor.putBoolean("enableFsIntegrityChecks", enableFsIntegrityChecks)
|
||||
editor.putInt("fsGlobalAccessLogMode", fsGlobalAccessLogMode)
|
||||
editor.putBoolean("ignoreMissingServices", ignoreMissingServices)
|
||||
|
||||
+122
-81
@@ -31,14 +31,6 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
sharedPref = getPreferences()
|
||||
previousFolderCallback = activity.storageHelper!!.onFolderSelected
|
||||
previousFileCallback = activity.storageHelper!!.onFileSelected
|
||||
activity.storageHelper!!.onFolderSelected = { _, folder ->
|
||||
run {
|
||||
val p = folder.getAbsolutePath(activity)
|
||||
val editor = sharedPref.edit()
|
||||
editor?.putString("gameFolder", p)
|
||||
editor?.apply()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun getPreferences(): SharedPreferences {
|
||||
@@ -52,6 +44,8 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
vSyncMode: MutableState<VSyncMode>,
|
||||
enableDocked: MutableState<Boolean>,
|
||||
enablePptc: MutableState<Boolean>,
|
||||
enableLowPowerPptc: MutableState<Boolean>,
|
||||
enableJitCacheEviction: MutableState<Boolean>,
|
||||
enableFsIntegrityChecks: MutableState<Boolean>,
|
||||
fsGlobalAccessLogMode: MutableState<Int>,
|
||||
ignoreMissingServices: MutableState<Boolean>,
|
||||
@@ -77,11 +71,13 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
enableGraphicsLogs: MutableState<Boolean>
|
||||
) {
|
||||
memoryManagerMode.value = MemoryManagerMode.values()[sharedPref.getInt("memoryManagerMode", MemoryManagerMode.HostMappedUnsafe.ordinal)]
|
||||
useNce.value = sharedPref.getBoolean("useNce", true)
|
||||
useNce.value = sharedPref.getBoolean("useNce", false)
|
||||
memoryConfiguration.value = MemoryConfiguration.values()[sharedPref.getInt("memoryConfiguration", MemoryConfiguration.MemoryConfiguration4GiB.ordinal)]
|
||||
vSyncMode.value = VSyncMode.values()[sharedPref.getInt("vSyncMode", VSyncMode.Switch.ordinal)]
|
||||
enableDocked.value = sharedPref.getBoolean("enableDocked", true)
|
||||
enablePptc.value = sharedPref.getBoolean("enablePptc", true)
|
||||
enableLowPowerPptc.value = sharedPref.getBoolean("enableLowPowerPptc", false)
|
||||
enableJitCacheEviction.value = sharedPref.getBoolean("enableJitCacheEviction", false)
|
||||
enableFsIntegrityChecks.value = sharedPref.getBoolean("enableFsIntegrityChecks", false)
|
||||
fsGlobalAccessLogMode.value = sharedPref.getInt("fsGlobalAccessLogMode", 0)
|
||||
ignoreMissingServices.value = sharedPref.getBoolean("ignoreMissingServices", false)
|
||||
@@ -102,7 +98,7 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
enableErrorLogs.value = sharedPref.getBoolean("enableErrorLogs", true)
|
||||
enableGuestLogs.value = sharedPref.getBoolean("enableGuestLogs", true)
|
||||
enableFsAccessLogs.value = sharedPref.getBoolean("enableFsAccessLogs", false)
|
||||
enableTraceLogs.value = sharedPref.getBoolean("enableStubLogs", false)
|
||||
enableTraceLogs.value = sharedPref.getBoolean("enableTraceLogs", false)
|
||||
enableDebugLogs.value = sharedPref.getBoolean("enableDebugLogs", false)
|
||||
enableGraphicsLogs.value = sharedPref.getBoolean("enableGraphicsLogs", false)
|
||||
}
|
||||
@@ -114,6 +110,8 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
vSyncMode: MutableState<VSyncMode>,
|
||||
enableDocked: MutableState<Boolean>,
|
||||
enablePptc: MutableState<Boolean>,
|
||||
enableLowPowerPptc: MutableState<Boolean>,
|
||||
enableJitCacheEviction: MutableState<Boolean>,
|
||||
enableFsIntegrityChecks: MutableState<Boolean>,
|
||||
fsGlobalAccessLogMode: MutableState<Int>,
|
||||
ignoreMissingServices: MutableState<Boolean>,
|
||||
@@ -146,6 +144,8 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
editor.putInt("vSyncMode", vSyncMode.value.ordinal)
|
||||
editor.putBoolean("enableDocked", enableDocked.value)
|
||||
editor.putBoolean("enablePptc", enablePptc.value)
|
||||
editor.putBoolean("enableLowPowerPptc", enableLowPowerPptc.value)
|
||||
editor.putBoolean("enableJitCacheEviction", enableJitCacheEviction.value)
|
||||
editor.putBoolean("enableFsIntegrityChecks", enableFsIntegrityChecks.value)
|
||||
editor.putInt("fsGlobalAccessLogMode", fsGlobalAccessLogMode.value)
|
||||
editor.putBoolean("ignoreMissingServices", ignoreMissingServices.value)
|
||||
@@ -171,7 +171,6 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
editor.putBoolean("enableGraphicsLogs", enableGraphicsLogs.value)
|
||||
|
||||
editor.apply()
|
||||
activity.storageHelper!!.onFolderSelected = previousFolderCallback
|
||||
|
||||
KenjinxNative.loggingSetEnabled(LogLevel.Info, enableInfoLogs.value)
|
||||
KenjinxNative.loggingSetEnabled(LogLevel.Stub, enableStubLogs.value)
|
||||
@@ -187,6 +186,15 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
fun openGameFolder() {
|
||||
val path = sharedPref.getString("gameFolder", "") ?: ""
|
||||
|
||||
activity.storageHelper!!.onFolderSelected = { _, folder ->
|
||||
val p = folder.getAbsolutePath(activity)
|
||||
val editor = sharedPref.edit()
|
||||
editor.putString("gameFolder", p)
|
||||
editor.apply()
|
||||
activity.storageHelper!!.onFolderSelected = previousFolderCallback
|
||||
activity.shutdownAndRestart()
|
||||
}
|
||||
|
||||
if (path.isEmpty())
|
||||
activity.storageHelper?.storage?.openFolderPicker()
|
||||
else
|
||||
@@ -197,22 +205,20 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
}
|
||||
|
||||
fun selectKey(installState: MutableState<KeyInstallState>) {
|
||||
if (installState.value != KeyInstallState.None)
|
||||
if (installState.value != KeyInstallState.File)
|
||||
return
|
||||
|
||||
activity.storageHelper!!.onFileSelected = { _, files ->
|
||||
run {
|
||||
activity.storageHelper!!.onFileSelected = previousFileCallback
|
||||
val file = files.firstOrNull()
|
||||
file?.apply {
|
||||
if (name == "prod.keys") {
|
||||
selectedKeyFile = file
|
||||
installState.value = KeyInstallState.Query
|
||||
}
|
||||
else {
|
||||
installState.value = KeyInstallState.Cancelled
|
||||
}
|
||||
val file = files.firstOrNull()
|
||||
file?.apply {
|
||||
if (name == "prod.keys") {
|
||||
selectedKeyFile = file
|
||||
installState.value = KeyInstallState.Query
|
||||
} else {
|
||||
installState.value = KeyInstallState.Cancelled
|
||||
}
|
||||
}
|
||||
activity.storageHelper!!.onFileSelected = previousFileCallback
|
||||
}
|
||||
activity.storageHelper?.storage?.openFilePicker()
|
||||
}
|
||||
@@ -221,7 +227,7 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
if (installState.value != KeyInstallState.Query)
|
||||
return
|
||||
if (selectedKeyFile == null) {
|
||||
installState.value = KeyInstallState.None
|
||||
installState.value = KeyInstallState.File
|
||||
return
|
||||
}
|
||||
selectedKeyFile?.apply {
|
||||
@@ -247,37 +253,35 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
|
||||
fun clearKeySelection(installState: MutableState<KeyInstallState>) {
|
||||
selectedKeyFile = null
|
||||
installState.value = KeyInstallState.None
|
||||
installState.value = KeyInstallState.File
|
||||
}
|
||||
|
||||
fun selectFirmware(installState: MutableState<FirmwareInstallState>) {
|
||||
if (installState.value != FirmwareInstallState.None)
|
||||
if (installState.value != FirmwareInstallState.File)
|
||||
return
|
||||
|
||||
activity.storageHelper!!.onFileSelected = { _, files ->
|
||||
run {
|
||||
activity.storageHelper!!.onFileSelected = previousFileCallback
|
||||
val file = files.firstOrNull()
|
||||
file?.apply {
|
||||
if (extension == "xci" || extension == "zip") {
|
||||
installState.value = FirmwareInstallState.Verifying
|
||||
thread {
|
||||
Thread.sleep(1000)
|
||||
val descriptor = activity.contentResolver.openFileDescriptor(file.uri, "rw")
|
||||
descriptor?.use { d ->
|
||||
selectedFirmwareVersion = KenjinxNative.deviceVerifyFirmware(d.fd, extension == "xci")
|
||||
selectedFirmwareFile = file
|
||||
if (!selectedFirmwareVersion.isEmpty()) {
|
||||
installState.value = FirmwareInstallState.Query
|
||||
} else {
|
||||
installState.value = FirmwareInstallState.Cancelled
|
||||
}
|
||||
val file = files.firstOrNull()
|
||||
file?.apply {
|
||||
if (extension == "xci" || extension == "zip") {
|
||||
installState.value = FirmwareInstallState.Verifying
|
||||
thread {
|
||||
val descriptor = activity.contentResolver.openFileDescriptor(file.uri, "rw")
|
||||
descriptor?.use { d ->
|
||||
selectedFirmwareVersion = KenjinxNative.deviceVerifyFirmware(d.fd, extension == "xci")
|
||||
selectedFirmwareFile = file
|
||||
if (!selectedFirmwareVersion.isEmpty()) {
|
||||
installState.value = FirmwareInstallState.Query
|
||||
} else {
|
||||
installState.value = FirmwareInstallState.Cancelled
|
||||
}
|
||||
}
|
||||
} else {
|
||||
installState.value = FirmwareInstallState.Cancelled
|
||||
}
|
||||
} else {
|
||||
installState.value = FirmwareInstallState.Cancelled
|
||||
}
|
||||
}
|
||||
activity.storageHelper!!.onFileSelected = previousFileCallback
|
||||
}
|
||||
activity.storageHelper?.storage?.openFilePicker()
|
||||
}
|
||||
@@ -286,7 +290,7 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
if (installState.value != FirmwareInstallState.Query)
|
||||
return
|
||||
if (selectedFirmwareFile == null) {
|
||||
installState.value = FirmwareInstallState.None
|
||||
installState.value = FirmwareInstallState.File
|
||||
return
|
||||
}
|
||||
selectedFirmwareFile?.apply {
|
||||
@@ -312,18 +316,18 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
fun clearFirmwareSelection(installState: MutableState<FirmwareInstallState>) {
|
||||
selectedFirmwareFile = null
|
||||
selectedFirmwareVersion = ""
|
||||
installState.value = FirmwareInstallState.None
|
||||
installState.value = FirmwareInstallState.File
|
||||
}
|
||||
|
||||
fun importAppData(
|
||||
file: DocumentFile,
|
||||
dataImportState: MutableState<DataImportState>
|
||||
fun resetAppData(
|
||||
dataResetState: MutableState<DataResetState>
|
||||
) {
|
||||
dataImportState.value = DataImportState.Import
|
||||
try {
|
||||
MainActivity.StorageHelper?.apply {
|
||||
val stream = file.openInputStream(storage.context)
|
||||
stream?.apply {
|
||||
dataResetState.value = DataResetState.Reset
|
||||
thread {
|
||||
Thread.sleep(1000)
|
||||
|
||||
try {
|
||||
MainActivity.StorageHelper?.apply {
|
||||
val folders = listOf("bis", "games", "profiles", "system")
|
||||
for (f in folders) {
|
||||
val dir = File(MainActivity.AppPath + "${File.separator}${f}")
|
||||
@@ -333,42 +337,73 @@ class SettingsViewModel(val activity: MainActivity) {
|
||||
|
||||
dir.mkdirs()
|
||||
}
|
||||
ZipInputStream(stream).use { zip ->
|
||||
while (true) {
|
||||
val header = zip.nextEntry ?: break
|
||||
if (!folders.any { header.fileName.startsWith(it) }) {
|
||||
continue
|
||||
}
|
||||
val filePath =
|
||||
MainActivity.AppPath + File.separator + header.fileName
|
||||
}
|
||||
} finally {
|
||||
dataResetState.value = DataResetState.Done
|
||||
KenjinxNative.deviceReloadFilesystem()
|
||||
MainActivity.mainViewModel?.refreshFirmwareVersion()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!header.isDirectory) {
|
||||
val bos = BufferedOutputStream(FileOutputStream(filePath))
|
||||
val bytesIn = ByteArray(4096)
|
||||
var read: Int = 0
|
||||
while (zip.read(bytesIn).also { read = it } > 0) {
|
||||
bos.write(bytesIn, 0, read)
|
||||
fun importAppData(
|
||||
file: DocumentFile,
|
||||
dataImportState: MutableState<DataImportState>
|
||||
) {
|
||||
dataImportState.value = DataImportState.Import
|
||||
thread {
|
||||
Thread.sleep(1000)
|
||||
|
||||
try {
|
||||
MainActivity.StorageHelper?.apply {
|
||||
val stream = file.openInputStream(storage.context)
|
||||
stream?.apply {
|
||||
val folders = listOf("bis", "games", "profiles", "system")
|
||||
for (f in folders) {
|
||||
val dir = File(MainActivity.AppPath + "${File.separator}${f}")
|
||||
if (dir.exists()) {
|
||||
dir.deleteRecursively()
|
||||
}
|
||||
|
||||
dir.mkdirs()
|
||||
}
|
||||
ZipInputStream(stream).use { zip ->
|
||||
while (true) {
|
||||
val header = zip.nextEntry ?: break
|
||||
if (!folders.any { header.fileName.startsWith(it) }) {
|
||||
continue
|
||||
}
|
||||
val filePath =
|
||||
MainActivity.AppPath + File.separator + header.fileName
|
||||
|
||||
if (!header.isDirectory) {
|
||||
val bos = BufferedOutputStream(FileOutputStream(filePath))
|
||||
val bytesIn = ByteArray(4096)
|
||||
var read: Int = 0
|
||||
while (zip.read(bytesIn).also { read = it } > 0) {
|
||||
bos.write(bytesIn, 0, read)
|
||||
}
|
||||
bos.close()
|
||||
} else {
|
||||
val dir = File(filePath)
|
||||
dir.mkdir()
|
||||
}
|
||||
bos.close()
|
||||
} else {
|
||||
val dir = File(filePath)
|
||||
dir.mkdir()
|
||||
}
|
||||
}
|
||||
stream.close()
|
||||
}
|
||||
stream.close()
|
||||
}
|
||||
} finally {
|
||||
dataImportState.value = DataImportState.Done
|
||||
KenjinxNative.deviceReloadFilesystem()
|
||||
MainActivity.mainViewModel?.refreshFirmwareVersion()
|
||||
}
|
||||
} finally {
|
||||
dataImportState.value = DataImportState.Done
|
||||
KenjinxNative.deviceReloadFilesystem()
|
||||
MainActivity.mainViewModel?.refreshFirmwareVersion()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum class KeyInstallState {
|
||||
None,
|
||||
File,
|
||||
Cancelled,
|
||||
Query,
|
||||
Install,
|
||||
@@ -376,7 +411,7 @@ enum class KeyInstallState {
|
||||
}
|
||||
|
||||
enum class FirmwareInstallState {
|
||||
None,
|
||||
File,
|
||||
Cancelled,
|
||||
Verifying,
|
||||
Query,
|
||||
@@ -384,8 +419,14 @@ enum class FirmwareInstallState {
|
||||
Done
|
||||
}
|
||||
|
||||
enum class DataResetState {
|
||||
Query,
|
||||
Reset,
|
||||
Done
|
||||
}
|
||||
|
||||
enum class DataImportState {
|
||||
None,
|
||||
File,
|
||||
Query,
|
||||
Import,
|
||||
Done
|
||||
|
||||
@@ -22,6 +22,7 @@ import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.automirrored.filled.ArrowBack
|
||||
import androidx.compose.material.icons.filled.Add
|
||||
import androidx.compose.material.icons.filled.Build
|
||||
import androidx.compose.material.icons.filled.Create
|
||||
import androidx.compose.material.icons.filled.FileDownload
|
||||
import androidx.compose.material.icons.filled.Home
|
||||
import androidx.compose.material.icons.filled.MailOutline
|
||||
@@ -62,6 +63,7 @@ import kotlin.concurrent.thread
|
||||
import org.kenjinx.android.MainActivity
|
||||
import org.kenjinx.android.providers.DocumentProvider
|
||||
import org.kenjinx.android.viewmodels.DataImportState
|
||||
import org.kenjinx.android.viewmodels.DataResetState
|
||||
import org.kenjinx.android.viewmodels.FirmwareInstallState
|
||||
import org.kenjinx.android.viewmodels.KeyInstallState
|
||||
import org.kenjinx.android.viewmodels.MainViewModel
|
||||
@@ -90,6 +92,8 @@ class SettingViews {
|
||||
val vSyncMode = remember { mutableStateOf(VSyncMode.Switch) }
|
||||
val enableDocked = remember { mutableStateOf(false) }
|
||||
val enablePptc = remember { mutableStateOf(false) }
|
||||
val enableLowPowerPptc = remember { mutableStateOf(false) }
|
||||
val enableJitCacheEviction = remember { mutableStateOf(false) }
|
||||
var enableFsIntegrityChecks = remember { mutableStateOf(false) }
|
||||
var fsGlobalAccessLogMode = remember { mutableStateOf(0) }
|
||||
val ignoreMissingServices = remember { mutableStateOf(false) }
|
||||
@@ -100,12 +104,14 @@ class SettingViews {
|
||||
val maxAnisotropy = remember { mutableStateOf(0f) }
|
||||
val useVirtualController = remember { mutableStateOf(true) }
|
||||
val showKeyDialog = remember { mutableStateOf(false) }
|
||||
val keyInstallState = remember { mutableStateOf(KeyInstallState.None) }
|
||||
val keyInstallState = remember { mutableStateOf(KeyInstallState.File) }
|
||||
val showFirwmareDialog = remember { mutableStateOf(false) }
|
||||
val firmwareInstallState = remember { mutableStateOf(FirmwareInstallState.None) }
|
||||
val firmwareInstallState = remember { mutableStateOf(FirmwareInstallState.File) }
|
||||
val firmwareVersion = remember { mutableStateOf(mainViewModel.firmwareVersion) }
|
||||
val showDataResetDialog = remember { mutableStateOf(false) }
|
||||
val showDataImportDialog = remember { mutableStateOf(false) }
|
||||
val dataImportState = remember { mutableStateOf(DataImportState.None) }
|
||||
val dataResetState = remember { mutableStateOf(DataResetState.Query) }
|
||||
val dataImportState = remember { mutableStateOf(DataImportState.File) }
|
||||
var dataFile = remember { mutableStateOf<DocumentFile?>(null) }
|
||||
val isGrid = remember { mutableStateOf(true) }
|
||||
val useSwitchLayout = remember { mutableStateOf(true) }
|
||||
@@ -131,6 +137,8 @@ class SettingViews {
|
||||
vSyncMode,
|
||||
enableDocked,
|
||||
enablePptc,
|
||||
enableLowPowerPptc,
|
||||
enableJitCacheEviction,
|
||||
enableFsIntegrityChecks,
|
||||
fsGlobalAccessLogMode,
|
||||
ignoreMissingServices,
|
||||
@@ -172,6 +180,8 @@ class SettingViews {
|
||||
vSyncMode,
|
||||
enableDocked,
|
||||
enablePptc,
|
||||
enableLowPowerPptc,
|
||||
enableJitCacheEviction,
|
||||
enableFsIntegrityChecks,
|
||||
fsGlobalAccessLogMode,
|
||||
ignoreMissingServices,
|
||||
@@ -236,23 +246,6 @@ class SettingViews {
|
||||
modifier = Modifier.align(Alignment.CenterVertically)
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(56.dp)
|
||||
.padding(horizontal = 8.dp, vertical = 8.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
){
|
||||
ActionButton(
|
||||
onClick = {
|
||||
settingsViewModel.openGameFolder()
|
||||
},
|
||||
text = "Add Game Folder",
|
||||
icon = Icons.Default.Add,
|
||||
modifier = Modifier.weight(1f),
|
||||
isFullWidth = false,
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -287,7 +280,40 @@ class SettingViews {
|
||||
isFullWidth = false,
|
||||
)
|
||||
}
|
||||
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(56.dp)
|
||||
.padding(horizontal = 8.dp, vertical = 8.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
){
|
||||
ActionButton(
|
||||
onClick = {
|
||||
settingsViewModel.openGameFolder()
|
||||
},
|
||||
text = "Add Game Folder",
|
||||
icon = Icons.Default.Add,
|
||||
modifier = Modifier.weight(1f),
|
||||
isFullWidth = false,
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.height(56.dp)
|
||||
.padding(horizontal = 8.dp, vertical = 8.dp),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
) {
|
||||
ActionButton(
|
||||
onClick = {
|
||||
showDataResetDialog.value = true
|
||||
},
|
||||
text = "Reinit App Data",
|
||||
icon = Icons.Default.Create,
|
||||
modifier = Modifier.weight(1f),
|
||||
isFullWidth = false,
|
||||
)
|
||||
}
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
@@ -359,6 +385,7 @@ class SettingViews {
|
||||
if (keyInstallState.value != KeyInstallState.Install) {
|
||||
showKeyDialog.value = false
|
||||
settingsViewModel.clearKeySelection(keyInstallState)
|
||||
keyInstallState.value = KeyInstallState.File
|
||||
}
|
||||
}
|
||||
) {
|
||||
@@ -378,7 +405,7 @@ class SettingViews {
|
||||
)
|
||||
|
||||
when (keyInstallState.value) {
|
||||
KeyInstallState.None -> {
|
||||
KeyInstallState.File -> {
|
||||
Text(
|
||||
text = "Select a key file to install key from.",
|
||||
modifier = Modifier
|
||||
@@ -437,7 +464,7 @@ class SettingViews {
|
||||
keyInstallState
|
||||
)
|
||||
|
||||
if (keyInstallState.value == KeyInstallState.None) {
|
||||
if (keyInstallState.value == KeyInstallState.File) {
|
||||
showKeyDialog.value = false
|
||||
settingsViewModel.clearKeySelection(keyInstallState)
|
||||
}
|
||||
@@ -561,6 +588,7 @@ class SettingViews {
|
||||
if (firmwareInstallState.value != FirmwareInstallState.Install) {
|
||||
showFirwmareDialog.value = false
|
||||
settingsViewModel.clearFirmwareSelection(firmwareInstallState)
|
||||
firmwareInstallState.value = FirmwareInstallState.File
|
||||
}
|
||||
}
|
||||
) {
|
||||
@@ -580,7 +608,7 @@ class SettingViews {
|
||||
)
|
||||
|
||||
when (firmwareInstallState.value) {
|
||||
FirmwareInstallState.None -> {
|
||||
FirmwareInstallState.File -> {
|
||||
Text(
|
||||
text = "Select a zip or xci file to install firmware from.",
|
||||
modifier = Modifier
|
||||
@@ -635,7 +663,7 @@ class SettingViews {
|
||||
onClick = {
|
||||
settingsViewModel.installFirmware(firmwareInstallState)
|
||||
|
||||
if (firmwareInstallState.value == FirmwareInstallState.None) {
|
||||
if (firmwareInstallState.value == FirmwareInstallState.File) {
|
||||
showFirwmareDialog.value = false
|
||||
settingsViewModel.clearFirmwareSelection(firmwareInstallState)
|
||||
}
|
||||
@@ -779,13 +807,125 @@ class SettingViews {
|
||||
}
|
||||
}
|
||||
}
|
||||
SimpleAlertDialog.Custom(
|
||||
showDialog = showDataResetDialog,
|
||||
onDismissRequest = {
|
||||
if (dataResetState.value != DataResetState.Reset) {
|
||||
showDataResetDialog.value = false
|
||||
dataResetState.value = DataResetState.Query
|
||||
}
|
||||
}
|
||||
) {
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.padding(16.dp)
|
||||
.fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.SpaceBetween,
|
||||
horizontalAlignment = Alignment.CenterHorizontally
|
||||
) {
|
||||
Text(
|
||||
text = "App Data Reinit",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(bottom = 16.dp),
|
||||
textAlign = TextAlign.Center
|
||||
)
|
||||
|
||||
when (dataResetState.value) {
|
||||
DataResetState.Query -> {
|
||||
Text(
|
||||
text = "Current bis, games, profiles and system folders will be reset. Do you want to continue?",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 8.dp, bottom = 8.dp),
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp)
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
thread {
|
||||
settingsViewModel.resetAppData(dataResetState)
|
||||
}
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Text(text = "Yes")
|
||||
}
|
||||
Button(
|
||||
onClick = {
|
||||
showDataResetDialog.value = false
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Text(text = "No")
|
||||
}
|
||||
}
|
||||
}
|
||||
DataResetState.Reset -> {
|
||||
Text(
|
||||
text = "Resetting app data...",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 8.dp, bottom = 8.dp),
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
LinearProgressIndicator(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp)
|
||||
)
|
||||
}
|
||||
DataResetState.Done -> {
|
||||
Text(
|
||||
text = "Data reset completed successfully.",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 8.dp, bottom = 8.dp),
|
||||
textAlign = TextAlign.Start
|
||||
)
|
||||
|
||||
Row(
|
||||
horizontalArrangement = Arrangement.SpaceEvenly,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(top = 16.dp)
|
||||
) {
|
||||
Button(
|
||||
onClick = {
|
||||
showDataResetDialog.value = false
|
||||
firmwareVersion.value = mainViewModel.firmwareVersion
|
||||
dataResetState.value = DataResetState.Query
|
||||
mainViewModel.userViewModel.refreshUsers()
|
||||
mainViewModel.homeViewModel.requestReload()
|
||||
mainViewModel.activity.shutdownAndRestart()
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
.padding(horizontal = 8.dp)
|
||||
) {
|
||||
Text(text = "Close")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
SimpleAlertDialog.Custom(
|
||||
showDialog = showDataImportDialog,
|
||||
onDismissRequest = {
|
||||
if (dataImportState.value != DataImportState.Import) {
|
||||
showDataImportDialog.value = false
|
||||
dataFile.value = null
|
||||
dataImportState.value = DataImportState.None
|
||||
dataImportState.value = DataImportState.File
|
||||
}
|
||||
}
|
||||
) {
|
||||
@@ -805,9 +945,9 @@ class SettingViews {
|
||||
)
|
||||
|
||||
when (dataImportState.value) {
|
||||
DataImportState.None -> {
|
||||
DataImportState.File -> {
|
||||
Text(
|
||||
text = "Select a zip file to import app data from.",
|
||||
text = "Select a zip file to import bis, games, profiles and system folders from another Android installation.",
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(start = 8.dp, bottom = 8.dp),
|
||||
@@ -854,7 +994,7 @@ class SettingViews {
|
||||
onClick = {
|
||||
showDataImportDialog.value = false
|
||||
dataFile.value = null
|
||||
dataImportState.value = DataImportState.None
|
||||
dataImportState.value = DataImportState.File
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
@@ -942,9 +1082,10 @@ class SettingViews {
|
||||
showDataImportDialog.value = false
|
||||
dataFile.value = null
|
||||
firmwareVersion.value = mainViewModel.firmwareVersion
|
||||
dataImportState.value = DataImportState.None
|
||||
dataImportState.value = DataImportState.File
|
||||
mainViewModel.userViewModel.refreshUsers()
|
||||
mainViewModel.homeViewModel.requestReload()
|
||||
mainViewModel.activity.shutdownAndRestart()
|
||||
},
|
||||
modifier = Modifier
|
||||
.weight(1f)
|
||||
@@ -1032,6 +1173,8 @@ class SettingViews {
|
||||
Column(modifier = Modifier.fillMaxWidth()) {
|
||||
useNce.SwitchSelector(label = "Enable NCE (Native Code Execution)")
|
||||
enablePptc.SwitchSelector(label = "Enable PPTC (Profiled Persistent Translation Cache)")
|
||||
enableLowPowerPptc.SwitchSelector(label = "Enable Low-Power PPTC")
|
||||
enableJitCacheEviction.SwitchSelector(label = "Enable Jit Cache Eviction")
|
||||
MemoryModeDropdown(
|
||||
selectedMemoryManagerMode = memoryManagerMode.value,
|
||||
onModeSelected = { mode ->
|
||||
|
||||
Reference in New Issue
Block a user