diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/MainViewModel.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/MainViewModel.kt index 5647c516d..81b3bf91b 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/MainViewModel.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/MainViewModel.kt @@ -4,6 +4,7 @@ import android.annotation.SuppressLint import androidx.compose.runtime.MutableState import androidx.compose.runtime.mutableStateOf import androidx.navigation.NavHostController +import androidx.preference.PreferenceManager import com.anggrayudi.storage.extension.launchOnUiThread import kotlinx.coroutines.runBlocking import kotlinx.coroutines.sync.Semaphore @@ -75,6 +76,20 @@ class MainViewModel(val activity: MainActivity) { motionSensorManager?.setControllerId(-1) } + // ---- Load language/region from Preferences (Defaults: AmericanEnglish/USA) ---- + private fun loadSystemLanguage(): SystemLanguage { + val prefs = PreferenceManager.getDefaultSharedPreferences(activity) + val stored = prefs.getString("system_language", "AmericanEnglish") ?: "AmericanEnglish" + return runCatching { SystemLanguage.valueOf(stored) }.getOrElse { SystemLanguage.AmericanEnglish } + } + + private fun loadRegionCode(): RegionCode { + val prefs = PreferenceManager.getDefaultSharedPreferences(activity) + val stored = prefs.getString("region_code", "USA") ?: "USA" + return runCatching { RegionCode.valueOf(stored) }.getOrElse { RegionCode.USA } + } + // ------------------------------------------------------------------------------- + fun loadGame(game: GameModel, overrideSettings: Boolean? = false, forceNceAndPptc: Boolean? = false): Int { KenjinxNative.deviceReinitEmulation() MainActivity.mainViewModel?.activity?.uiHandler = UiHandler() @@ -174,8 +189,10 @@ class MainViewModel(val activity: MainActivity) { settings.memoryManagerMode.ordinal, settings.useNce, settings.memoryConfiguration.ordinal, - SystemLanguage.AmericanEnglish.ordinal, - RegionCode.USA.ordinal, + /* OLD: was fixed -> SystemLanguage.AmericanEnglish.ordinal */ + loadSystemLanguage().ordinal, + /* OLD: was fixed -> RegionCode.USA.ordinal */ + loadRegionCode().ordinal, settings.vSyncMode.ordinal, settings.enableDocked, settings.enablePptc, @@ -282,8 +299,10 @@ class MainViewModel(val activity: MainActivity) { settings.memoryManagerMode.ordinal, settings.useNce, settings.memoryConfiguration.ordinal, - SystemLanguage.AmericanEnglish.ordinal, - RegionCode.USA.ordinal, + /* OLD: was fixed -> SystemLanguage.AmericanEnglish.ordinal */ + loadSystemLanguage().ordinal, + /* OLD: was fixed -> RegionCode.USA.ordinal */ + loadRegionCode().ordinal, settings.vSyncMode.ordinal, settings.enableDocked, settings.enablePptc, diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/SettingsViewModel.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/SettingsViewModel.kt index f59e004b7..fc804aa9f 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/SettingsViewModel.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/viewmodels/SettingsViewModel.kt @@ -20,6 +20,10 @@ import java.io.FileOutputStream import kotlin.concurrent.thread import androidx.core.content.edit +// Import enums +import org.kenjinx.android.SystemLanguage +import org.kenjinx.android.RegionCode + class SettingsViewModel(val activity: MainActivity) { var selectedFirmwareVersion: String = "" private var previousFileCallback: ((requestCode: Int, files: List) -> Unit)? @@ -69,7 +73,9 @@ class SettingsViewModel(val activity: MainActivity) { enableFsAccessLogs: MutableState, enableTraceLogs: MutableState, enableDebugLogs: MutableState, - enableGraphicsLogs: MutableState + enableGraphicsLogs: MutableState, + systemLanguage: MutableState, + regionCode: MutableState ) { memoryManagerMode.value = MemoryManagerMode.entries.toTypedArray()[sharedPref.getInt("memoryManagerMode", MemoryManagerMode.HostMappedUnsafe.ordinal)] useNce.value = sharedPref.getBoolean("useNce", false) @@ -102,6 +108,12 @@ class SettingsViewModel(val activity: MainActivity) { enableTraceLogs.value = sharedPref.getBoolean("enableTraceLogs", false) enableDebugLogs.value = sharedPref.getBoolean("enableDebugLogs", false) enableGraphicsLogs.value = sharedPref.getBoolean("enableGraphicsLogs", false) + + // Load language/region (strings, fallback to defaults, then .valueOf) + val langName = sharedPref.getString("system_language", "AmericanEnglish") ?: "AmericanEnglish" + val regionName = sharedPref.getString("region_code", "USA") ?: "USA" + systemLanguage.value = runCatching { SystemLanguage.valueOf(langName) }.getOrElse { SystemLanguage.AmericanEnglish } + regionCode.value = runCatching { RegionCode.valueOf(regionName) }.getOrElse { RegionCode.USA } } fun save( @@ -135,7 +147,9 @@ class SettingsViewModel(val activity: MainActivity) { enableFsAccessLogs: MutableState, enableTraceLogs: MutableState, enableDebugLogs: MutableState, - enableGraphicsLogs: MutableState + enableGraphicsLogs: MutableState, + systemLanguage: MutableState, + regionCode: MutableState ) { sharedPref.edit { @@ -171,6 +185,9 @@ class SettingsViewModel(val activity: MainActivity) { putBoolean("enableDebugLogs", enableDebugLogs.value) putBoolean("enableGraphicsLogs", enableGraphicsLogs.value) + // Save language/region as string (enum name) + putString("system_language", systemLanguage.value.name) + putString("region_code", regionCode.value.name) } activity.storageHelper!!.onFolderSelected = previousFolderCallback diff --git a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/SettingViews.kt b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/SettingViews.kt index 4fcb4455c..a2554f78f 100644 --- a/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/SettingViews.kt +++ b/src/KenjinxAndroid/app/src/main/java/org/kenjinx/android/views/SettingViews.kt @@ -43,6 +43,7 @@ import androidx.compose.material3.MaterialTheme import androidx.compose.material3.PlainTooltip import androidx.compose.material3.Scaffold import androidx.compose.material3.Slider +import androidx.compose.material3.Switch import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar import androidx.compose.runtime.Composable @@ -83,6 +84,10 @@ import org.kenjinx.android.widgets.SwitchSelector import org.kenjinx.android.viewmodels.QuickSettings import org.kenjinx.android.viewmodels.QuickSettings.OrientationPreference +// Import enums +import org.kenjinx.android.SystemLanguage +import org.kenjinx.android.RegionCode + class SettingViews { companion object { const val EXPANSTION_TRANSITION_DURATION = 450 @@ -140,6 +145,10 @@ class SettingViews { mutableStateOf(QuickSettings(mainViewModel.activity).orientationPreference) } + // Language & Region States + val systemLanguage = remember { mutableStateOf(SystemLanguage.AmericanEnglish) } + val regionCode = remember { mutableStateOf(RegionCode.USA) } + if (!loaded.value) { settingsViewModel.initializeState( memoryManagerMode, @@ -172,7 +181,9 @@ class SettingViews { enableFsAccessLogs, enableTraceLogs, enableDebugLogs, - enableGraphicsLogs + enableGraphicsLogs, + systemLanguage, + regionCode ) loaded.value = true } @@ -215,7 +226,9 @@ class SettingViews { enableFsAccessLogs, enableTraceLogs, enableDebugLogs, - enableGraphicsLogs + enableGraphicsLogs, + systemLanguage, + regionCode ) if (!isNavigating.value) { @@ -1174,6 +1187,17 @@ class SettingViews { } ExpandableView(onCardArrowClick = { }, title = "System", icon = Icons.Outlined.Settings) { Column(modifier = Modifier.fillMaxWidth()) { + + // Language & Region + LanguageDropdown( + selectedLanguage = systemLanguage.value, + onLanguageSelected = { lang -> systemLanguage.value = lang } + ) + RegionDropdown( + selectedRegion = regionCode.value, + onRegionSelected = { reg -> regionCode.value = reg } + ) + VSyncDropdown( selectedVSyncMode = vSyncMode.value, onModeSelected = { mode -> @@ -1296,6 +1320,71 @@ class SettingViews { } } + // ---- Dropdowns for language & region ---- + + @Composable + fun LanguageDropdown( + selectedLanguage: SystemLanguage, + onLanguageSelected: (SystemLanguage) -> Unit + ) { + val options = SystemLanguage.entries.toTypedArray() + DropdownSelector( + label = "System Language", + selectedValue = selectedLanguage, + options = options.toList(), + getDisplayText = { lang -> + when (lang) { + SystemLanguage.Japanese -> "Japanese" + SystemLanguage.AmericanEnglish -> "English (US)" + SystemLanguage.French -> "French" + SystemLanguage.German -> "German" + SystemLanguage.Italian -> "Italian" + SystemLanguage.Spanish -> "Spanish (EU)" + SystemLanguage.Chinese -> "Chinese" + SystemLanguage.Korean -> "Korean" + SystemLanguage.Dutch -> "Dutch" + SystemLanguage.Portuguese -> "Portuguese (EU)" + SystemLanguage.Russian -> "Russian" + SystemLanguage.Taiwanese -> "Chinese (Taiwan)" + SystemLanguage.BritishEnglish -> "English (UK)" + SystemLanguage.CanadianFrench -> "French (Canada)" + SystemLanguage.LatinAmericanSpanish -> "Spanish (LatAm)" + SystemLanguage.SimplifiedChinese -> "Chinese (Simplified)" + SystemLanguage.TraditionalChinese -> "Chinese (Traditional)" + SystemLanguage.BrazilianPortuguese -> "Portuguese (Brazil)" + } + }, + onOptionSelected = onLanguageSelected + ) + } + + @Composable + fun RegionDropdown( + selectedRegion: RegionCode, + onRegionSelected: (RegionCode) -> Unit + ) { + val options = RegionCode.entries.toTypedArray() + DropdownSelector( + label = "Region", + selectedValue = selectedRegion, + options = options.toList(), + getDisplayText = { region -> + when (region) { + RegionCode.Japan -> "Japan" + RegionCode.USA -> "USA" + RegionCode.Europe -> "Europe" + RegionCode.Australia -> "Australia" + RegionCode.China -> "China" + RegionCode.Korea -> "Korea" + RegionCode.Taiwan -> "Taiwan" + } + }, + onOptionSelected = onRegionSelected + ) + } + + // ---- Existing dropdowns ---- + // ---- Dropdown for orientation ---- @Composable fun OrientationDropdown(