diff options
49 files changed, 869 insertions, 969 deletions
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt index 9c32e044c..5a7cf4ed7 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/NativeLibrary.kt | |||
| @@ -219,10 +219,6 @@ object NativeLibrary { | |||
| 219 | 219 | ||
| 220 | external fun reloadSettings() | 220 | external fun reloadSettings() |
| 221 | 221 | ||
| 222 | external fun getUserSetting(gameID: String?, Section: String?, Key: String?): String? | ||
| 223 | |||
| 224 | external fun setUserSetting(gameID: String?, Section: String?, Key: String?, Value: String?) | ||
| 225 | |||
| 226 | external fun initGameIni(gameID: String?) | 222 | external fun initGameIni(gameID: String?) |
| 227 | 223 | ||
| 228 | /** | 224 | /** |
| @@ -413,14 +409,17 @@ object NativeLibrary { | |||
| 413 | details.ifEmpty { emulationActivity.getString(R.string.system_archive_general) } | 409 | details.ifEmpty { emulationActivity.getString(R.string.system_archive_general) } |
| 414 | ) | 410 | ) |
| 415 | } | 411 | } |
| 412 | |||
| 416 | CoreError.ErrorSavestate -> { | 413 | CoreError.ErrorSavestate -> { |
| 417 | title = emulationActivity.getString(R.string.save_load_error) | 414 | title = emulationActivity.getString(R.string.save_load_error) |
| 418 | message = details | 415 | message = details |
| 419 | } | 416 | } |
| 417 | |||
| 420 | CoreError.ErrorUnknown -> { | 418 | CoreError.ErrorUnknown -> { |
| 421 | title = emulationActivity.getString(R.string.fatal_error) | 419 | title = emulationActivity.getString(R.string.fatal_error) |
| 422 | message = emulationActivity.getString(R.string.fatal_error_message) | 420 | message = emulationActivity.getString(R.string.fatal_error_message) |
| 423 | } | 421 | } |
| 422 | |||
| 424 | else -> { | 423 | else -> { |
| 425 | return true | 424 | return true |
| 426 | } | 425 | } |
| @@ -454,6 +453,7 @@ object NativeLibrary { | |||
| 454 | captionId = R.string.loader_error_video_core | 453 | captionId = R.string.loader_error_video_core |
| 455 | descriptionId = R.string.loader_error_video_core_description | 454 | descriptionId = R.string.loader_error_video_core_description |
| 456 | } | 455 | } |
| 456 | |||
| 457 | else -> { | 457 | else -> { |
| 458 | captionId = R.string.loader_error_encrypted | 458 | captionId = R.string.loader_error_encrypted |
| 459 | descriptionId = R.string.loader_error_encrypted_roms_description | 459 | descriptionId = R.string.loader_error_encrypted_roms_description |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt index 7461fb093..6f52a7a8d 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/activities/EmulationActivity.kt | |||
| @@ -28,7 +28,6 @@ import android.view.Surface | |||
| 28 | import android.view.View | 28 | import android.view.View |
| 29 | import android.view.inputmethod.InputMethodManager | 29 | import android.view.inputmethod.InputMethodManager |
| 30 | import android.widget.Toast | 30 | import android.widget.Toast |
| 31 | import androidx.activity.viewModels | ||
| 32 | import androidx.appcompat.app.AppCompatActivity | 31 | import androidx.appcompat.app.AppCompatActivity |
| 33 | import androidx.core.view.WindowCompat | 32 | import androidx.core.view.WindowCompat |
| 34 | import androidx.core.view.WindowInsetsCompat | 33 | import androidx.core.view.WindowInsetsCompat |
| @@ -42,7 +41,6 @@ import org.yuzu.yuzu_emu.databinding.ActivityEmulationBinding | |||
| 42 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | 41 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| 43 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting | 42 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting |
| 44 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 43 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 45 | import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel | ||
| 46 | import org.yuzu.yuzu_emu.model.Game | 44 | import org.yuzu.yuzu_emu.model.Game |
| 47 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper | 45 | import org.yuzu.yuzu_emu.utils.ControllerMappingHelper |
| 48 | import org.yuzu.yuzu_emu.utils.ForegroundService | 46 | import org.yuzu.yuzu_emu.utils.ForegroundService |
| @@ -72,8 +70,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 72 | private val actionMute = "ACTION_EMULATOR_MUTE" | 70 | private val actionMute = "ACTION_EMULATOR_MUTE" |
| 73 | private val actionUnmute = "ACTION_EMULATOR_UNMUTE" | 71 | private val actionUnmute = "ACTION_EMULATOR_UNMUTE" |
| 74 | 72 | ||
| 75 | private val settingsViewModel: SettingsViewModel by viewModels() | ||
| 76 | |||
| 77 | override fun onDestroy() { | 73 | override fun onDestroy() { |
| 78 | stopForegroundService(this) | 74 | stopForegroundService(this) |
| 79 | super.onDestroy() | 75 | super.onDestroy() |
| @@ -82,8 +78,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener { | |||
| 82 | override fun onCreate(savedInstanceState: Bundle?) { | 78 | override fun onCreate(savedInstanceState: Bundle?) { |
| 83 | ThemeHelper.setTheme(this) | 79 | ThemeHelper.setTheme(this) |
| 84 | 80 | ||
| 85 | settingsViewModel.settings.loadSettings() | ||
| 86 | |||
| 87 | super.onCreate(savedInstanceState) | 81 | super.onCreate(savedInstanceState) |
| 88 | 82 | ||
| 89 | binding = ActivityEmulationBinding.inflate(layoutInflater) | 83 | binding = ActivityEmulationBinding.inflate(layoutInflater) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractBooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractBooleanSetting.kt index a6e9833ee..aeda8d222 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractBooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractBooleanSetting.kt | |||
| @@ -4,5 +4,7 @@ | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | interface AbstractBooleanSetting : AbstractSetting { | 6 | interface AbstractBooleanSetting : AbstractSetting { |
| 7 | var boolean: Boolean | 7 | val boolean: Boolean |
| 8 | |||
| 9 | fun setBoolean(value: Boolean) | ||
| 8 | } | 10 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/SettingsViewModel.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractByteSetting.kt index bd9233d62..606519ad8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/SettingsViewModel.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractByteSetting.kt | |||
| @@ -3,8 +3,8 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | import androidx.lifecycle.ViewModel | 6 | interface AbstractByteSetting : AbstractSetting { |
| 7 | val byte: Byte | ||
| 7 | 8 | ||
| 8 | class SettingsViewModel : ViewModel() { | 9 | fun setByte(value: Byte) |
| 9 | val settings = Settings() | ||
| 10 | } | 10 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractFloatSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractFloatSetting.kt index 6fe4bc263..974925eed 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractFloatSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractFloatSetting.kt | |||
| @@ -4,5 +4,7 @@ | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | interface AbstractFloatSetting : AbstractSetting { | 6 | interface AbstractFloatSetting : AbstractSetting { |
| 7 | var float: Float | 7 | val float: Float |
| 8 | |||
| 9 | fun setFloat(value: Float) | ||
| 8 | } | 10 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractIntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractIntSetting.kt index 892b7dcfe..89b285b10 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractIntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractIntSetting.kt | |||
| @@ -4,5 +4,7 @@ | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | interface AbstractIntSetting : AbstractSetting { | 6 | interface AbstractIntSetting : AbstractSetting { |
| 7 | var int: Int | 7 | val int: Int |
| 8 | |||
| 9 | fun setInt(value: Int) | ||
| 8 | } | 10 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractLongSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractLongSetting.kt new file mode 100644 index 000000000..4873942db --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractLongSetting.kt | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | ||
| 5 | |||
| 6 | interface AbstractLongSetting : AbstractSetting { | ||
| 7 | val long: Long | ||
| 8 | |||
| 9 | fun setLong(value: Long) | ||
| 10 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractSetting.kt index 258580209..7afed95ad 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractSetting.kt | |||
| @@ -3,10 +3,17 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 7 | |||
| 6 | interface AbstractSetting { | 8 | interface AbstractSetting { |
| 7 | val key: String? | 9 | val key: String? |
| 8 | val section: String? | 10 | val category: Settings.Category |
| 9 | val isRuntimeEditable: Boolean | ||
| 10 | val valueAsString: String | ||
| 11 | val defaultValue: Any | 11 | val defaultValue: Any |
| 12 | val valueAsString: String | ||
| 13 | get() = "" | ||
| 14 | |||
| 15 | val isRuntimeModifiable: Boolean | ||
| 16 | get() = NativeConfig.getIsRuntimeModifiable(key!!) | ||
| 17 | |||
| 18 | fun reset() = run { } | ||
| 12 | } | 19 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractShortSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractShortSetting.kt new file mode 100644 index 000000000..91407ccbb --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractShortSetting.kt | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | ||
| 5 | |||
| 6 | interface AbstractShortSetting : AbstractSetting { | ||
| 7 | val short: Short | ||
| 8 | |||
| 9 | fun setShort(value: Short) | ||
| 10 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractStringSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractStringSetting.kt index 0d02c5997..c8935cc48 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractStringSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/AbstractStringSetting.kt | |||
| @@ -4,5 +4,7 @@ | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | interface AbstractStringSetting : AbstractSetting { | 6 | interface AbstractStringSetting : AbstractSetting { |
| 7 | var string: String | 7 | val string: String |
| 8 | |||
| 9 | fun setString(value: String) | ||
| 8 | } | 10 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt index d41933766..f7528642e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/BooleanSetting.kt | |||
| @@ -3,41 +3,34 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 7 | |||
| 6 | enum class BooleanSetting( | 8 | enum class BooleanSetting( |
| 7 | override val key: String, | 9 | override val key: String, |
| 8 | override val section: String, | 10 | override val category: Settings.Category |
| 9 | override val defaultValue: Boolean | ||
| 10 | ) : AbstractBooleanSetting { | 11 | ) : AbstractBooleanSetting { |
| 11 | CPU_DEBUG_MODE("cpu_debug_mode", Settings.SECTION_CPU, false), | 12 | CPU_DEBUG_MODE("cpu_debug_mode", Settings.Category.Cpu), |
| 12 | FASTMEM("cpuopt_fastmem", Settings.SECTION_CPU, true), | 13 | FASTMEM("cpuopt_fastmem", Settings.Category.Cpu), |
| 13 | FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives", Settings.SECTION_CPU, true), | 14 | FASTMEM_EXCLUSIVES("cpuopt_fastmem_exclusives", Settings.Category.Cpu), |
| 14 | PICTURE_IN_PICTURE("picture_in_picture", Settings.SECTION_GENERAL, true), | 15 | RENDERER_USE_SPEED_LIMIT("use_speed_limit", Settings.Category.Core), |
| 15 | USE_CUSTOM_RTC("custom_rtc_enabled", Settings.SECTION_SYSTEM, false); | 16 | USE_DOCKED_MODE("use_docked_mode", Settings.Category.System), |
| 16 | 17 | RENDERER_USE_DISK_SHADER_CACHE("use_disk_shader_cache", Settings.Category.Renderer), | |
| 17 | override var boolean: Boolean = defaultValue | 18 | RENDERER_FORCE_MAX_CLOCK("force_max_clock", Settings.Category.Renderer), |
| 19 | RENDERER_ASYNCHRONOUS_SHADERS("use_asynchronous_shaders", Settings.Category.Renderer), | ||
| 20 | RENDERER_REACTIVE_FLUSHING("use_reactive_flushing", Settings.Category.Renderer), | ||
| 21 | RENDERER_DEBUG("debug", Settings.Category.Renderer), | ||
| 22 | PICTURE_IN_PICTURE("picture_in_picture", Settings.Category.Android), | ||
| 23 | USE_CUSTOM_RTC("custom_rtc_enabled", Settings.Category.System); | ||
| 24 | |||
| 25 | override val boolean: Boolean | ||
| 26 | get() = NativeConfig.getBoolean(key, false) | ||
| 27 | |||
| 28 | override fun setBoolean(value: Boolean) = NativeConfig.setBoolean(key, value) | ||
| 29 | |||
| 30 | override val defaultValue: Boolean by lazy { NativeConfig.getBoolean(key, true) } | ||
| 18 | 31 | ||
| 19 | override val valueAsString: String | 32 | override val valueAsString: String |
| 20 | get() = boolean.toString() | 33 | get() = if (boolean) "1" else "0" |
| 21 | 34 | ||
| 22 | override val isRuntimeEditable: Boolean | 35 | override fun reset() = NativeConfig.setBoolean(key, defaultValue) |
| 23 | get() { | ||
| 24 | for (setting in NOT_RUNTIME_EDITABLE) { | ||
| 25 | if (setting == this) { | ||
| 26 | return false | ||
| 27 | } | ||
| 28 | } | ||
| 29 | return true | ||
| 30 | } | ||
| 31 | |||
| 32 | companion object { | ||
| 33 | private val NOT_RUNTIME_EDITABLE = listOf( | ||
| 34 | PICTURE_IN_PICTURE, | ||
| 35 | USE_CUSTOM_RTC | ||
| 36 | ) | ||
| 37 | |||
| 38 | fun from(key: String): BooleanSetting? = | ||
| 39 | BooleanSetting.values().firstOrNull { it.key == key } | ||
| 40 | |||
| 41 | fun clear() = BooleanSetting.values().forEach { it.boolean = it.defaultValue } | ||
| 42 | } | ||
| 43 | } | 36 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ByteSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ByteSetting.kt new file mode 100644 index 000000000..6ec0a765e --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ByteSetting.kt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | ||
| 5 | |||
| 6 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 7 | |||
| 8 | enum class ByteSetting( | ||
| 9 | override val key: String, | ||
| 10 | override val category: Settings.Category | ||
| 11 | ) : AbstractByteSetting { | ||
| 12 | AUDIO_VOLUME("volume", Settings.Category.Audio); | ||
| 13 | |||
| 14 | override val byte: Byte | ||
| 15 | get() = NativeConfig.getByte(key, false) | ||
| 16 | |||
| 17 | override fun setByte(value: Byte) = NativeConfig.setByte(key, value) | ||
| 18 | |||
| 19 | override val defaultValue: Byte by lazy { NativeConfig.getByte(key, true) } | ||
| 20 | |||
| 21 | override val valueAsString: String | ||
| 22 | get() = byte.toString() | ||
| 23 | |||
| 24 | override fun reset() = NativeConfig.setByte(key, defaultValue) | ||
| 25 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/FloatSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/FloatSetting.kt index e5545a916..0181d06f2 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/FloatSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/FloatSetting.kt | |||
| @@ -3,34 +3,24 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 7 | |||
| 6 | enum class FloatSetting( | 8 | enum class FloatSetting( |
| 7 | override val key: String, | 9 | override val key: String, |
| 8 | override val section: String, | 10 | override val category: Settings.Category |
| 9 | override val defaultValue: Float | ||
| 10 | ) : AbstractFloatSetting { | 11 | ) : AbstractFloatSetting { |
| 11 | // No float settings currently exist | 12 | // No float settings currently exist |
| 12 | EMPTY_SETTING("", "", 0f); | 13 | EMPTY_SETTING("", Settings.Category.UiGeneral); |
| 13 | |||
| 14 | override var float: Float = defaultValue | ||
| 15 | 14 | ||
| 16 | override val valueAsString: String | 15 | override val float: Float |
| 17 | get() = float.toString() | 16 | get() = NativeConfig.getFloat(key, false) |
| 18 | 17 | ||
| 19 | override val isRuntimeEditable: Boolean | 18 | override fun setFloat(value: Float) = NativeConfig.setFloat(key, value) |
| 20 | get() { | ||
| 21 | for (setting in NOT_RUNTIME_EDITABLE) { | ||
| 22 | if (setting == this) { | ||
| 23 | return false | ||
| 24 | } | ||
| 25 | } | ||
| 26 | return true | ||
| 27 | } | ||
| 28 | 19 | ||
| 29 | companion object { | 20 | override val defaultValue: Float by lazy { NativeConfig.getFloat(key, true) } |
| 30 | private val NOT_RUNTIME_EDITABLE = emptyList<FloatSetting>() | ||
| 31 | 21 | ||
| 32 | fun from(key: String): FloatSetting? = FloatSetting.values().firstOrNull { it.key == key } | 22 | override val valueAsString: String |
| 23 | get() = float.toString() | ||
| 33 | 24 | ||
| 34 | fun clear() = FloatSetting.values().forEach { it.float = it.defaultValue } | 25 | override fun reset() = NativeConfig.setFloat(key, defaultValue) |
| 35 | } | ||
| 36 | } | 26 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt index 4427a7d9d..a64757207 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/IntSetting.kt | |||
| @@ -3,139 +3,34 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 7 | |||
| 6 | enum class IntSetting( | 8 | enum class IntSetting( |
| 7 | override val key: String, | 9 | override val key: String, |
| 8 | override val section: String, | 10 | override val category: Settings.Category |
| 9 | override val defaultValue: Int | ||
| 10 | ) : AbstractIntSetting { | 11 | ) : AbstractIntSetting { |
| 11 | RENDERER_USE_SPEED_LIMIT( | 12 | CPU_ACCURACY("cpu_accuracy", Settings.Category.Cpu), |
| 12 | "use_speed_limit", | 13 | REGION_INDEX("region_index", Settings.Category.System), |
| 13 | Settings.SECTION_RENDERER, | 14 | LANGUAGE_INDEX("language_index", Settings.Category.System), |
| 14 | 1 | 15 | RENDERER_BACKEND("backend", Settings.Category.Renderer), |
| 15 | ), | 16 | RENDERER_ACCURACY("gpu_accuracy", Settings.Category.Renderer), |
| 16 | USE_DOCKED_MODE( | 17 | RENDERER_RESOLUTION("resolution_setup", Settings.Category.Renderer), |
| 17 | "use_docked_mode", | 18 | RENDERER_VSYNC("use_vsync", Settings.Category.Renderer), |
| 18 | Settings.SECTION_SYSTEM, | 19 | RENDERER_SCALING_FILTER("scaling_filter", Settings.Category.Renderer), |
| 19 | 0 | 20 | RENDERER_ANTI_ALIASING("anti_aliasing", Settings.Category.Renderer), |
| 20 | ), | 21 | RENDERER_SCREEN_LAYOUT("screen_layout", Settings.Category.Android), |
| 21 | RENDERER_USE_DISK_SHADER_CACHE( | 22 | RENDERER_ASPECT_RATIO("aspect_ratio", Settings.Category.Renderer), |
| 22 | "use_disk_shader_cache", | 23 | AUDIO_OUTPUT_ENGINE("output_engine", Settings.Category.Audio); |
| 23 | Settings.SECTION_RENDERER, | 24 | |
| 24 | 1 | 25 | override val int: Int |
| 25 | ), | 26 | get() = NativeConfig.getInt(key, false) |
| 26 | RENDERER_FORCE_MAX_CLOCK( | 27 | |
| 27 | "force_max_clock", | 28 | override fun setInt(value: Int) = NativeConfig.setInt(key, value) |
| 28 | Settings.SECTION_RENDERER, | 29 | |
| 29 | 0 | 30 | override val defaultValue: Int by lazy { NativeConfig.getInt(key, true) } |
| 30 | ), | ||
| 31 | RENDERER_ASYNCHRONOUS_SHADERS( | ||
| 32 | "use_asynchronous_shaders", | ||
| 33 | Settings.SECTION_RENDERER, | ||
| 34 | 0 | ||
| 35 | ), | ||
| 36 | RENDERER_REACTIVE_FLUSHING( | ||
| 37 | "use_reactive_flushing", | ||
| 38 | Settings.SECTION_RENDERER, | ||
| 39 | 0 | ||
| 40 | ), | ||
| 41 | RENDERER_DEBUG( | ||
| 42 | "debug", | ||
| 43 | Settings.SECTION_RENDERER, | ||
| 44 | 0 | ||
| 45 | ), | ||
| 46 | RENDERER_SPEED_LIMIT( | ||
| 47 | "speed_limit", | ||
| 48 | Settings.SECTION_RENDERER, | ||
| 49 | 100 | ||
| 50 | ), | ||
| 51 | CPU_ACCURACY( | ||
| 52 | "cpu_accuracy", | ||
| 53 | Settings.SECTION_CPU, | ||
| 54 | 0 | ||
| 55 | ), | ||
| 56 | REGION_INDEX( | ||
| 57 | "region_index", | ||
| 58 | Settings.SECTION_SYSTEM, | ||
| 59 | -1 | ||
| 60 | ), | ||
| 61 | LANGUAGE_INDEX( | ||
| 62 | "language_index", | ||
| 63 | Settings.SECTION_SYSTEM, | ||
| 64 | 1 | ||
| 65 | ), | ||
| 66 | RENDERER_BACKEND( | ||
| 67 | "backend", | ||
| 68 | Settings.SECTION_RENDERER, | ||
| 69 | 1 | ||
| 70 | ), | ||
| 71 | RENDERER_ACCURACY( | ||
| 72 | "gpu_accuracy", | ||
| 73 | Settings.SECTION_RENDERER, | ||
| 74 | 0 | ||
| 75 | ), | ||
| 76 | RENDERER_RESOLUTION( | ||
| 77 | "resolution_setup", | ||
| 78 | Settings.SECTION_RENDERER, | ||
| 79 | 2 | ||
| 80 | ), | ||
| 81 | RENDERER_VSYNC( | ||
| 82 | "use_vsync", | ||
| 83 | Settings.SECTION_RENDERER, | ||
| 84 | 0 | ||
| 85 | ), | ||
| 86 | RENDERER_SCALING_FILTER( | ||
| 87 | "scaling_filter", | ||
| 88 | Settings.SECTION_RENDERER, | ||
| 89 | 1 | ||
| 90 | ), | ||
| 91 | RENDERER_ANTI_ALIASING( | ||
| 92 | "anti_aliasing", | ||
| 93 | Settings.SECTION_RENDERER, | ||
| 94 | 0 | ||
| 95 | ), | ||
| 96 | RENDERER_SCREEN_LAYOUT( | ||
| 97 | "screen_layout", | ||
| 98 | Settings.SECTION_RENDERER, | ||
| 99 | Settings.LayoutOption_MobileLandscape | ||
| 100 | ), | ||
| 101 | RENDERER_ASPECT_RATIO( | ||
| 102 | "aspect_ratio", | ||
| 103 | Settings.SECTION_RENDERER, | ||
| 104 | 0 | ||
| 105 | ), | ||
| 106 | AUDIO_VOLUME( | ||
| 107 | "volume", | ||
| 108 | Settings.SECTION_AUDIO, | ||
| 109 | 100 | ||
| 110 | ); | ||
| 111 | |||
| 112 | override var int: Int = defaultValue | ||
| 113 | 31 | ||
| 114 | override val valueAsString: String | 32 | override val valueAsString: String |
| 115 | get() = int.toString() | 33 | get() = int.toString() |
| 116 | 34 | ||
| 117 | override val isRuntimeEditable: Boolean | 35 | override fun reset() = NativeConfig.setInt(key, defaultValue) |
| 118 | get() { | ||
| 119 | for (setting in NOT_RUNTIME_EDITABLE) { | ||
| 120 | if (setting == this) { | ||
| 121 | return false | ||
| 122 | } | ||
| 123 | } | ||
| 124 | return true | ||
| 125 | } | ||
| 126 | |||
| 127 | companion object { | ||
| 128 | private val NOT_RUNTIME_EDITABLE = listOf( | ||
| 129 | RENDERER_USE_DISK_SHADER_CACHE, | ||
| 130 | RENDERER_ASYNCHRONOUS_SHADERS, | ||
| 131 | RENDERER_DEBUG, | ||
| 132 | RENDERER_BACKEND, | ||
| 133 | RENDERER_RESOLUTION, | ||
| 134 | RENDERER_VSYNC | ||
| 135 | ) | ||
| 136 | |||
| 137 | fun from(key: String): IntSetting? = IntSetting.values().firstOrNull { it.key == key } | ||
| 138 | |||
| 139 | fun clear() = IntSetting.values().forEach { it.int = it.defaultValue } | ||
| 140 | } | ||
| 141 | } | 36 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/LongSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/LongSetting.kt new file mode 100644 index 000000000..c526fc4cf --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/LongSetting.kt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | ||
| 5 | |||
| 6 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 7 | |||
| 8 | enum class LongSetting( | ||
| 9 | override val key: String, | ||
| 10 | override val category: Settings.Category | ||
| 11 | ) : AbstractLongSetting { | ||
| 12 | CUSTOM_RTC("custom_rtc", Settings.Category.System); | ||
| 13 | |||
| 14 | override val long: Long | ||
| 15 | get() = NativeConfig.getLong(key, false) | ||
| 16 | |||
| 17 | override fun setLong(value: Long) = NativeConfig.setLong(key, value) | ||
| 18 | |||
| 19 | override val defaultValue: Long by lazy { NativeConfig.getLong(key, true) } | ||
| 20 | |||
| 21 | override val valueAsString: String | ||
| 22 | get() = long.toString() | ||
| 23 | |||
| 24 | override fun reset() = NativeConfig.setLong(key, defaultValue) | ||
| 25 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/SettingSection.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/SettingSection.kt deleted file mode 100644 index 474f598a9..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/SettingSection.kt +++ /dev/null | |||
| @@ -1,37 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | ||
| 5 | |||
| 6 | /** | ||
| 7 | * A semantically-related group of Settings objects. These Settings are | ||
| 8 | * internally stored as a HashMap. | ||
| 9 | */ | ||
| 10 | class SettingSection(val name: String) { | ||
| 11 | val settings = HashMap<String, AbstractSetting>() | ||
| 12 | |||
| 13 | /** | ||
| 14 | * Convenience method; inserts a value directly into the backing HashMap. | ||
| 15 | * | ||
| 16 | * @param setting The Setting to be inserted. | ||
| 17 | */ | ||
| 18 | fun putSetting(setting: AbstractSetting) { | ||
| 19 | settings[setting.key!!] = setting | ||
| 20 | } | ||
| 21 | |||
| 22 | /** | ||
| 23 | * Convenience method; gets a value directly from the backing HashMap. | ||
| 24 | * | ||
| 25 | * @param key Used to retrieve the Setting. | ||
| 26 | * @return A Setting object (you should probably cast this before using) | ||
| 27 | */ | ||
| 28 | fun getSetting(key: String): AbstractSetting? { | ||
| 29 | return settings[key] | ||
| 30 | } | ||
| 31 | |||
| 32 | fun mergeSection(settingSection: SettingSection) { | ||
| 33 | for (setting in settingSection.settings.values) { | ||
| 34 | putSetting(setting) | ||
| 35 | } | ||
| 36 | } | ||
| 37 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt index a6251bafd..0702236e8 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/Settings.kt | |||
| @@ -4,195 +4,151 @@ | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | import android.text.TextUtils | 6 | import android.text.TextUtils |
| 7 | import java.util.* | 7 | import android.widget.Toast |
| 8 | import org.yuzu.yuzu_emu.R | 8 | import org.yuzu.yuzu_emu.R |
| 9 | import org.yuzu.yuzu_emu.YuzuApplication | 9 | import org.yuzu.yuzu_emu.YuzuApplication |
| 10 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivityView | ||
| 11 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 10 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
| 12 | 11 | ||
| 13 | class Settings { | 12 | object Settings { |
| 14 | private var gameId: String? = null | 13 | private val context get() = YuzuApplication.appContext |
| 15 | 14 | ||
| 16 | var isLoaded = false | 15 | fun saveSettings(gameId: String = "") { |
| 17 | |||
| 18 | /** | ||
| 19 | * A HashMap<String></String>, SettingSection> that constructs a new SettingSection instead of returning null | ||
| 20 | * when getting a key not already in the map | ||
| 21 | */ | ||
| 22 | class SettingsSectionMap : HashMap<String, SettingSection?>() { | ||
| 23 | override operator fun get(key: String): SettingSection? { | ||
| 24 | if (!super.containsKey(key)) { | ||
| 25 | val section = SettingSection(key) | ||
| 26 | super.put(key, section) | ||
| 27 | return section | ||
| 28 | } | ||
| 29 | return super.get(key) | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | var sections: HashMap<String, SettingSection?> = SettingsSectionMap() | ||
| 34 | |||
| 35 | fun getSection(sectionName: String): SettingSection? { | ||
| 36 | return sections[sectionName] | ||
| 37 | } | ||
| 38 | |||
| 39 | val isEmpty: Boolean | ||
| 40 | get() = sections.isEmpty() | ||
| 41 | |||
| 42 | fun loadSettings(view: SettingsActivityView? = null) { | ||
| 43 | sections = SettingsSectionMap() | ||
| 44 | loadYuzuSettings(view) | ||
| 45 | if (!TextUtils.isEmpty(gameId)) { | ||
| 46 | loadCustomGameSettings(gameId!!, view) | ||
| 47 | } | ||
| 48 | isLoaded = true | ||
| 49 | } | ||
| 50 | |||
| 51 | private fun loadYuzuSettings(view: SettingsActivityView?) { | ||
| 52 | for ((fileName) in configFileSectionsMap) { | ||
| 53 | sections.putAll(SettingsFile.readFile(fileName, view)) | ||
| 54 | } | ||
| 55 | } | ||
| 56 | |||
| 57 | private fun loadCustomGameSettings(gameId: String, view: SettingsActivityView?) { | ||
| 58 | // Custom game settings | ||
| 59 | mergeSections(SettingsFile.readCustomGameSettings(gameId, view)) | ||
| 60 | } | ||
| 61 | |||
| 62 | private fun mergeSections(updatedSections: HashMap<String, SettingSection?>) { | ||
| 63 | for ((key, updatedSection) in updatedSections) { | ||
| 64 | if (sections.containsKey(key)) { | ||
| 65 | val originalSection = sections[key] | ||
| 66 | originalSection!!.mergeSection(updatedSection!!) | ||
| 67 | } else { | ||
| 68 | sections[key] = updatedSection | ||
| 69 | } | ||
| 70 | } | ||
| 71 | } | ||
| 72 | |||
| 73 | fun loadSettings(gameId: String, view: SettingsActivityView) { | ||
| 74 | this.gameId = gameId | ||
| 75 | loadSettings(view) | ||
| 76 | } | ||
| 77 | |||
| 78 | fun saveSettings(view: SettingsActivityView) { | ||
| 79 | if (TextUtils.isEmpty(gameId)) { | 16 | if (TextUtils.isEmpty(gameId)) { |
| 80 | view.showToastMessage( | 17 | Toast.makeText( |
| 81 | YuzuApplication.appContext.getString(R.string.ini_saved), | 18 | context, |
| 82 | false | 19 | context.getString(R.string.ini_saved), |
| 83 | ) | 20 | Toast.LENGTH_SHORT |
| 84 | 21 | ).show() | |
| 85 | for ((fileName, sectionNames) in configFileSectionsMap) { | 22 | SettingsFile.saveFile(SettingsFile.FILE_NAME_CONFIG) |
| 86 | val iniSections = TreeMap<String, SettingSection>() | ||
| 87 | for (section in sectionNames) { | ||
| 88 | iniSections[section] = sections[section]!! | ||
| 89 | } | ||
| 90 | |||
| 91 | SettingsFile.saveFile(fileName, iniSections, view) | ||
| 92 | } | ||
| 93 | } else { | 23 | } else { |
| 94 | // Custom game settings | 24 | // TODO: Save custom game settings |
| 95 | view.showToastMessage( | 25 | Toast.makeText( |
| 96 | YuzuApplication.appContext.getString(R.string.gameid_saved, gameId), | 26 | context, |
| 97 | false | 27 | context.getString(R.string.gameid_saved, gameId), |
| 98 | ) | 28 | Toast.LENGTH_SHORT |
| 99 | 29 | ).show() | |
| 100 | SettingsFile.saveCustomGameSettings(gameId, sections) | ||
| 101 | } | 30 | } |
| 102 | } | 31 | } |
| 103 | 32 | ||
| 104 | companion object { | 33 | enum class Category { |
| 105 | const val SECTION_GENERAL = "General" | 34 | Android, |
| 106 | const val SECTION_SYSTEM = "System" | 35 | Audio, |
| 107 | const val SECTION_RENDERER = "Renderer" | 36 | Core, |
| 108 | const val SECTION_AUDIO = "Audio" | 37 | Cpu, |
| 109 | const val SECTION_CPU = "Cpu" | 38 | CpuDebug, |
| 110 | const val SECTION_THEME = "Theme" | 39 | CpuUnsafe, |
| 111 | const val SECTION_DEBUG = "Debug" | 40 | Renderer, |
| 112 | 41 | RendererAdvanced, | |
| 113 | const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown" | 42 | RendererDebug, |
| 114 | 43 | System, | |
| 115 | const val PREF_OVERLAY_VERSION = "OverlayVersion" | 44 | SystemAudio, |
| 116 | const val PREF_LANDSCAPE_OVERLAY_VERSION = "LandscapeOverlayVersion" | 45 | DataStorage, |
| 117 | const val PREF_PORTRAIT_OVERLAY_VERSION = "PortraitOverlayVersion" | 46 | Debugging, |
| 118 | const val PREF_FOLDABLE_OVERLAY_VERSION = "FoldableOverlayVersion" | 47 | DebuggingGraphics, |
| 119 | val overlayLayoutPrefs = listOf( | 48 | Miscellaneous, |
| 120 | PREF_LANDSCAPE_OVERLAY_VERSION, | 49 | Network, |
| 121 | PREF_PORTRAIT_OVERLAY_VERSION, | 50 | WebService, |
| 122 | PREF_FOLDABLE_OVERLAY_VERSION | 51 | AddOns, |
| 123 | ) | 52 | Controls, |
| 124 | 53 | Ui, | |
| 125 | const val PREF_CONTROL_SCALE = "controlScale" | 54 | UiGeneral, |
| 126 | const val PREF_CONTROL_OPACITY = "controlOpacity" | 55 | UiLayout, |
| 127 | const val PREF_TOUCH_ENABLED = "isTouchEnabled" | 56 | UiGameList, |
| 128 | const val PREF_BUTTON_A = "buttonToggle0" | 57 | Screenshots, |
| 129 | const val PREF_BUTTON_B = "buttonToggle1" | 58 | Shortcuts, |
| 130 | const val PREF_BUTTON_X = "buttonToggle2" | 59 | Multiplayer, |
| 131 | const val PREF_BUTTON_Y = "buttonToggle3" | 60 | Services, |
| 132 | const val PREF_BUTTON_L = "buttonToggle4" | 61 | Paths, |
| 133 | const val PREF_BUTTON_R = "buttonToggle5" | 62 | MaxEnum |
| 134 | const val PREF_BUTTON_ZL = "buttonToggle6" | ||
| 135 | const val PREF_BUTTON_ZR = "buttonToggle7" | ||
| 136 | const val PREF_BUTTON_PLUS = "buttonToggle8" | ||
| 137 | const val PREF_BUTTON_MINUS = "buttonToggle9" | ||
| 138 | const val PREF_BUTTON_DPAD = "buttonToggle10" | ||
| 139 | const val PREF_STICK_L = "buttonToggle11" | ||
| 140 | const val PREF_STICK_R = "buttonToggle12" | ||
| 141 | const val PREF_BUTTON_STICK_L = "buttonToggle13" | ||
| 142 | const val PREF_BUTTON_STICK_R = "buttonToggle14" | ||
| 143 | const val PREF_BUTTON_HOME = "buttonToggle15" | ||
| 144 | const val PREF_BUTTON_SCREENSHOT = "buttonToggle16" | ||
| 145 | |||
| 146 | const val PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER = "EmulationMenuSettings_JoystickRelCenter" | ||
| 147 | const val PREF_MENU_SETTINGS_DPAD_SLIDE = "EmulationMenuSettings_DpadSlideEnable" | ||
| 148 | const val PREF_MENU_SETTINGS_HAPTICS = "EmulationMenuSettings_Haptics" | ||
| 149 | const val PREF_MENU_SETTINGS_SHOW_FPS = "EmulationMenuSettings_ShowFps" | ||
| 150 | const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay" | ||
| 151 | |||
| 152 | const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" | ||
| 153 | const val PREF_THEME = "Theme" | ||
| 154 | const val PREF_THEME_MODE = "ThemeMode" | ||
| 155 | const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds" | ||
| 156 | |||
| 157 | private val configFileSectionsMap: MutableMap<String, List<String>> = HashMap() | ||
| 158 | |||
| 159 | val overlayPreferences = listOf( | ||
| 160 | PREF_OVERLAY_VERSION, | ||
| 161 | PREF_CONTROL_SCALE, | ||
| 162 | PREF_CONTROL_OPACITY, | ||
| 163 | PREF_TOUCH_ENABLED, | ||
| 164 | PREF_BUTTON_A, | ||
| 165 | PREF_BUTTON_B, | ||
| 166 | PREF_BUTTON_X, | ||
| 167 | PREF_BUTTON_Y, | ||
| 168 | PREF_BUTTON_L, | ||
| 169 | PREF_BUTTON_R, | ||
| 170 | PREF_BUTTON_ZL, | ||
| 171 | PREF_BUTTON_ZR, | ||
| 172 | PREF_BUTTON_PLUS, | ||
| 173 | PREF_BUTTON_MINUS, | ||
| 174 | PREF_BUTTON_DPAD, | ||
| 175 | PREF_STICK_L, | ||
| 176 | PREF_STICK_R, | ||
| 177 | PREF_BUTTON_HOME, | ||
| 178 | PREF_BUTTON_SCREENSHOT, | ||
| 179 | PREF_BUTTON_STICK_L, | ||
| 180 | PREF_BUTTON_STICK_R | ||
| 181 | ) | ||
| 182 | |||
| 183 | const val LayoutOption_Unspecified = 0 | ||
| 184 | const val LayoutOption_MobilePortrait = 4 | ||
| 185 | const val LayoutOption_MobileLandscape = 5 | ||
| 186 | |||
| 187 | init { | ||
| 188 | configFileSectionsMap[SettingsFile.FILE_NAME_CONFIG] = | ||
| 189 | listOf( | ||
| 190 | SECTION_GENERAL, | ||
| 191 | SECTION_SYSTEM, | ||
| 192 | SECTION_RENDERER, | ||
| 193 | SECTION_AUDIO, | ||
| 194 | SECTION_CPU | ||
| 195 | ) | ||
| 196 | } | ||
| 197 | } | 63 | } |
| 64 | |||
| 65 | val settingsList = listOf<AbstractSetting>( | ||
| 66 | *BooleanSetting.values(), | ||
| 67 | *ByteSetting.values(), | ||
| 68 | *ShortSetting.values(), | ||
| 69 | *IntSetting.values(), | ||
| 70 | *FloatSetting.values(), | ||
| 71 | *LongSetting.values(), | ||
| 72 | *StringSetting.values() | ||
| 73 | ) | ||
| 74 | |||
| 75 | const val SECTION_GENERAL = "General" | ||
| 76 | const val SECTION_SYSTEM = "System" | ||
| 77 | const val SECTION_RENDERER = "Renderer" | ||
| 78 | const val SECTION_AUDIO = "Audio" | ||
| 79 | const val SECTION_CPU = "Cpu" | ||
| 80 | const val SECTION_THEME = "Theme" | ||
| 81 | const val SECTION_DEBUG = "Debug" | ||
| 82 | |||
| 83 | const val PREF_MEMORY_WARNING_SHOWN = "MemoryWarningShown" | ||
| 84 | |||
| 85 | const val PREF_OVERLAY_VERSION = "OverlayVersion" | ||
| 86 | const val PREF_LANDSCAPE_OVERLAY_VERSION = "LandscapeOverlayVersion" | ||
| 87 | const val PREF_PORTRAIT_OVERLAY_VERSION = "PortraitOverlayVersion" | ||
| 88 | const val PREF_FOLDABLE_OVERLAY_VERSION = "FoldableOverlayVersion" | ||
| 89 | val overlayLayoutPrefs = listOf( | ||
| 90 | PREF_LANDSCAPE_OVERLAY_VERSION, | ||
| 91 | PREF_PORTRAIT_OVERLAY_VERSION, | ||
| 92 | PREF_FOLDABLE_OVERLAY_VERSION | ||
| 93 | ) | ||
| 94 | |||
| 95 | const val PREF_CONTROL_SCALE = "controlScale" | ||
| 96 | const val PREF_CONTROL_OPACITY = "controlOpacity" | ||
| 97 | const val PREF_TOUCH_ENABLED = "isTouchEnabled" | ||
| 98 | const val PREF_BUTTON_A = "buttonToggle0" | ||
| 99 | const val PREF_BUTTON_B = "buttonToggle1" | ||
| 100 | const val PREF_BUTTON_X = "buttonToggle2" | ||
| 101 | const val PREF_BUTTON_Y = "buttonToggle3" | ||
| 102 | const val PREF_BUTTON_L = "buttonToggle4" | ||
| 103 | const val PREF_BUTTON_R = "buttonToggle5" | ||
| 104 | const val PREF_BUTTON_ZL = "buttonToggle6" | ||
| 105 | const val PREF_BUTTON_ZR = "buttonToggle7" | ||
| 106 | const val PREF_BUTTON_PLUS = "buttonToggle8" | ||
| 107 | const val PREF_BUTTON_MINUS = "buttonToggle9" | ||
| 108 | const val PREF_BUTTON_DPAD = "buttonToggle10" | ||
| 109 | const val PREF_STICK_L = "buttonToggle11" | ||
| 110 | const val PREF_STICK_R = "buttonToggle12" | ||
| 111 | const val PREF_BUTTON_STICK_L = "buttonToggle13" | ||
| 112 | const val PREF_BUTTON_STICK_R = "buttonToggle14" | ||
| 113 | const val PREF_BUTTON_HOME = "buttonToggle15" | ||
| 114 | const val PREF_BUTTON_SCREENSHOT = "buttonToggle16" | ||
| 115 | |||
| 116 | const val PREF_MENU_SETTINGS_JOYSTICK_REL_CENTER = "EmulationMenuSettings_JoystickRelCenter" | ||
| 117 | const val PREF_MENU_SETTINGS_DPAD_SLIDE = "EmulationMenuSettings_DpadSlideEnable" | ||
| 118 | const val PREF_MENU_SETTINGS_HAPTICS = "EmulationMenuSettings_Haptics" | ||
| 119 | const val PREF_MENU_SETTINGS_SHOW_FPS = "EmulationMenuSettings_ShowFps" | ||
| 120 | const val PREF_MENU_SETTINGS_SHOW_OVERLAY = "EmulationMenuSettings_ShowOverlay" | ||
| 121 | |||
| 122 | const val PREF_FIRST_APP_LAUNCH = "FirstApplicationLaunch" | ||
| 123 | const val PREF_THEME = "Theme" | ||
| 124 | const val PREF_THEME_MODE = "ThemeMode" | ||
| 125 | const val PREF_BLACK_BACKGROUNDS = "BlackBackgrounds" | ||
| 126 | |||
| 127 | val overlayPreferences = listOf( | ||
| 128 | PREF_OVERLAY_VERSION, | ||
| 129 | PREF_CONTROL_SCALE, | ||
| 130 | PREF_CONTROL_OPACITY, | ||
| 131 | PREF_TOUCH_ENABLED, | ||
| 132 | PREF_BUTTON_A, | ||
| 133 | PREF_BUTTON_B, | ||
| 134 | PREF_BUTTON_X, | ||
| 135 | PREF_BUTTON_Y, | ||
| 136 | PREF_BUTTON_L, | ||
| 137 | PREF_BUTTON_R, | ||
| 138 | PREF_BUTTON_ZL, | ||
| 139 | PREF_BUTTON_ZR, | ||
| 140 | PREF_BUTTON_PLUS, | ||
| 141 | PREF_BUTTON_MINUS, | ||
| 142 | PREF_BUTTON_DPAD, | ||
| 143 | PREF_STICK_L, | ||
| 144 | PREF_STICK_R, | ||
| 145 | PREF_BUTTON_HOME, | ||
| 146 | PREF_BUTTON_SCREENSHOT, | ||
| 147 | PREF_BUTTON_STICK_L, | ||
| 148 | PREF_BUTTON_STICK_R | ||
| 149 | ) | ||
| 150 | |||
| 151 | const val LayoutOption_Unspecified = 0 | ||
| 152 | const val LayoutOption_MobilePortrait = 4 | ||
| 153 | const val LayoutOption_MobileLandscape = 5 | ||
| 198 | } | 154 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt new file mode 100644 index 000000000..c9a0c664c --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/ShortSetting.kt | |||
| @@ -0,0 +1,25 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | ||
| 5 | |||
| 6 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 7 | |||
| 8 | enum class ShortSetting( | ||
| 9 | override val key: String, | ||
| 10 | override val category: Settings.Category | ||
| 11 | ) : AbstractShortSetting { | ||
| 12 | RENDERER_SPEED_LIMIT("speed_limit", Settings.Category.Core); | ||
| 13 | |||
| 14 | override val short: Short | ||
| 15 | get() = NativeConfig.getShort(key, false) | ||
| 16 | |||
| 17 | override fun setShort(value: Short) = NativeConfig.setShort(key, value) | ||
| 18 | |||
| 19 | override val defaultValue: Short by lazy { NativeConfig.getShort(key, true) } | ||
| 20 | |||
| 21 | override val valueAsString: String | ||
| 22 | get() = short.toString() | ||
| 23 | |||
| 24 | override fun reset() = NativeConfig.setShort(key, defaultValue) | ||
| 25 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt index 6621289fd..9bb3e66d4 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/StringSetting.kt | |||
| @@ -3,36 +3,24 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model | 4 | package org.yuzu.yuzu_emu.features.settings.model |
| 5 | 5 | ||
| 6 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 7 | |||
| 6 | enum class StringSetting( | 8 | enum class StringSetting( |
| 7 | override val key: String, | 9 | override val key: String, |
| 8 | override val section: String, | 10 | override val category: Settings.Category |
| 9 | override val defaultValue: String | ||
| 10 | ) : AbstractStringSetting { | 11 | ) : AbstractStringSetting { |
| 11 | AUDIO_OUTPUT_ENGINE("output_engine", Settings.SECTION_AUDIO, "auto"), | 12 | // No string settings currently exist |
| 12 | CUSTOM_RTC("custom_rtc", Settings.SECTION_SYSTEM, "0"); | 13 | EMPTY_SETTING("", Settings.Category.UiGeneral); |
| 14 | |||
| 15 | override val string: String | ||
| 16 | get() = NativeConfig.getString(key, false) | ||
| 17 | |||
| 18 | override fun setString(value: String) = NativeConfig.setString(key, value) | ||
| 13 | 19 | ||
| 14 | override var string: String = defaultValue | 20 | override val defaultValue: String by lazy { NativeConfig.getString(key, true) } |
| 15 | 21 | ||
| 16 | override val valueAsString: String | 22 | override val valueAsString: String |
| 17 | get() = string | 23 | get() = string |
| 18 | 24 | ||
| 19 | override val isRuntimeEditable: Boolean | 25 | override fun reset() = NativeConfig.setString(key, defaultValue) |
| 20 | get() { | ||
| 21 | for (setting in NOT_RUNTIME_EDITABLE) { | ||
| 22 | if (setting == this) { | ||
| 23 | return false | ||
| 24 | } | ||
| 25 | } | ||
| 26 | return true | ||
| 27 | } | ||
| 28 | |||
| 29 | companion object { | ||
| 30 | private val NOT_RUNTIME_EDITABLE = listOf( | ||
| 31 | CUSTOM_RTC | ||
| 32 | ) | ||
| 33 | |||
| 34 | fun from(key: String): StringSetting? = StringSetting.values().firstOrNull { it.key == key } | ||
| 35 | |||
| 36 | fun clear() = StringSetting.values().forEach { it.string = it.defaultValue } | ||
| 37 | } | ||
| 38 | } | 26 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt index bc0bf7788..7c858916e 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/DateTimeSetting.kt | |||
| @@ -3,29 +3,29 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | 4 | package org.yuzu.yuzu_emu.features.settings.model.view |
| 5 | 5 | ||
| 6 | import org.yuzu.yuzu_emu.features.settings.model.AbstractLongSetting | ||
| 6 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting | 7 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting |
| 7 | import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting | ||
| 8 | 8 | ||
| 9 | class DateTimeSetting( | 9 | class DateTimeSetting( |
| 10 | setting: AbstractSetting?, | 10 | setting: AbstractSetting?, |
| 11 | titleId: Int, | 11 | titleId: Int, |
| 12 | descriptionId: Int, | 12 | descriptionId: Int, |
| 13 | val key: String? = null, | 13 | val key: String? = null, |
| 14 | private val defaultValue: String? = null | 14 | private val defaultValue: Long? = null |
| 15 | ) : SettingsItem(setting, titleId, descriptionId) { | 15 | ) : SettingsItem(setting, titleId, descriptionId) { |
| 16 | override val type = TYPE_DATETIME_SETTING | 16 | override val type = TYPE_DATETIME_SETTING |
| 17 | 17 | ||
| 18 | val value: String | 18 | val value: Long |
| 19 | get() = if (setting != null) { | 19 | get() = if (setting != null) { |
| 20 | val setting = setting as AbstractStringSetting | 20 | val setting = setting as AbstractLongSetting |
| 21 | setting.string | 21 | setting.long |
| 22 | } else { | 22 | } else { |
| 23 | defaultValue!! | 23 | defaultValue!! |
| 24 | } | 24 | } |
| 25 | 25 | ||
| 26 | fun setSelectedValue(datetime: String): AbstractStringSetting { | 26 | fun setSelectedValue(datetime: Long): AbstractLongSetting { |
| 27 | val stringSetting = setting as AbstractStringSetting | 27 | val longSetting = setting as AbstractLongSetting |
| 28 | stringSetting.string = datetime | 28 | longSetting.setLong(datetime) |
| 29 | return stringSetting | 29 | return longSetting |
| 30 | } | 30 | } |
| 31 | } | 31 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt index 07520849e..a6cba977c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SettingsItem.kt | |||
| @@ -23,7 +23,7 @@ abstract class SettingsItem( | |||
| 23 | val isEditable: Boolean | 23 | val isEditable: Boolean |
| 24 | get() { | 24 | get() { |
| 25 | if (!NativeLibrary.isRunning()) return true | 25 | if (!NativeLibrary.isRunning()) return true |
| 26 | return setting?.isRuntimeEditable ?: false | 26 | return setting?.isRuntimeModifiable ?: false |
| 27 | } | 27 | } |
| 28 | 28 | ||
| 29 | companion object { | 29 | companion object { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt index 7306ec458..b6a8c4612 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SingleChoiceSetting.kt | |||
| @@ -33,7 +33,7 @@ class SingleChoiceSetting( | |||
| 33 | */ | 33 | */ |
| 34 | fun setSelectedValue(selection: Int): AbstractIntSetting { | 34 | fun setSelectedValue(selection: Int): AbstractIntSetting { |
| 35 | val intSetting = setting as AbstractIntSetting | 35 | val intSetting = setting as AbstractIntSetting |
| 36 | intSetting.int = selection | 36 | intSetting.setInt(selection) |
| 37 | return intSetting | 37 | return intSetting |
| 38 | } | 38 | } |
| 39 | } | 39 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt index 92d0167ae..e71a29e35 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SliderSetting.kt | |||
| @@ -3,10 +3,12 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.model.view | 4 | package org.yuzu.yuzu_emu.features.settings.model.view |
| 5 | 5 | ||
| 6 | import org.yuzu.yuzu_emu.features.settings.model.AbstractByteSetting | ||
| 6 | import kotlin.math.roundToInt | 7 | import kotlin.math.roundToInt |
| 7 | import org.yuzu.yuzu_emu.features.settings.model.AbstractFloatSetting | 8 | import org.yuzu.yuzu_emu.features.settings.model.AbstractFloatSetting |
| 8 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting | 9 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting |
| 9 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting | 10 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting |
| 11 | import org.yuzu.yuzu_emu.features.settings.model.AbstractShortSetting | ||
| 10 | import org.yuzu.yuzu_emu.utils.Log | 12 | import org.yuzu.yuzu_emu.utils.Log |
| 11 | 13 | ||
| 12 | class SliderSetting( | 14 | class SliderSetting( |
| @@ -17,14 +19,16 @@ class SliderSetting( | |||
| 17 | val max: Int, | 19 | val max: Int, |
| 18 | val units: String, | 20 | val units: String, |
| 19 | val key: String? = null, | 21 | val key: String? = null, |
| 20 | val defaultValue: Int? = null | 22 | val defaultValue: Any? = null |
| 21 | ) : SettingsItem(setting, titleId, descriptionId) { | 23 | ) : SettingsItem(setting, titleId, descriptionId) { |
| 22 | override val type = TYPE_SLIDER | 24 | override val type = TYPE_SLIDER |
| 23 | 25 | ||
| 24 | val selectedValue: Int | 26 | val selectedValue: Any |
| 25 | get() { | 27 | get() { |
| 26 | val setting = setting ?: return defaultValue!! | 28 | val setting = setting ?: return defaultValue!! |
| 27 | return when (setting) { | 29 | return when (setting) { |
| 30 | is AbstractByteSetting -> setting.byte.toInt() | ||
| 31 | is AbstractShortSetting -> setting.short.toInt() | ||
| 28 | is AbstractIntSetting -> setting.int | 32 | is AbstractIntSetting -> setting.int |
| 29 | is AbstractFloatSetting -> setting.float.roundToInt() | 33 | is AbstractFloatSetting -> setting.float.roundToInt() |
| 30 | else -> { | 34 | else -> { |
| @@ -43,7 +47,7 @@ class SliderSetting( | |||
| 43 | */ | 47 | */ |
| 44 | fun setSelectedValue(selection: Int): AbstractIntSetting { | 48 | fun setSelectedValue(selection: Int): AbstractIntSetting { |
| 45 | val intSetting = setting as AbstractIntSetting | 49 | val intSetting = setting as AbstractIntSetting |
| 46 | intSetting.int = selection | 50 | intSetting.setInt(selection) |
| 47 | return intSetting | 51 | return intSetting |
| 48 | } | 52 | } |
| 49 | 53 | ||
| @@ -56,7 +60,19 @@ class SliderSetting( | |||
| 56 | */ | 60 | */ |
| 57 | fun setSelectedValue(selection: Float): AbstractFloatSetting { | 61 | fun setSelectedValue(selection: Float): AbstractFloatSetting { |
| 58 | val floatSetting = setting as AbstractFloatSetting | 62 | val floatSetting = setting as AbstractFloatSetting |
| 59 | floatSetting.float = selection | 63 | floatSetting.setFloat(selection) |
| 60 | return floatSetting | 64 | return floatSetting |
| 61 | } | 65 | } |
| 66 | |||
| 67 | fun setSelectedValue(selection: Short): AbstractShortSetting { | ||
| 68 | val shortSetting = setting as AbstractShortSetting | ||
| 69 | shortSetting.setShort(selection) | ||
| 70 | return shortSetting | ||
| 71 | } | ||
| 72 | |||
| 73 | fun setSelectedValue(selection: Byte): AbstractByteSetting { | ||
| 74 | val byteSetting = setting as AbstractByteSetting | ||
| 75 | byteSetting.setByte(selection) | ||
| 76 | return byteSetting | ||
| 77 | } | ||
| 62 | } | 78 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt index 3b6731dcd..2195641e3 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/StringSingleChoiceSetting.kt | |||
| @@ -53,7 +53,7 @@ class StringSingleChoiceSetting( | |||
| 53 | */ | 53 | */ |
| 54 | fun setSelectedValue(selection: String): AbstractStringSetting { | 54 | fun setSelectedValue(selection: String): AbstractStringSetting { |
| 55 | val stringSetting = setting as AbstractStringSetting | 55 | val stringSetting = setting as AbstractStringSetting |
| 56 | stringSetting.string = selection | 56 | stringSetting.setString(selection) |
| 57 | return stringSetting | 57 | return stringSetting |
| 58 | } | 58 | } |
| 59 | } | 59 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt index 90b198718..4ed8070e5 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/model/view/SwitchSetting.kt | |||
| @@ -49,14 +49,14 @@ class SwitchSetting( | |||
| 49 | // Try integer setting | 49 | // Try integer setting |
| 50 | try { | 50 | try { |
| 51 | val setting = setting as AbstractIntSetting | 51 | val setting = setting as AbstractIntSetting |
| 52 | setting.int = if (checked) 1 else 0 | 52 | setting.setInt(if (checked) 1 else 0) |
| 53 | return setting | 53 | return setting |
| 54 | } catch (_: ClassCastException) { | 54 | } catch (_: ClassCastException) { |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | // Try boolean setting | 57 | // Try boolean setting |
| 58 | val setting = setting as AbstractBooleanSetting | 58 | val setting = setting as AbstractBooleanSetting |
| 59 | setting.boolean = checked | 59 | setting.setBoolean(checked) |
| 60 | return setting | 60 | return setting |
| 61 | } | 61 | } |
| 62 | } | 62 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt index e6fffc832..733a53c8c 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivity.kt | |||
| @@ -21,12 +21,7 @@ import com.google.android.material.color.MaterialColors | |||
| 21 | import java.io.IOException | 21 | import java.io.IOException |
| 22 | import org.yuzu.yuzu_emu.R | 22 | import org.yuzu.yuzu_emu.R |
| 23 | import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding | 23 | import org.yuzu.yuzu_emu.databinding.ActivitySettingsBinding |
| 24 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | ||
| 25 | import org.yuzu.yuzu_emu.features.settings.model.FloatSetting | ||
| 26 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting | ||
| 27 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 24 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 28 | import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel | ||
| 29 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting | ||
| 30 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 25 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
| 31 | import org.yuzu.yuzu_emu.utils.* | 26 | import org.yuzu.yuzu_emu.utils.* |
| 32 | 27 | ||
| @@ -35,10 +30,6 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView { | |||
| 35 | 30 | ||
| 36 | private lateinit var binding: ActivitySettingsBinding | 31 | private lateinit var binding: ActivitySettingsBinding |
| 37 | 32 | ||
| 38 | private val settingsViewModel: SettingsViewModel by viewModels() | ||
| 39 | |||
| 40 | override val settings: Settings get() = settingsViewModel.settings | ||
| 41 | |||
| 42 | override fun onCreate(savedInstanceState: Bundle?) { | 33 | override fun onCreate(savedInstanceState: Bundle?) { |
| 43 | ThemeHelper.setTheme(this) | 34 | ThemeHelper.setTheme(this) |
| 44 | 35 | ||
| @@ -171,14 +162,6 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView { | |||
| 171 | fragment?.loadSettingsList() | 162 | fragment?.loadSettingsList() |
| 172 | } | 163 | } |
| 173 | 164 | ||
| 174 | override fun showToastMessage(message: String, is_long: Boolean) { | ||
| 175 | Toast.makeText( | ||
| 176 | this, | ||
| 177 | message, | ||
| 178 | if (is_long) Toast.LENGTH_LONG else Toast.LENGTH_SHORT | ||
| 179 | ).show() | ||
| 180 | } | ||
| 181 | |||
| 182 | override fun onSettingChanged() { | 165 | override fun onSettingChanged() { |
| 183 | presenter.onSettingChanged() | 166 | presenter.onSettingChanged() |
| 184 | } | 167 | } |
| @@ -187,19 +170,18 @@ class SettingsActivity : AppCompatActivity(), SettingsActivityView { | |||
| 187 | // Prevents saving to a non-existent settings file | 170 | // Prevents saving to a non-existent settings file |
| 188 | presenter.onSettingsReset() | 171 | presenter.onSettingsReset() |
| 189 | 172 | ||
| 190 | // Reset the static memory representation of each setting | ||
| 191 | BooleanSetting.clear() | ||
| 192 | FloatSetting.clear() | ||
| 193 | IntSetting.clear() | ||
| 194 | StringSetting.clear() | ||
| 195 | |||
| 196 | // Delete settings file because the user may have changed values that do not exist in the UI | 173 | // Delete settings file because the user may have changed values that do not exist in the UI |
| 197 | val settingsFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG) | 174 | val settingsFile = SettingsFile.getSettingsFile(SettingsFile.FILE_NAME_CONFIG) |
| 198 | if (!settingsFile.delete()) { | 175 | if (!settingsFile.delete()) { |
| 199 | throw IOException("Failed to delete $settingsFile") | 176 | throw IOException("Failed to delete $settingsFile") |
| 200 | } | 177 | } |
| 178 | Settings.settingsList.forEach { it.reset() } | ||
| 201 | 179 | ||
| 202 | showToastMessage(getString(R.string.settings_reset), true) | 180 | Toast.makeText( |
| 181 | applicationContext, | ||
| 182 | getString(R.string.settings_reset), | ||
| 183 | Toast.LENGTH_LONG | ||
| 184 | ).show() | ||
| 203 | finish() | 185 | finish() |
| 204 | } | 186 | } |
| 205 | 187 | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt index 93e677b21..fdbad32bf 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityPresenter.kt | |||
| @@ -5,7 +5,6 @@ package org.yuzu.yuzu_emu.features.settings.ui | |||
| 5 | 5 | ||
| 6 | import android.content.Context | 6 | import android.content.Context |
| 7 | import android.os.Bundle | 7 | import android.os.Bundle |
| 8 | import android.text.TextUtils | ||
| 9 | import java.io.File | 8 | import java.io.File |
| 10 | import org.yuzu.yuzu_emu.NativeLibrary | 9 | import org.yuzu.yuzu_emu.NativeLibrary |
| 11 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 10 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| @@ -14,8 +13,6 @@ import org.yuzu.yuzu_emu.utils.DirectoryInitialization | |||
| 14 | import org.yuzu.yuzu_emu.utils.Log | 13 | import org.yuzu.yuzu_emu.utils.Log |
| 15 | 14 | ||
| 16 | class SettingsActivityPresenter(private val activityView: SettingsActivityView) { | 15 | class SettingsActivityPresenter(private val activityView: SettingsActivityView) { |
| 17 | val settings: Settings get() = activityView.settings | ||
| 18 | |||
| 19 | private var shouldSave = false | 16 | private var shouldSave = false |
| 20 | private lateinit var menuTag: String | 17 | private lateinit var menuTag: String |
| 21 | private lateinit var gameId: String | 18 | private lateinit var gameId: String |
| @@ -33,13 +30,7 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView) | |||
| 33 | } | 30 | } |
| 34 | 31 | ||
| 35 | private fun loadSettingsUI() { | 32 | private fun loadSettingsUI() { |
| 36 | if (!settings.isLoaded) { | 33 | // TODO: Load custom settings contextually |
| 37 | if (!TextUtils.isEmpty(gameId)) { | ||
| 38 | settings.loadSettings(gameId, activityView) | ||
| 39 | } else { | ||
| 40 | settings.loadSettings(activityView) | ||
| 41 | } | ||
| 42 | } | ||
| 43 | activityView.showSettingsFragment(menuTag, false, gameId) | 34 | activityView.showSettingsFragment(menuTag, false, gameId) |
| 44 | activityView.onSettingsFileLoaded() | 35 | activityView.onSettingsFileLoaded() |
| 45 | } | 36 | } |
| @@ -67,9 +58,9 @@ class SettingsActivityPresenter(private val activityView: SettingsActivityView) | |||
| 67 | fun onStop(finishing: Boolean) { | 58 | fun onStop(finishing: Boolean) { |
| 68 | if (finishing && shouldSave) { | 59 | if (finishing && shouldSave) { |
| 69 | Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...") | 60 | Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...") |
| 70 | settings.saveSettings(activityView) | 61 | Settings.saveSettings() |
| 62 | NativeLibrary.reloadSettings() | ||
| 71 | } | 63 | } |
| 72 | NativeLibrary.reloadSettings() | ||
| 73 | } | 64 | } |
| 74 | 65 | ||
| 75 | fun onSettingChanged() { | 66 | fun onSettingChanged() { |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityView.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityView.kt index c186fc388..07a58b4ea 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityView.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsActivityView.kt | |||
| @@ -3,8 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.ui | 4 | package org.yuzu.yuzu_emu.features.settings.ui |
| 5 | 5 | ||
| 6 | import org.yuzu.yuzu_emu.features.settings.model.Settings | ||
| 7 | |||
| 8 | /** | 6 | /** |
| 9 | * Abstraction for the Activity that manages SettingsFragments. | 7 | * Abstraction for the Activity that manages SettingsFragments. |
| 10 | */ | 8 | */ |
| @@ -18,15 +16,6 @@ interface SettingsActivityView { | |||
| 18 | fun showSettingsFragment(menuTag: String, addToStack: Boolean, gameId: String) | 16 | fun showSettingsFragment(menuTag: String, addToStack: Boolean, gameId: String) |
| 19 | 17 | ||
| 20 | /** | 18 | /** |
| 21 | * Called by a contained Fragment to get access to the Setting HashMap | ||
| 22 | * loaded from disk, so that each Fragment doesn't need to perform its own | ||
| 23 | * read operation. | ||
| 24 | * | ||
| 25 | * @return A HashMap of Settings. | ||
| 26 | */ | ||
| 27 | val settings: Settings | ||
| 28 | |||
| 29 | /** | ||
| 30 | * Called when a load operation completes. | 19 | * Called when a load operation completes. |
| 31 | */ | 20 | */ |
| 32 | fun onSettingsFileLoaded() | 21 | fun onSettingsFileLoaded() |
| @@ -37,14 +26,6 @@ interface SettingsActivityView { | |||
| 37 | fun onSettingsFileNotFound() | 26 | fun onSettingsFileNotFound() |
| 38 | 27 | ||
| 39 | /** | 28 | /** |
| 40 | * Display a popup text message on screen. | ||
| 41 | * | ||
| 42 | * @param message The contents of the onscreen message. | ||
| 43 | * @param is_long Whether this should be a long Toast or short one. | ||
| 44 | */ | ||
| 45 | fun showToastMessage(message: String, is_long: Boolean) | ||
| 46 | |||
| 47 | /** | ||
| 48 | * End the activity. | 29 | * End the activity. |
| 49 | */ | 30 | */ |
| 50 | fun finish() | 31 | fun finish() |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt index 9711e2c51..e2e8d8bec 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt | |||
| @@ -24,12 +24,10 @@ import org.yuzu.yuzu_emu.databinding.DialogSliderBinding | |||
| 24 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding | 24 | import org.yuzu.yuzu_emu.databinding.ListItemSettingBinding |
| 25 | import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding | 25 | import org.yuzu.yuzu_emu.databinding.ListItemSettingSwitchBinding |
| 26 | import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding | 26 | import org.yuzu.yuzu_emu.databinding.ListItemSettingsHeaderBinding |
| 27 | import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting | ||
| 28 | import org.yuzu.yuzu_emu.features.settings.model.AbstractFloatSetting | ||
| 29 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting | ||
| 30 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting | 27 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting |
| 31 | import org.yuzu.yuzu_emu.features.settings.model.AbstractStringSetting | 28 | import org.yuzu.yuzu_emu.features.settings.model.ByteSetting |
| 32 | import org.yuzu.yuzu_emu.features.settings.model.FloatSetting | 29 | import org.yuzu.yuzu_emu.features.settings.model.FloatSetting |
| 30 | import org.yuzu.yuzu_emu.features.settings.model.ShortSetting | ||
| 33 | import org.yuzu.yuzu_emu.features.settings.model.view.* | 31 | import org.yuzu.yuzu_emu.features.settings.model.view.* |
| 34 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.* | 32 | import org.yuzu.yuzu_emu.features.settings.ui.viewholder.* |
| 35 | 33 | ||
| @@ -115,8 +113,7 @@ class SettingsAdapter( | |||
| 115 | } | 113 | } |
| 116 | 114 | ||
| 117 | fun onBooleanClick(item: SwitchSetting, position: Int, checked: Boolean) { | 115 | fun onBooleanClick(item: SwitchSetting, position: Int, checked: Boolean) { |
| 118 | val setting = item.setChecked(checked) | 116 | item.setChecked(checked) |
| 119 | fragmentView.putSetting(setting) | ||
| 120 | fragmentView.onSettingChanged() | 117 | fragmentView.onSettingChanged() |
| 121 | } | 118 | } |
| 122 | 119 | ||
| @@ -150,7 +147,7 @@ class SettingsAdapter( | |||
| 150 | fun onDateTimeClick(item: DateTimeSetting, position: Int) { | 147 | fun onDateTimeClick(item: DateTimeSetting, position: Int) { |
| 151 | clickedItem = item | 148 | clickedItem = item |
| 152 | clickedPosition = position | 149 | clickedPosition = position |
| 153 | val storedTime = java.lang.Long.decode(item.value) * 1000 | 150 | val storedTime = item.value * 1000 |
| 154 | 151 | ||
| 155 | // Helper to extract hour and minute from epoch time | 152 | // Helper to extract hour and minute from epoch time |
| 156 | val calendar: Calendar = Calendar.getInstance() | 153 | val calendar: Calendar = Calendar.getInstance() |
| @@ -183,13 +180,11 @@ class SettingsAdapter( | |||
| 183 | var epochTime: Long = datePicker.selection!! / 1000 | 180 | var epochTime: Long = datePicker.selection!! / 1000 |
| 184 | epochTime += timePicker.hour.toLong() * 60 * 60 | 181 | epochTime += timePicker.hour.toLong() * 60 * 60 |
| 185 | epochTime += timePicker.minute.toLong() * 60 | 182 | epochTime += timePicker.minute.toLong() * 60 |
| 186 | val rtcString = epochTime.toString() | 183 | if (item.value != epochTime) { |
| 187 | if (item.value != rtcString) { | ||
| 188 | fragmentView.onSettingChanged() | 184 | fragmentView.onSettingChanged() |
| 185 | notifyItemChanged(clickedPosition) | ||
| 186 | item.setSelectedValue(epochTime) | ||
| 189 | } | 187 | } |
| 190 | notifyItemChanged(clickedPosition) | ||
| 191 | val setting = item.setSelectedValue(rtcString) | ||
| 192 | fragmentView.putSetting(setting) | ||
| 193 | clickedItem = null | 188 | clickedItem = null |
| 194 | } | 189 | } |
| 195 | datePicker.show( | 190 | datePicker.show( |
| @@ -201,7 +196,7 @@ class SettingsAdapter( | |||
| 201 | fun onSliderClick(item: SliderSetting, position: Int) { | 196 | fun onSliderClick(item: SliderSetting, position: Int) { |
| 202 | clickedItem = item | 197 | clickedItem = item |
| 203 | clickedPosition = position | 198 | clickedPosition = position |
| 204 | sliderProgress = item.selectedValue | 199 | sliderProgress = item.selectedValue as Int |
| 205 | 200 | ||
| 206 | val inflater = LayoutInflater.from(context) | 201 | val inflater = LayoutInflater.from(context) |
| 207 | val sliderBinding = DialogSliderBinding.inflate(inflater) | 202 | val sliderBinding = DialogSliderBinding.inflate(inflater) |
| @@ -249,8 +244,7 @@ class SettingsAdapter( | |||
| 249 | } | 244 | } |
| 250 | 245 | ||
| 251 | // Get the backing Setting, which may be null (if for example it was missing from the file) | 246 | // Get the backing Setting, which may be null (if for example it was missing from the file) |
| 252 | val setting = scSetting.setSelectedValue(value) | 247 | scSetting.setSelectedValue(value) |
| 253 | fragmentView.putSetting(setting) | ||
| 254 | closeDialog() | 248 | closeDialog() |
| 255 | } | 249 | } |
| 256 | 250 | ||
| @@ -258,8 +252,7 @@ class SettingsAdapter( | |||
| 258 | val scSetting = clickedItem as StringSingleChoiceSetting | 252 | val scSetting = clickedItem as StringSingleChoiceSetting |
| 259 | val value = scSetting.getValueAt(which) | 253 | val value = scSetting.getValueAt(which) |
| 260 | if (scSetting.selectedValue != value) fragmentView.onSettingChanged() | 254 | if (scSetting.selectedValue != value) fragmentView.onSettingChanged() |
| 261 | val setting = scSetting.setSelectedValue(value!!) | 255 | scSetting.setSelectedValue(value!!) |
| 262 | fragmentView.putSetting(setting) | ||
| 263 | closeDialog() | 256 | closeDialog() |
| 264 | } | 257 | } |
| 265 | 258 | ||
| @@ -268,13 +261,25 @@ class SettingsAdapter( | |||
| 268 | if (sliderSetting.selectedValue != sliderProgress) { | 261 | if (sliderSetting.selectedValue != sliderProgress) { |
| 269 | fragmentView.onSettingChanged() | 262 | fragmentView.onSettingChanged() |
| 270 | } | 263 | } |
| 271 | if (sliderSetting.setting is FloatSetting) { | 264 | when (sliderSetting.setting) { |
| 272 | val value = sliderProgress.toFloat() | 265 | is ByteSetting -> { |
| 273 | val setting = sliderSetting.setSelectedValue(value) | 266 | val value = sliderProgress.toByte() |
| 274 | fragmentView.putSetting(setting) | 267 | sliderSetting.setSelectedValue(value) |
| 275 | } else { | 268 | } |
| 276 | val setting = sliderSetting.setSelectedValue(sliderProgress) | 269 | |
| 277 | fragmentView.putSetting(setting) | 270 | is ShortSetting -> { |
| 271 | val value = sliderProgress.toShort() | ||
| 272 | sliderSetting.setSelectedValue(value) | ||
| 273 | } | ||
| 274 | |||
| 275 | is FloatSetting -> { | ||
| 276 | val value = sliderProgress.toFloat() | ||
| 277 | sliderSetting.setSelectedValue(value) | ||
| 278 | } | ||
| 279 | |||
| 280 | else -> { | ||
| 281 | sliderSetting.setSelectedValue(sliderProgress) | ||
| 282 | } | ||
| 278 | } | 283 | } |
| 279 | closeDialog() | 284 | closeDialog() |
| 280 | } | 285 | } |
| @@ -286,13 +291,8 @@ class SettingsAdapter( | |||
| 286 | fun onLongClick(setting: AbstractSetting, position: Int): Boolean { | 291 | fun onLongClick(setting: AbstractSetting, position: Int): Boolean { |
| 287 | MaterialAlertDialogBuilder(context) | 292 | MaterialAlertDialogBuilder(context) |
| 288 | .setMessage(R.string.reset_setting_confirmation) | 293 | .setMessage(R.string.reset_setting_confirmation) |
| 289 | .setPositiveButton(android.R.string.ok) { dialog: DialogInterface, which: Int -> | 294 | .setPositiveButton(android.R.string.ok) { _: DialogInterface, _: Int -> |
| 290 | when (setting) { | 295 | setting.reset() |
| 291 | is AbstractBooleanSetting -> setting.boolean = setting.defaultValue as Boolean | ||
| 292 | is AbstractFloatSetting -> setting.float = setting.defaultValue as Float | ||
| 293 | is AbstractIntSetting -> setting.int = setting.defaultValue as Int | ||
| 294 | is AbstractStringSetting -> setting.string = setting.defaultValue as String | ||
| 295 | } | ||
| 296 | notifyItemChanged(position) | 296 | notifyItemChanged(position) |
| 297 | fragmentView.onSettingChanged() | 297 | fragmentView.onSettingChanged() |
| 298 | } | 298 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt index 70a74c4dd..dc1bf6eb1 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragment.kt | |||
| @@ -15,7 +15,6 @@ import androidx.fragment.app.Fragment | |||
| 15 | import androidx.recyclerview.widget.LinearLayoutManager | 15 | import androidx.recyclerview.widget.LinearLayoutManager |
| 16 | import com.google.android.material.divider.MaterialDividerItemDecoration | 16 | import com.google.android.material.divider.MaterialDividerItemDecoration |
| 17 | import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding | 17 | import org.yuzu.yuzu_emu.databinding.FragmentSettingsBinding |
| 18 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting | ||
| 19 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | 18 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem |
| 20 | 19 | ||
| 21 | class SettingsFragment : Fragment(), SettingsFragmentView { | 20 | class SettingsFragment : Fragment(), SettingsFragmentView { |
| @@ -89,14 +88,6 @@ class SettingsFragment : Fragment(), SettingsFragmentView { | |||
| 89 | ) | 88 | ) |
| 90 | } | 89 | } |
| 91 | 90 | ||
| 92 | override fun showToastMessage(message: String?, is_long: Boolean) { | ||
| 93 | activityView!!.showToastMessage(message!!, is_long) | ||
| 94 | } | ||
| 95 | |||
| 96 | override fun putSetting(setting: AbstractSetting) { | ||
| 97 | fragmentPresenter.putSetting(setting) | ||
| 98 | } | ||
| 99 | |||
| 100 | override fun onSettingChanged() { | 91 | override fun onSettingChanged() { |
| 101 | activityView!!.onSettingChanged() | 92 | activityView!!.onSettingChanged() |
| 102 | } | 93 | } |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt index 59c1d9d54..2bab9e542 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentPresenter.kt | |||
| @@ -6,16 +6,18 @@ package org.yuzu.yuzu_emu.features.settings.ui | |||
| 6 | import android.content.SharedPreferences | 6 | import android.content.SharedPreferences |
| 7 | import android.os.Build | 7 | import android.os.Build |
| 8 | import android.text.TextUtils | 8 | import android.text.TextUtils |
| 9 | import android.widget.Toast | ||
| 9 | import androidx.preference.PreferenceManager | 10 | import androidx.preference.PreferenceManager |
| 10 | import org.yuzu.yuzu_emu.R | 11 | import org.yuzu.yuzu_emu.R |
| 11 | import org.yuzu.yuzu_emu.YuzuApplication | 12 | import org.yuzu.yuzu_emu.YuzuApplication |
| 12 | import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting | 13 | import org.yuzu.yuzu_emu.features.settings.model.AbstractBooleanSetting |
| 13 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting | 14 | import org.yuzu.yuzu_emu.features.settings.model.AbstractIntSetting |
| 14 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting | ||
| 15 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting | 15 | import org.yuzu.yuzu_emu.features.settings.model.BooleanSetting |
| 16 | import org.yuzu.yuzu_emu.features.settings.model.ByteSetting | ||
| 16 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting | 17 | import org.yuzu.yuzu_emu.features.settings.model.IntSetting |
| 18 | import org.yuzu.yuzu_emu.features.settings.model.LongSetting | ||
| 17 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 19 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 18 | import org.yuzu.yuzu_emu.features.settings.model.StringSetting | 20 | import org.yuzu.yuzu_emu.features.settings.model.ShortSetting |
| 19 | import org.yuzu.yuzu_emu.features.settings.model.view.* | 21 | import org.yuzu.yuzu_emu.features.settings.model.view.* |
| 20 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 22 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
| 21 | import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment | 23 | import org.yuzu.yuzu_emu.fragments.ResetSettingsDialogFragment |
| @@ -27,7 +29,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 27 | private var settingsList: ArrayList<SettingsItem>? = null | 29 | private var settingsList: ArrayList<SettingsItem>? = null |
| 28 | 30 | ||
| 29 | private val settingsActivity get() = fragmentView.activityView as SettingsActivity | 31 | private val settingsActivity get() = fragmentView.activityView as SettingsActivity |
| 30 | private val settings get() = fragmentView.activityView!!.settings | ||
| 31 | 32 | ||
| 32 | private lateinit var preferences: SharedPreferences | 33 | private lateinit var preferences: SharedPreferences |
| 33 | 34 | ||
| @@ -41,17 +42,6 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 41 | loadSettingsList() | 42 | loadSettingsList() |
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | fun putSetting(setting: AbstractSetting) { | ||
| 45 | if (setting.section == null || setting.key == null) { | ||
| 46 | return | ||
| 47 | } | ||
| 48 | |||
| 49 | val section = settings.getSection(setting.section!!)!! | ||
| 50 | if (section.getSetting(setting.key!!) == null) { | ||
| 51 | section.putSetting(setting) | ||
| 52 | } | ||
| 53 | } | ||
| 54 | |||
| 55 | fun loadSettingsList() { | 45 | fun loadSettingsList() { |
| 56 | if (!TextUtils.isEmpty(gameId)) { | 46 | if (!TextUtils.isEmpty(gameId)) { |
| 57 | settingsActivity.setToolbarTitle("Game Settings: $gameId") | 47 | settingsActivity.setToolbarTitle("Game Settings: $gameId") |
| @@ -69,7 +59,12 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 69 | Settings.SECTION_THEME -> addThemeSettings(sl) | 59 | Settings.SECTION_THEME -> addThemeSettings(sl) |
| 70 | Settings.SECTION_DEBUG -> addDebugSettings(sl) | 60 | Settings.SECTION_DEBUG -> addDebugSettings(sl) |
| 71 | else -> { | 61 | else -> { |
| 72 | fragmentView.showToastMessage("Unimplemented menu", false) | 62 | val context = YuzuApplication.appContext |
| 63 | Toast.makeText( | ||
| 64 | context, | ||
| 65 | context.getString(R.string.unimplemented_menu), | ||
| 66 | Toast.LENGTH_SHORT | ||
| 67 | ).show() | ||
| 73 | return | 68 | return |
| 74 | } | 69 | } |
| 75 | } | 70 | } |
| @@ -135,23 +130,23 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 135 | sl.apply { | 130 | sl.apply { |
| 136 | add( | 131 | add( |
| 137 | SwitchSetting( | 132 | SwitchSetting( |
| 138 | IntSetting.RENDERER_USE_SPEED_LIMIT, | 133 | BooleanSetting.RENDERER_USE_SPEED_LIMIT, |
| 139 | R.string.frame_limit_enable, | 134 | R.string.frame_limit_enable, |
| 140 | R.string.frame_limit_enable_description, | 135 | R.string.frame_limit_enable_description, |
| 141 | IntSetting.RENDERER_USE_SPEED_LIMIT.key, | 136 | BooleanSetting.RENDERER_USE_SPEED_LIMIT.key, |
| 142 | IntSetting.RENDERER_USE_SPEED_LIMIT.defaultValue | 137 | BooleanSetting.RENDERER_USE_SPEED_LIMIT.defaultValue |
| 143 | ) | 138 | ) |
| 144 | ) | 139 | ) |
| 145 | add( | 140 | add( |
| 146 | SliderSetting( | 141 | SliderSetting( |
| 147 | IntSetting.RENDERER_SPEED_LIMIT, | 142 | ShortSetting.RENDERER_SPEED_LIMIT, |
| 148 | R.string.frame_limit_slider, | 143 | R.string.frame_limit_slider, |
| 149 | R.string.frame_limit_slider_description, | 144 | R.string.frame_limit_slider_description, |
| 150 | 1, | 145 | 1, |
| 151 | 200, | 146 | 200, |
| 152 | "%", | 147 | "%", |
| 153 | IntSetting.RENDERER_SPEED_LIMIT.key, | 148 | ShortSetting.RENDERER_SPEED_LIMIT.key, |
| 154 | IntSetting.RENDERER_SPEED_LIMIT.defaultValue | 149 | ShortSetting.RENDERER_SPEED_LIMIT.defaultValue |
| 155 | ) | 150 | ) |
| 156 | ) | 151 | ) |
| 157 | add( | 152 | add( |
| @@ -182,11 +177,11 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 182 | sl.apply { | 177 | sl.apply { |
| 183 | add( | 178 | add( |
| 184 | SwitchSetting( | 179 | SwitchSetting( |
| 185 | IntSetting.USE_DOCKED_MODE, | 180 | BooleanSetting.USE_DOCKED_MODE, |
| 186 | R.string.use_docked_mode, | 181 | R.string.use_docked_mode, |
| 187 | R.string.use_docked_mode_description, | 182 | R.string.use_docked_mode_description, |
| 188 | IntSetting.USE_DOCKED_MODE.key, | 183 | BooleanSetting.USE_DOCKED_MODE.key, |
| 189 | IntSetting.USE_DOCKED_MODE.defaultValue | 184 | BooleanSetting.USE_DOCKED_MODE.defaultValue |
| 190 | ) | 185 | ) |
| 191 | ) | 186 | ) |
| 192 | add( | 187 | add( |
| @@ -222,11 +217,11 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 222 | ) | 217 | ) |
| 223 | add( | 218 | add( |
| 224 | DateTimeSetting( | 219 | DateTimeSetting( |
| 225 | StringSetting.CUSTOM_RTC, | 220 | LongSetting.CUSTOM_RTC, |
| 226 | R.string.set_custom_rtc, | 221 | R.string.set_custom_rtc, |
| 227 | 0, | 222 | 0, |
| 228 | StringSetting.CUSTOM_RTC.key, | 223 | LongSetting.CUSTOM_RTC.key, |
| 229 | StringSetting.CUSTOM_RTC.defaultValue | 224 | LongSetting.CUSTOM_RTC.defaultValue |
| 230 | ) | 225 | ) |
| 231 | ) | 226 | ) |
| 232 | } | 227 | } |
| @@ -314,38 +309,38 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 314 | ) | 309 | ) |
| 315 | add( | 310 | add( |
| 316 | SwitchSetting( | 311 | SwitchSetting( |
| 317 | IntSetting.RENDERER_USE_DISK_SHADER_CACHE, | 312 | BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE, |
| 318 | R.string.use_disk_shader_cache, | 313 | R.string.use_disk_shader_cache, |
| 319 | R.string.use_disk_shader_cache_description, | 314 | R.string.use_disk_shader_cache_description, |
| 320 | IntSetting.RENDERER_USE_DISK_SHADER_CACHE.key, | 315 | BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.key, |
| 321 | IntSetting.RENDERER_USE_DISK_SHADER_CACHE.defaultValue | 316 | BooleanSetting.RENDERER_USE_DISK_SHADER_CACHE.defaultValue |
| 322 | ) | 317 | ) |
| 323 | ) | 318 | ) |
| 324 | add( | 319 | add( |
| 325 | SwitchSetting( | 320 | SwitchSetting( |
| 326 | IntSetting.RENDERER_FORCE_MAX_CLOCK, | 321 | BooleanSetting.RENDERER_FORCE_MAX_CLOCK, |
| 327 | R.string.renderer_force_max_clock, | 322 | R.string.renderer_force_max_clock, |
| 328 | R.string.renderer_force_max_clock_description, | 323 | R.string.renderer_force_max_clock_description, |
| 329 | IntSetting.RENDERER_FORCE_MAX_CLOCK.key, | 324 | BooleanSetting.RENDERER_FORCE_MAX_CLOCK.key, |
| 330 | IntSetting.RENDERER_FORCE_MAX_CLOCK.defaultValue | 325 | BooleanSetting.RENDERER_FORCE_MAX_CLOCK.defaultValue |
| 331 | ) | 326 | ) |
| 332 | ) | 327 | ) |
| 333 | add( | 328 | add( |
| 334 | SwitchSetting( | 329 | SwitchSetting( |
| 335 | IntSetting.RENDERER_ASYNCHRONOUS_SHADERS, | 330 | BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS, |
| 336 | R.string.renderer_asynchronous_shaders, | 331 | R.string.renderer_asynchronous_shaders, |
| 337 | R.string.renderer_asynchronous_shaders_description, | 332 | R.string.renderer_asynchronous_shaders_description, |
| 338 | IntSetting.RENDERER_ASYNCHRONOUS_SHADERS.key, | 333 | BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.key, |
| 339 | IntSetting.RENDERER_ASYNCHRONOUS_SHADERS.defaultValue | 334 | BooleanSetting.RENDERER_ASYNCHRONOUS_SHADERS.defaultValue |
| 340 | ) | 335 | ) |
| 341 | ) | 336 | ) |
| 342 | add( | 337 | add( |
| 343 | SwitchSetting( | 338 | SwitchSetting( |
| 344 | IntSetting.RENDERER_REACTIVE_FLUSHING, | 339 | BooleanSetting.RENDERER_REACTIVE_FLUSHING, |
| 345 | R.string.renderer_reactive_flushing, | 340 | R.string.renderer_reactive_flushing, |
| 346 | R.string.renderer_reactive_flushing_description, | 341 | R.string.renderer_reactive_flushing_description, |
| 347 | IntSetting.RENDERER_REACTIVE_FLUSHING.key, | 342 | BooleanSetting.RENDERER_REACTIVE_FLUSHING.key, |
| 348 | IntSetting.RENDERER_REACTIVE_FLUSHING.defaultValue | 343 | BooleanSetting.RENDERER_REACTIVE_FLUSHING.defaultValue |
| 349 | ) | 344 | ) |
| 350 | ) | 345 | ) |
| 351 | } | 346 | } |
| @@ -355,26 +350,26 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 355 | settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_audio)) | 350 | settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_audio)) |
| 356 | sl.apply { | 351 | sl.apply { |
| 357 | add( | 352 | add( |
| 358 | StringSingleChoiceSetting( | 353 | SingleChoiceSetting( |
| 359 | StringSetting.AUDIO_OUTPUT_ENGINE, | 354 | IntSetting.AUDIO_OUTPUT_ENGINE, |
| 360 | R.string.audio_output_engine, | 355 | R.string.audio_output_engine, |
| 361 | 0, | 356 | 0, |
| 362 | settingsActivity.resources.getStringArray(R.array.outputEngineEntries), | 357 | R.array.outputEngineEntries, |
| 363 | settingsActivity.resources.getStringArray(R.array.outputEngineValues), | 358 | R.array.outputEngineValues, |
| 364 | StringSetting.AUDIO_OUTPUT_ENGINE.key, | 359 | IntSetting.AUDIO_OUTPUT_ENGINE.key, |
| 365 | StringSetting.AUDIO_OUTPUT_ENGINE.defaultValue | 360 | IntSetting.AUDIO_OUTPUT_ENGINE.defaultValue |
| 366 | ) | 361 | ) |
| 367 | ) | 362 | ) |
| 368 | add( | 363 | add( |
| 369 | SliderSetting( | 364 | SliderSetting( |
| 370 | IntSetting.AUDIO_VOLUME, | 365 | ByteSetting.AUDIO_VOLUME, |
| 371 | R.string.audio_volume, | 366 | R.string.audio_volume, |
| 372 | R.string.audio_volume_description, | 367 | R.string.audio_volume_description, |
| 373 | 0, | 368 | 0, |
| 374 | 100, | 369 | 100, |
| 375 | "%", | 370 | "%", |
| 376 | IntSetting.AUDIO_VOLUME.key, | 371 | ByteSetting.AUDIO_VOLUME.key, |
| 377 | IntSetting.AUDIO_VOLUME.defaultValue | 372 | ByteSetting.AUDIO_VOLUME.defaultValue |
| 378 | ) | 373 | ) |
| 379 | ) | 374 | ) |
| 380 | } | 375 | } |
| @@ -384,19 +379,19 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 384 | settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_theme)) | 379 | settingsActivity.setToolbarTitle(settingsActivity.getString(R.string.preferences_theme)) |
| 385 | sl.apply { | 380 | sl.apply { |
| 386 | val theme: AbstractIntSetting = object : AbstractIntSetting { | 381 | val theme: AbstractIntSetting = object : AbstractIntSetting { |
| 387 | override var int: Int | 382 | override val int: Int |
| 388 | get() = preferences.getInt(Settings.PREF_THEME, 0) | 383 | get() = preferences.getInt(Settings.PREF_THEME, 0) |
| 389 | set(value) { | 384 | |
| 390 | preferences.edit() | 385 | override fun setInt(value: Int) { |
| 391 | .putInt(Settings.PREF_THEME, value) | 386 | preferences.edit() |
| 392 | .apply() | 387 | .putInt(Settings.PREF_THEME, value) |
| 393 | settingsActivity.recreate() | 388 | .apply() |
| 394 | } | 389 | settingsActivity.recreate() |
| 390 | } | ||
| 391 | |||
| 395 | override val key: String? = null | 392 | override val key: String? = null |
| 396 | override val section: String? = null | 393 | override val category = Settings.Category.UiGeneral |
| 397 | override val isRuntimeEditable: Boolean = false | 394 | override val isRuntimeModifiable: Boolean = false |
| 398 | override val valueAsString: String | ||
| 399 | get() = preferences.getInt(Settings.PREF_THEME, 0).toString() | ||
| 400 | override val defaultValue: Any = 0 | 395 | override val defaultValue: Any = 0 |
| 401 | } | 396 | } |
| 402 | 397 | ||
| @@ -423,19 +418,19 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 423 | } | 418 | } |
| 424 | 419 | ||
| 425 | val themeMode: AbstractIntSetting = object : AbstractIntSetting { | 420 | val themeMode: AbstractIntSetting = object : AbstractIntSetting { |
| 426 | override var int: Int | 421 | override val int: Int |
| 427 | get() = preferences.getInt(Settings.PREF_THEME_MODE, -1) | 422 | get() = preferences.getInt(Settings.PREF_THEME_MODE, -1) |
| 428 | set(value) { | 423 | |
| 429 | preferences.edit() | 424 | override fun setInt(value: Int) { |
| 430 | .putInt(Settings.PREF_THEME_MODE, value) | 425 | preferences.edit() |
| 431 | .apply() | 426 | .putInt(Settings.PREF_THEME_MODE, value) |
| 432 | ThemeHelper.setThemeMode(settingsActivity) | 427 | .apply() |
| 433 | } | 428 | ThemeHelper.setThemeMode(settingsActivity) |
| 429 | } | ||
| 430 | |||
| 434 | override val key: String? = null | 431 | override val key: String? = null |
| 435 | override val section: String? = null | 432 | override val category = Settings.Category.UiGeneral |
| 436 | override val isRuntimeEditable: Boolean = false | 433 | override val isRuntimeModifiable: Boolean = false |
| 437 | override val valueAsString: String | ||
| 438 | get() = preferences.getInt(Settings.PREF_THEME_MODE, -1).toString() | ||
| 439 | override val defaultValue: Any = -1 | 434 | override val defaultValue: Any = -1 |
| 440 | } | 435 | } |
| 441 | 436 | ||
| @@ -450,20 +445,19 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 450 | ) | 445 | ) |
| 451 | 446 | ||
| 452 | val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting { | 447 | val blackBackgrounds: AbstractBooleanSetting = object : AbstractBooleanSetting { |
| 453 | override var boolean: Boolean | 448 | override val boolean: Boolean |
| 454 | get() = preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) | 449 | get() = preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) |
| 455 | set(value) { | 450 | |
| 456 | preferences.edit() | 451 | override fun setBoolean(value: Boolean) { |
| 457 | .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, value) | 452 | preferences.edit() |
| 458 | .apply() | 453 | .putBoolean(Settings.PREF_BLACK_BACKGROUNDS, value) |
| 459 | settingsActivity.recreate() | 454 | .apply() |
| 460 | } | 455 | settingsActivity.recreate() |
| 456 | } | ||
| 457 | |||
| 461 | override val key: String? = null | 458 | override val key: String? = null |
| 462 | override val section: String? = null | 459 | override val category = Settings.Category.UiGeneral |
| 463 | override val isRuntimeEditable: Boolean = false | 460 | override val isRuntimeModifiable: Boolean = false |
| 464 | override val valueAsString: String | ||
| 465 | get() = preferences.getBoolean(Settings.PREF_BLACK_BACKGROUNDS, false) | ||
| 466 | .toString() | ||
| 467 | override val defaultValue: Any = false | 461 | override val defaultValue: Any = false |
| 468 | } | 462 | } |
| 469 | 463 | ||
| @@ -494,11 +488,11 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 494 | ) | 488 | ) |
| 495 | add( | 489 | add( |
| 496 | SwitchSetting( | 490 | SwitchSetting( |
| 497 | IntSetting.RENDERER_DEBUG, | 491 | BooleanSetting.RENDERER_DEBUG, |
| 498 | R.string.renderer_debug, | 492 | R.string.renderer_debug, |
| 499 | R.string.renderer_debug_description, | 493 | R.string.renderer_debug_description, |
| 500 | IntSetting.RENDERER_DEBUG.key, | 494 | BooleanSetting.RENDERER_DEBUG.key, |
| 501 | IntSetting.RENDERER_DEBUG.defaultValue | 495 | BooleanSetting.RENDERER_DEBUG.defaultValue |
| 502 | ) | 496 | ) |
| 503 | ) | 497 | ) |
| 504 | 498 | ||
| @@ -514,17 +508,18 @@ class SettingsFragmentPresenter(private val fragmentView: SettingsFragmentView) | |||
| 514 | ) | 508 | ) |
| 515 | 509 | ||
| 516 | val fastmem = object : AbstractBooleanSetting { | 510 | val fastmem = object : AbstractBooleanSetting { |
| 517 | override var boolean: Boolean | 511 | override val boolean: Boolean |
| 518 | get() = | 512 | get() = |
| 519 | BooleanSetting.FASTMEM.boolean && BooleanSetting.FASTMEM_EXCLUSIVES.boolean | 513 | BooleanSetting.FASTMEM.boolean && BooleanSetting.FASTMEM_EXCLUSIVES.boolean |
| 520 | set(value) { | 514 | |
| 521 | BooleanSetting.FASTMEM.boolean = value | 515 | override fun setBoolean(value: Boolean) { |
| 522 | BooleanSetting.FASTMEM_EXCLUSIVES.boolean = value | 516 | BooleanSetting.FASTMEM.setBoolean(value) |
| 523 | } | 517 | BooleanSetting.FASTMEM_EXCLUSIVES.setBoolean(value) |
| 518 | } | ||
| 519 | |||
| 524 | override val key: String? = null | 520 | override val key: String? = null |
| 525 | override val section: String = Settings.SECTION_CPU | 521 | override val category = Settings.Category.Cpu |
| 526 | override val isRuntimeEditable: Boolean = false | 522 | override val isRuntimeModifiable: Boolean = false |
| 527 | override val valueAsString: String = "" | ||
| 528 | override val defaultValue: Any = true | 523 | override val defaultValue: Any = true |
| 529 | } | 524 | } |
| 530 | add( | 525 | add( |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentView.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentView.kt index 1ebe35eaa..a4d7a80aa 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentView.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsFragmentView.kt | |||
| @@ -3,7 +3,6 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.ui | 4 | package org.yuzu.yuzu_emu.features.settings.ui |
| 5 | 5 | ||
| 6 | import org.yuzu.yuzu_emu.features.settings.model.AbstractSetting | ||
| 7 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem | 6 | import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem |
| 8 | 7 | ||
| 9 | /** | 8 | /** |
| @@ -37,21 +36,6 @@ interface SettingsFragmentView { | |||
| 37 | fun loadSubMenu(menuKey: String) | 36 | fun loadSubMenu(menuKey: String) |
| 38 | 37 | ||
| 39 | /** | 38 | /** |
| 40 | * Tell the Fragment to tell the containing activity to display a toast message. | ||
| 41 | * | ||
| 42 | * @param message Text to be shown in the Toast | ||
| 43 | * @param is_long Whether this should be a long Toast or short one. | ||
| 44 | */ | ||
| 45 | fun showToastMessage(message: String?, is_long: Boolean) | ||
| 46 | |||
| 47 | /** | ||
| 48 | * Have the fragment add a setting to the HashMap. | ||
| 49 | * | ||
| 50 | * @param setting The (possibly previously missing) new setting. | ||
| 51 | */ | ||
| 52 | fun putSetting(setting: AbstractSetting) | ||
| 53 | |||
| 54 | /** | ||
| 55 | * Have the fragment tell the containing Activity that a setting was modified. | 39 | * Have the fragment tell the containing Activity that a setting was modified. |
| 56 | */ | 40 | */ |
| 57 | fun onSettingChanged() | 41 | fun onSettingChanged() |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt index 79572fc06..eb25ea4fb 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/viewholder/DateTimeViewHolder.kt | |||
| @@ -29,7 +29,7 @@ class DateTimeViewHolder(val binding: ListItemSettingBinding, adapter: SettingsA | |||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | binding.textSettingValue.visibility = View.VISIBLE | 31 | binding.textSettingValue.visibility = View.VISIBLE |
| 32 | val epochTime = setting.value.toLong() | 32 | val epochTime = setting.value |
| 33 | val instant = Instant.ofEpochMilli(epochTime * 1000) | 33 | val instant = Instant.ofEpochMilli(epochTime * 1000) |
| 34 | val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC")) | 34 | val zonedTime = ZonedDateTime.ofInstant(instant, ZoneId.of("UTC")) |
| 35 | val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) | 35 | val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt index 70a52df5d..2b04d666a 100644 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/utils/SettingsFile.kt | |||
| @@ -3,18 +3,15 @@ | |||
| 3 | 3 | ||
| 4 | package org.yuzu.yuzu_emu.features.settings.utils | 4 | package org.yuzu.yuzu_emu.features.settings.utils |
| 5 | 5 | ||
| 6 | import android.widget.Toast | ||
| 6 | import java.io.* | 7 | import java.io.* |
| 7 | import java.util.* | ||
| 8 | import org.ini4j.Wini | 8 | import org.ini4j.Wini |
| 9 | import org.yuzu.yuzu_emu.NativeLibrary | ||
| 10 | import org.yuzu.yuzu_emu.R | 9 | import org.yuzu.yuzu_emu.R |
| 11 | import org.yuzu.yuzu_emu.YuzuApplication | 10 | import org.yuzu.yuzu_emu.YuzuApplication |
| 12 | import org.yuzu.yuzu_emu.features.settings.model.* | 11 | import org.yuzu.yuzu_emu.features.settings.model.* |
| 13 | import org.yuzu.yuzu_emu.features.settings.model.Settings.SettingsSectionMap | ||
| 14 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivityView | ||
| 15 | import org.yuzu.yuzu_emu.utils.BiMap | ||
| 16 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization | 12 | import org.yuzu.yuzu_emu.utils.DirectoryInitialization |
| 17 | import org.yuzu.yuzu_emu.utils.Log | 13 | import org.yuzu.yuzu_emu.utils.Log |
| 14 | import org.yuzu.yuzu_emu.utils.NativeConfig | ||
| 18 | 15 | ||
| 19 | /** | 16 | /** |
| 20 | * Contains static methods for interacting with .ini files in which settings are stored. | 17 | * Contains static methods for interacting with .ini files in which settings are stored. |
| @@ -22,243 +19,41 @@ import org.yuzu.yuzu_emu.utils.Log | |||
| 22 | object SettingsFile { | 19 | object SettingsFile { |
| 23 | const val FILE_NAME_CONFIG = "config" | 20 | const val FILE_NAME_CONFIG = "config" |
| 24 | 21 | ||
| 25 | private var sectionsMap = BiMap<String?, String?>() | ||
| 26 | |||
| 27 | /** | ||
| 28 | * Reads a given .ini file from disk and returns it as a HashMap of Settings, themselves | ||
| 29 | * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it | ||
| 30 | * failed. | ||
| 31 | * | ||
| 32 | * @param ini The ini file to load the settings from | ||
| 33 | * @param isCustomGame | ||
| 34 | * @param view The current view. | ||
| 35 | * @return An Observable that emits a HashMap of the file's contents, then completes. | ||
| 36 | */ | ||
| 37 | private fun readFile( | ||
| 38 | ini: File?, | ||
| 39 | isCustomGame: Boolean, | ||
| 40 | view: SettingsActivityView? = null | ||
| 41 | ): HashMap<String, SettingSection?> { | ||
| 42 | val sections: HashMap<String, SettingSection?> = SettingsSectionMap() | ||
| 43 | var reader: BufferedReader? = null | ||
| 44 | try { | ||
| 45 | reader = BufferedReader(FileReader(ini)) | ||
| 46 | var current: SettingSection? = null | ||
| 47 | var line: String? | ||
| 48 | while (reader.readLine().also { line = it } != null) { | ||
| 49 | if (line!!.startsWith("[") && line!!.endsWith("]")) { | ||
| 50 | current = sectionFromLine(line!!, isCustomGame) | ||
| 51 | sections[current.name] = current | ||
| 52 | } else if (current != null) { | ||
| 53 | val setting = settingFromLine(line!!) | ||
| 54 | if (setting != null) { | ||
| 55 | current.putSetting(setting) | ||
| 56 | } | ||
| 57 | } | ||
| 58 | } | ||
| 59 | } catch (e: FileNotFoundException) { | ||
| 60 | Log.error("[SettingsFile] File not found: " + e.message) | ||
| 61 | view?.onSettingsFileNotFound() | ||
| 62 | } catch (e: IOException) { | ||
| 63 | Log.error("[SettingsFile] Error reading from: " + e.message) | ||
| 64 | view?.onSettingsFileNotFound() | ||
| 65 | } finally { | ||
| 66 | if (reader != null) { | ||
| 67 | try { | ||
| 68 | reader.close() | ||
| 69 | } catch (e: IOException) { | ||
| 70 | Log.error("[SettingsFile] Error closing: " + e.message) | ||
| 71 | } | ||
| 72 | } | ||
| 73 | } | ||
| 74 | return sections | ||
| 75 | } | ||
| 76 | |||
| 77 | fun readFile(fileName: String, view: SettingsActivityView?): HashMap<String, SettingSection?> { | ||
| 78 | return readFile(getSettingsFile(fileName), false, view) | ||
| 79 | } | ||
| 80 | |||
| 81 | fun readFile(fileName: String): HashMap<String, SettingSection?> = | ||
| 82 | readFile(getSettingsFile(fileName), false) | ||
| 83 | |||
| 84 | /** | ||
| 85 | * Reads a given .ini file from disk and returns it as a HashMap of SettingSections, themselves | ||
| 86 | * effectively a HashMap of key/value settings. If unsuccessful, outputs an error telling why it | ||
| 87 | * failed. | ||
| 88 | * | ||
| 89 | * @param gameId the id of the game to load it's settings. | ||
| 90 | * @param view The current view. | ||
| 91 | */ | ||
| 92 | fun readCustomGameSettings( | ||
| 93 | gameId: String, | ||
| 94 | view: SettingsActivityView? | ||
| 95 | ): HashMap<String, SettingSection?> { | ||
| 96 | return readFile(getCustomGameSettingsFile(gameId), true, view) | ||
| 97 | } | ||
| 98 | |||
| 99 | /** | 22 | /** |
| 100 | * Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error | 23 | * Saves a Settings HashMap to a given .ini file on disk. If unsuccessful, outputs an error |
| 101 | * telling why it failed. | 24 | * telling why it failed. |
| 102 | * | 25 | * |
| 103 | * @param fileName The target filename without a path or extension. | 26 | * @param fileName The target filename without a path or extension. |
| 104 | * @param sections The HashMap containing the Settings we want to serialize. | ||
| 105 | * @param view The current view. | ||
| 106 | */ | 27 | */ |
| 107 | fun saveFile( | 28 | fun saveFile(fileName: String) { |
| 108 | fileName: String, | ||
| 109 | sections: TreeMap<String, SettingSection>, | ||
| 110 | view: SettingsActivityView | ||
| 111 | ) { | ||
| 112 | val ini = getSettingsFile(fileName) | 29 | val ini = getSettingsFile(fileName) |
| 113 | try { | 30 | try { |
| 114 | val writer = Wini(ini) | 31 | val wini = Wini(ini) |
| 115 | val keySet: Set<String> = sections.keys | 32 | for (specificCategory in Settings.Category.values()) { |
| 116 | for (key in keySet) { | 33 | val categoryHeader = NativeConfig.getConfigHeader(specificCategory.ordinal) |
| 117 | val section = sections[key] | 34 | for (setting in Settings.settingsList) { |
| 118 | writeSection(writer, section!!) | 35 | if (setting.key!!.isEmpty()) continue |
| 36 | |||
| 37 | val settingCategoryHeader = | ||
| 38 | NativeConfig.getConfigHeader(setting.category.ordinal) | ||
| 39 | val iniSetting: String? = wini.get(categoryHeader, setting.key) | ||
| 40 | if (iniSetting != null || settingCategoryHeader == categoryHeader) { | ||
| 41 | wini.put(settingCategoryHeader, setting.key, setting.valueAsString) | ||
| 42 | } | ||
| 43 | } | ||
| 119 | } | 44 | } |
| 120 | writer.store() | 45 | wini.store() |
| 121 | } catch (e: IOException) { | 46 | } catch (e: IOException) { |
| 122 | Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.message) | 47 | Log.error("[SettingsFile] File not found: " + fileName + ".ini: " + e.message) |
| 123 | view.showToastMessage( | 48 | val context = YuzuApplication.appContext |
| 124 | YuzuApplication.appContext | 49 | Toast.makeText( |
| 125 | .getString(R.string.error_saving, fileName, e.message), | 50 | context, |
| 126 | false | 51 | context.getString(R.string.error_saving, fileName, e.message), |
| 127 | ) | 52 | Toast.LENGTH_SHORT |
| 128 | } | 53 | ).show() |
| 129 | } | ||
| 130 | |||
| 131 | fun saveCustomGameSettings(gameId: String?, sections: HashMap<String, SettingSection?>) { | ||
| 132 | val sortedSections: Set<String> = TreeSet(sections.keys) | ||
| 133 | for (sectionKey in sortedSections) { | ||
| 134 | val section = sections[sectionKey] | ||
| 135 | val settings = section!!.settings | ||
| 136 | val sortedKeySet: Set<String> = TreeSet(settings.keys) | ||
| 137 | for (settingKey in sortedKeySet) { | ||
| 138 | val setting = settings[settingKey] | ||
| 139 | NativeLibrary.setUserSetting( | ||
| 140 | gameId, | ||
| 141 | mapSectionNameFromIni( | ||
| 142 | section.name | ||
| 143 | ), | ||
| 144 | setting!!.key, | ||
| 145 | setting.valueAsString | ||
| 146 | ) | ||
| 147 | } | ||
| 148 | } | ||
| 149 | } | ||
| 150 | |||
| 151 | private fun mapSectionNameFromIni(generalSectionName: String): String? { | ||
| 152 | return if (sectionsMap.getForward(generalSectionName) != null) { | ||
| 153 | sectionsMap.getForward(generalSectionName) | ||
| 154 | } else { | ||
| 155 | generalSectionName | ||
| 156 | } | ||
| 157 | } | ||
| 158 | |||
| 159 | private fun mapSectionNameToIni(generalSectionName: String): String { | ||
| 160 | return if (sectionsMap.getBackward(generalSectionName) != null) { | ||
| 161 | sectionsMap.getBackward(generalSectionName).toString() | ||
| 162 | } else { | ||
| 163 | generalSectionName | ||
| 164 | } | ||
| 165 | } | ||
| 166 | |||
| 167 | fun getSettingsFile(fileName: String): File { | ||
| 168 | return File( | ||
| 169 | DirectoryInitialization.userDirectory + "/config/" + fileName + ".ini" | ||
| 170 | ) | ||
| 171 | } | ||
| 172 | |||
| 173 | private fun getCustomGameSettingsFile(gameId: String): File { | ||
| 174 | return File(DirectoryInitialization.userDirectory + "/GameSettings/" + gameId + ".ini") | ||
| 175 | } | ||
| 176 | |||
| 177 | private fun sectionFromLine(line: String, isCustomGame: Boolean): SettingSection { | ||
| 178 | var sectionName: String = line.substring(1, line.length - 1) | ||
| 179 | if (isCustomGame) { | ||
| 180 | sectionName = mapSectionNameToIni(sectionName) | ||
| 181 | } | 54 | } |
| 182 | return SettingSection(sectionName) | ||
| 183 | } | 55 | } |
| 184 | 56 | ||
| 185 | /** | 57 | fun getSettingsFile(fileName: String): File = |
| 186 | * For a line of text, determines what type of data is being represented, and returns | 58 | File(DirectoryInitialization.userDirectory + "/config/" + fileName + ".ini") |
| 187 | * a Setting object containing this data. | ||
| 188 | * | ||
| 189 | * @param line The line of text being parsed. | ||
| 190 | * @return A typed Setting containing the key/value contained in the line. | ||
| 191 | */ | ||
| 192 | private fun settingFromLine(line: String): AbstractSetting? { | ||
| 193 | val splitLine = line.split("=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray() | ||
| 194 | if (splitLine.size != 2) { | ||
| 195 | return null | ||
| 196 | } | ||
| 197 | val key = splitLine[0].trim { it <= ' ' } | ||
| 198 | val value = splitLine[1].trim { it <= ' ' } | ||
| 199 | if (value.isEmpty()) { | ||
| 200 | return null | ||
| 201 | } | ||
| 202 | |||
| 203 | val booleanSetting = BooleanSetting.from(key) | ||
| 204 | if (booleanSetting != null) { | ||
| 205 | booleanSetting.boolean = value.toBoolean() | ||
| 206 | return booleanSetting | ||
| 207 | } | ||
| 208 | |||
| 209 | val intSetting = IntSetting.from(key) | ||
| 210 | if (intSetting != null) { | ||
| 211 | intSetting.int = value.toInt() | ||
| 212 | return intSetting | ||
| 213 | } | ||
| 214 | |||
| 215 | val floatSetting = FloatSetting.from(key) | ||
| 216 | if (floatSetting != null) { | ||
| 217 | floatSetting.float = value.toFloat() | ||
| 218 | return floatSetting | ||
| 219 | } | ||
| 220 | |||
| 221 | val stringSetting = StringSetting.from(key) | ||
| 222 | if (stringSetting != null) { | ||
| 223 | stringSetting.string = value | ||
| 224 | return stringSetting | ||
| 225 | } | ||
| 226 | |||
| 227 | return null | ||
| 228 | } | ||
| 229 | |||
| 230 | /** | ||
| 231 | * Writes the contents of a Section HashMap to disk. | ||
| 232 | * | ||
| 233 | * @param parser A Wini pointed at a file on disk. | ||
| 234 | * @param section A section containing settings to be written to the file. | ||
| 235 | */ | ||
| 236 | private fun writeSection(parser: Wini, section: SettingSection) { | ||
| 237 | // Write the section header. | ||
| 238 | val header = section.name | ||
| 239 | |||
| 240 | // Write this section's values. | ||
| 241 | val settings = section.settings | ||
| 242 | val keySet: Set<String> = settings.keys | ||
| 243 | for (key in keySet) { | ||
| 244 | val setting = settings[key] | ||
| 245 | parser.put(header, setting!!.key, setting.valueAsString) | ||
| 246 | } | ||
| 247 | |||
| 248 | BooleanSetting.values().forEach { | ||
| 249 | if (!keySet.contains(it.key)) { | ||
| 250 | parser.put(header, it.key, it.valueAsString) | ||
| 251 | } | ||
| 252 | } | ||
| 253 | IntSetting.values().forEach { | ||
| 254 | if (!keySet.contains(it.key)) { | ||
| 255 | parser.put(header, it.key, it.valueAsString) | ||
| 256 | } | ||
| 257 | } | ||
| 258 | StringSetting.values().forEach { | ||
| 259 | if (!keySet.contains(it.key)) { | ||
| 260 | parser.put(header, it.key, it.valueAsString) | ||
| 261 | } | ||
| 262 | } | ||
| 263 | } | ||
| 264 | } | 59 | } |
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 aaf3a0ec1..d8dbf1f45 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 | |||
| @@ -39,7 +39,6 @@ import org.yuzu.yuzu_emu.activities.EmulationActivity | |||
| 39 | import org.yuzu.yuzu_emu.databinding.ActivityMainBinding | 39 | import org.yuzu.yuzu_emu.databinding.ActivityMainBinding |
| 40 | import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding | 40 | import org.yuzu.yuzu_emu.databinding.DialogProgressBarBinding |
| 41 | import org.yuzu.yuzu_emu.features.settings.model.Settings | 41 | import org.yuzu.yuzu_emu.features.settings.model.Settings |
| 42 | import org.yuzu.yuzu_emu.features.settings.model.SettingsViewModel | ||
| 43 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity | 42 | import org.yuzu.yuzu_emu.features.settings.ui.SettingsActivity |
| 44 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile | 43 | import org.yuzu.yuzu_emu.features.settings.utils.SettingsFile |
| 45 | import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment | 44 | import org.yuzu.yuzu_emu.fragments.IndeterminateProgressDialogFragment |
| @@ -54,7 +53,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 54 | 53 | ||
| 55 | private val homeViewModel: HomeViewModel by viewModels() | 54 | private val homeViewModel: HomeViewModel by viewModels() |
| 56 | private val gamesViewModel: GamesViewModel by viewModels() | 55 | private val gamesViewModel: GamesViewModel by viewModels() |
| 57 | private val settingsViewModel: SettingsViewModel by viewModels() | ||
| 58 | 56 | ||
| 59 | override var themeId: Int = 0 | 57 | override var themeId: Int = 0 |
| 60 | 58 | ||
| @@ -62,8 +60,6 @@ class MainActivity : AppCompatActivity(), ThemeProvider { | |||
| 62 | val splashScreen = installSplashScreen() | 60 | val splashScreen = installSplashScreen() |
| 63 | splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } | 61 | splashScreen.setKeepOnScreenCondition { !DirectoryInitialization.areDirectoriesReady } |
| 64 | 62 | ||
| 65 | settingsViewModel.settings.loadSettings() | ||
| 66 | |||
| 67 | ThemeHelper.setTheme(this) | 63 | ThemeHelper.setTheme(this) |
| 68 | 64 | ||
| 69 | super.onCreate(savedInstanceState) | 65 | super.onCreate(savedInstanceState) |
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/BiMap.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/BiMap.kt deleted file mode 100644 index 9cfda74ee..000000000 --- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/BiMap.kt +++ /dev/null | |||
| @@ -1,25 +0,0 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.utils | ||
| 5 | |||
| 6 | class BiMap<K, V> { | ||
| 7 | private val forward: MutableMap<K, V> = HashMap() | ||
| 8 | private val backward: MutableMap<V, K> = HashMap() | ||
| 9 | |||
| 10 | @Synchronized | ||
| 11 | fun add(key: K, value: V) { | ||
| 12 | forward[key] = value | ||
| 13 | backward[value] = key | ||
| 14 | } | ||
| 15 | |||
| 16 | @Synchronized | ||
| 17 | fun getForward(key: K): V? { | ||
| 18 | return forward[key] | ||
| 19 | } | ||
| 20 | |||
| 21 | @Synchronized | ||
| 22 | fun getBackward(key: V): K? { | ||
| 23 | return backward[key] | ||
| 24 | } | ||
| 25 | } | ||
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt new file mode 100644 index 000000000..d4d981f9e --- /dev/null +++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/utils/NativeConfig.kt | |||
| @@ -0,0 +1,31 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | package org.yuzu.yuzu_emu.utils | ||
| 5 | |||
| 6 | object NativeConfig { | ||
| 7 | external fun getBoolean(key: String, getDefault: Boolean): Boolean | ||
| 8 | external fun setBoolean(key: String, value: Boolean) | ||
| 9 | |||
| 10 | external fun getByte(key: String, getDefault: Boolean): Byte | ||
| 11 | external fun setByte(key: String, value: Byte) | ||
| 12 | |||
| 13 | external fun getShort(key: String, getDefault: Boolean): Short | ||
| 14 | external fun setShort(key: String, value: Short) | ||
| 15 | |||
| 16 | external fun getInt(key: String, getDefault: Boolean): Int | ||
| 17 | external fun setInt(key: String, value: Int) | ||
| 18 | |||
| 19 | external fun getFloat(key: String, getDefault: Boolean): Float | ||
| 20 | external fun setFloat(key: String, value: Float) | ||
| 21 | |||
| 22 | external fun getLong(key: String, getDefault: Boolean): Long | ||
| 23 | external fun setLong(key: String, value: Long) | ||
| 24 | |||
| 25 | external fun getString(key: String, getDefault: Boolean): String | ||
| 26 | external fun setString(key: String, value: String) | ||
| 27 | |||
| 28 | external fun getIsRuntimeModifiable(key: String): Boolean | ||
| 29 | |||
| 30 | external fun getConfigHeader(category: Int): String | ||
| 31 | } | ||
diff --git a/src/android/app/src/main/jni/CMakeLists.txt b/src/android/app/src/main/jni/CMakeLists.txt index e2ed08e9f..e15d1480b 100644 --- a/src/android/app/src/main/jni/CMakeLists.txt +++ b/src/android/app/src/main/jni/CMakeLists.txt | |||
| @@ -14,6 +14,8 @@ add_library(yuzu-android SHARED | |||
| 14 | id_cache.cpp | 14 | id_cache.cpp |
| 15 | id_cache.h | 15 | id_cache.h |
| 16 | native.cpp | 16 | native.cpp |
| 17 | native_config.cpp | ||
| 18 | uisettings.cpp | ||
| 17 | ) | 19 | ) |
| 18 | 20 | ||
| 19 | set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) | 21 | set_property(TARGET yuzu-android PROPERTY IMPORTED_LOCATION ${FFmpeg_LIBRARY_DIR}) |
diff --git a/src/android/app/src/main/jni/config.cpp b/src/android/app/src/main/jni/config.cpp index 9de9bd93e..34b425cb4 100644 --- a/src/android/app/src/main/jni/config.cpp +++ b/src/android/app/src/main/jni/config.cpp | |||
| @@ -16,18 +16,20 @@ | |||
| 16 | #include "input_common/main.h" | 16 | #include "input_common/main.h" |
| 17 | #include "jni/config.h" | 17 | #include "jni/config.h" |
| 18 | #include "jni/default_ini.h" | 18 | #include "jni/default_ini.h" |
| 19 | #include "uisettings.h" | ||
| 19 | 20 | ||
| 20 | namespace FS = Common::FS; | 21 | namespace FS = Common::FS; |
| 21 | 22 | ||
| 22 | Config::Config(std::optional<std::filesystem::path> config_path) | 23 | Config::Config(const std::string& config_name, ConfigType config_type) |
| 23 | : config_loc{config_path.value_or(FS::GetYuzuPath(FS::YuzuPath::ConfigDir) / "config.ini")}, | 24 | : type(config_type), global{config_type == ConfigType::GlobalConfig} { |
| 24 | config{std::make_unique<INIReader>(FS::PathToUTF8String(config_loc))} { | 25 | Initialize(config_name); |
| 25 | Reload(); | ||
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | Config::~Config() = default; | 28 | Config::~Config() = default; |
| 29 | 29 | ||
| 30 | bool Config::LoadINI(const std::string& default_contents, bool retry) { | 30 | bool Config::LoadINI(const std::string& default_contents, bool retry) { |
| 31 | void(FS::CreateParentDir(config_loc)); | ||
| 32 | config = std::make_unique<INIReader>(FS::PathToUTF8String(config_loc)); | ||
| 31 | const auto config_loc_str = FS::PathToUTF8String(config_loc); | 33 | const auto config_loc_str = FS::PathToUTF8String(config_loc); |
| 32 | if (config->ParseError() < 0) { | 34 | if (config->ParseError() < 0) { |
| 33 | if (retry) { | 35 | if (retry) { |
| @@ -301,9 +303,28 @@ void Config::ReadValues() { | |||
| 301 | 303 | ||
| 302 | // Network | 304 | // Network |
| 303 | ReadSetting("Network", Settings::values.network_interface); | 305 | ReadSetting("Network", Settings::values.network_interface); |
| 306 | |||
| 307 | // Android | ||
| 308 | ReadSetting("Android", AndroidSettings::values.picture_in_picture); | ||
| 309 | ReadSetting("Android", AndroidSettings::values.screen_layout); | ||
| 304 | } | 310 | } |
| 305 | 311 | ||
| 306 | void Config::Reload() { | 312 | void Config::Initialize(const std::string& config_name) { |
| 313 | const auto fs_config_loc = FS::GetYuzuPath(FS::YuzuPath::ConfigDir); | ||
| 314 | const auto config_file = fmt::format("{}.ini", config_name); | ||
| 315 | |||
| 316 | switch (type) { | ||
| 317 | case ConfigType::GlobalConfig: | ||
| 318 | config_loc = FS::PathToUTF8String(fs_config_loc / config_file); | ||
| 319 | break; | ||
| 320 | case ConfigType::PerGameConfig: | ||
| 321 | config_loc = FS::PathToUTF8String(fs_config_loc / "custom" / FS::ToU8String(config_file)); | ||
| 322 | break; | ||
| 323 | case ConfigType::InputProfile: | ||
| 324 | config_loc = FS::PathToUTF8String(fs_config_loc / "input" / config_file); | ||
| 325 | LoadINI(DefaultINI::android_config_file); | ||
| 326 | return; | ||
| 327 | } | ||
| 307 | LoadINI(DefaultINI::android_config_file); | 328 | LoadINI(DefaultINI::android_config_file); |
| 308 | ReadValues(); | 329 | ReadValues(); |
| 309 | } | 330 | } |
diff --git a/src/android/app/src/main/jni/config.h b/src/android/app/src/main/jni/config.h index 0d7d6e94d..e1e8f47ed 100644 --- a/src/android/app/src/main/jni/config.h +++ b/src/android/app/src/main/jni/config.h | |||
| @@ -13,25 +13,35 @@ | |||
| 13 | class INIReader; | 13 | class INIReader; |
| 14 | 14 | ||
| 15 | class Config { | 15 | class Config { |
| 16 | std::filesystem::path config_loc; | ||
| 17 | std::unique_ptr<INIReader> config; | ||
| 18 | |||
| 19 | bool LoadINI(const std::string& default_contents = "", bool retry = true); | 16 | bool LoadINI(const std::string& default_contents = "", bool retry = true); |
| 20 | void ReadValues(); | ||
| 21 | 17 | ||
| 22 | public: | 18 | public: |
| 23 | explicit Config(std::optional<std::filesystem::path> config_path = std::nullopt); | 19 | enum class ConfigType { |
| 20 | GlobalConfig, | ||
| 21 | PerGameConfig, | ||
| 22 | InputProfile, | ||
| 23 | }; | ||
| 24 | |||
| 25 | explicit Config(const std::string& config_name = "config", | ||
| 26 | ConfigType config_type = ConfigType::GlobalConfig); | ||
| 24 | ~Config(); | 27 | ~Config(); |
| 25 | 28 | ||
| 26 | void Reload(); | 29 | void Initialize(const std::string& config_name); |
| 27 | 30 | ||
| 28 | private: | 31 | private: |
| 29 | /** | 32 | /** |
| 30 | * Applies a value read from the sdl2_config to a Setting. | 33 | * Applies a value read from the config to a Setting. |
| 31 | * | 34 | * |
| 32 | * @param group The name of the INI group | 35 | * @param group The name of the INI group |
| 33 | * @param setting The yuzu setting to modify | 36 | * @param setting The yuzu setting to modify |
| 34 | */ | 37 | */ |
| 35 | template <typename Type, bool ranged> | 38 | template <typename Type, bool ranged> |
| 36 | void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting); | 39 | void ReadSetting(const std::string& group, Settings::Setting<Type, ranged>& setting); |
| 40 | |||
| 41 | void ReadValues(); | ||
| 42 | |||
| 43 | const ConfigType type; | ||
| 44 | std::unique_ptr<INIReader> config; | ||
| 45 | std::string config_loc; | ||
| 46 | const bool global; | ||
| 37 | }; | 47 | }; |
diff --git a/src/android/app/src/main/jni/native.cpp b/src/android/app/src/main/jni/native.cpp index 7e17833a0..b2adfdeda 100644 --- a/src/android/app/src/main/jni/native.cpp +++ b/src/android/app/src/main/jni/native.cpp | |||
| @@ -824,34 +824,6 @@ void Java_org_yuzu_yuzu_1emu_NativeLibrary_reloadSettings(JNIEnv* env, jclass cl | |||
| 824 | Config{}; | 824 | Config{}; |
| 825 | } | 825 | } |
| 826 | 826 | ||
| 827 | jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getUserSetting(JNIEnv* env, jclass clazz, | ||
| 828 | jstring j_game_id, jstring j_section, | ||
| 829 | jstring j_key) { | ||
| 830 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | ||
| 831 | std::string_view section = env->GetStringUTFChars(j_section, 0); | ||
| 832 | std::string_view key = env->GetStringUTFChars(j_key, 0); | ||
| 833 | |||
| 834 | env->ReleaseStringUTFChars(j_game_id, game_id.data()); | ||
| 835 | env->ReleaseStringUTFChars(j_section, section.data()); | ||
| 836 | env->ReleaseStringUTFChars(j_key, key.data()); | ||
| 837 | |||
| 838 | return env->NewStringUTF(""); | ||
| 839 | } | ||
| 840 | |||
| 841 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_setUserSetting(JNIEnv* env, jclass clazz, | ||
| 842 | jstring j_game_id, jstring j_section, | ||
| 843 | jstring j_key, jstring j_value) { | ||
| 844 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | ||
| 845 | std::string_view section = env->GetStringUTFChars(j_section, 0); | ||
| 846 | std::string_view key = env->GetStringUTFChars(j_key, 0); | ||
| 847 | std::string_view value = env->GetStringUTFChars(j_value, 0); | ||
| 848 | |||
| 849 | env->ReleaseStringUTFChars(j_game_id, game_id.data()); | ||
| 850 | env->ReleaseStringUTFChars(j_section, section.data()); | ||
| 851 | env->ReleaseStringUTFChars(j_key, key.data()); | ||
| 852 | env->ReleaseStringUTFChars(j_value, value.data()); | ||
| 853 | } | ||
| 854 | |||
| 855 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni(JNIEnv* env, jclass clazz, | 827 | void Java_org_yuzu_yuzu_1emu_NativeLibrary_initGameIni(JNIEnv* env, jclass clazz, |
| 856 | jstring j_game_id) { | 828 | jstring j_game_id) { |
| 857 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); | 829 | std::string_view game_id = env->GetStringUTFChars(j_game_id, 0); |
diff --git a/src/android/app/src/main/jni/native_config.cpp b/src/android/app/src/main/jni/native_config.cpp new file mode 100644 index 000000000..6123b3d08 --- /dev/null +++ b/src/android/app/src/main/jni/native_config.cpp | |||
| @@ -0,0 +1,224 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include <string> | ||
| 5 | |||
| 6 | #include <jni.h> | ||
| 7 | |||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "common/settings.h" | ||
| 10 | #include "jni/android_common/android_common.h" | ||
| 11 | #include "jni/config.h" | ||
| 12 | #include "uisettings.h" | ||
| 13 | |||
| 14 | template <typename T> | ||
| 15 | Settings::Setting<T>* getSetting(JNIEnv* env, jstring jkey) { | ||
| 16 | auto key = GetJString(env, jkey); | ||
| 17 | auto basicSetting = Settings::values.linkage.by_key[key]; | ||
| 18 | auto basicAndroidSetting = AndroidSettings::values.linkage.by_key[key]; | ||
| 19 | if (basicSetting != 0) { | ||
| 20 | return static_cast<Settings::Setting<T>*>(basicSetting); | ||
| 21 | } | ||
| 22 | if (basicAndroidSetting != 0) { | ||
| 23 | return static_cast<Settings::Setting<T>*>(basicAndroidSetting); | ||
| 24 | } | ||
| 25 | LOG_ERROR(Frontend, "[Android Native] Could not find setting - {}", key); | ||
| 26 | return nullptr; | ||
| 27 | } | ||
| 28 | |||
| 29 | extern "C" { | ||
| 30 | |||
| 31 | jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getBoolean(JNIEnv* env, jobject obj, | ||
| 32 | jstring jkey, jboolean getDefault) { | ||
| 33 | auto setting = getSetting<bool>(env, jkey); | ||
| 34 | if (setting == nullptr) { | ||
| 35 | return false; | ||
| 36 | } | ||
| 37 | setting->SetGlobal(true); | ||
| 38 | |||
| 39 | if (static_cast<bool>(getDefault)) { | ||
| 40 | return setting->GetDefault(); | ||
| 41 | } | ||
| 42 | |||
| 43 | return setting->GetValue(); | ||
| 44 | } | ||
| 45 | |||
| 46 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setBoolean(JNIEnv* env, jobject obj, jstring jkey, | ||
| 47 | jboolean value) { | ||
| 48 | auto setting = getSetting<bool>(env, jkey); | ||
| 49 | if (setting == nullptr) { | ||
| 50 | return; | ||
| 51 | } | ||
| 52 | setting->SetGlobal(true); | ||
| 53 | setting->SetValue(static_cast<bool>(value)); | ||
| 54 | } | ||
| 55 | |||
| 56 | jbyte Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getByte(JNIEnv* env, jobject obj, jstring jkey, | ||
| 57 | jboolean getDefault) { | ||
| 58 | auto setting = getSetting<u8>(env, jkey); | ||
| 59 | if (setting == nullptr) { | ||
| 60 | return -1; | ||
| 61 | } | ||
| 62 | setting->SetGlobal(true); | ||
| 63 | |||
| 64 | if (static_cast<bool>(getDefault)) { | ||
| 65 | return setting->GetDefault(); | ||
| 66 | } | ||
| 67 | |||
| 68 | return setting->GetValue(); | ||
| 69 | } | ||
| 70 | |||
| 71 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setByte(JNIEnv* env, jobject obj, jstring jkey, | ||
| 72 | jbyte value) { | ||
| 73 | auto setting = getSetting<u8>(env, jkey); | ||
| 74 | if (setting == nullptr) { | ||
| 75 | return; | ||
| 76 | } | ||
| 77 | setting->SetGlobal(true); | ||
| 78 | setting->SetValue(value); | ||
| 79 | } | ||
| 80 | |||
| 81 | jshort Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getShort(JNIEnv* env, jobject obj, jstring jkey, | ||
| 82 | jboolean getDefault) { | ||
| 83 | auto setting = getSetting<u16>(env, jkey); | ||
| 84 | if (setting == nullptr) { | ||
| 85 | return -1; | ||
| 86 | } | ||
| 87 | setting->SetGlobal(true); | ||
| 88 | |||
| 89 | if (static_cast<bool>(getDefault)) { | ||
| 90 | return setting->GetDefault(); | ||
| 91 | } | ||
| 92 | |||
| 93 | return setting->GetValue(); | ||
| 94 | } | ||
| 95 | |||
| 96 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setShort(JNIEnv* env, jobject obj, jstring jkey, | ||
| 97 | jshort value) { | ||
| 98 | auto setting = getSetting<u16>(env, jkey); | ||
| 99 | if (setting == nullptr) { | ||
| 100 | return; | ||
| 101 | } | ||
| 102 | setting->SetGlobal(true); | ||
| 103 | setting->SetValue(value); | ||
| 104 | } | ||
| 105 | |||
| 106 | jint Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getInt(JNIEnv* env, jobject obj, jstring jkey, | ||
| 107 | jboolean getDefault) { | ||
| 108 | auto setting = getSetting<int>(env, jkey); | ||
| 109 | if (setting == nullptr) { | ||
| 110 | return -1; | ||
| 111 | } | ||
| 112 | setting->SetGlobal(true); | ||
| 113 | |||
| 114 | if (static_cast<bool>(getDefault)) { | ||
| 115 | return setting->GetDefault(); | ||
| 116 | } | ||
| 117 | |||
| 118 | return setting->GetValue(); | ||
| 119 | } | ||
| 120 | |||
| 121 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setInt(JNIEnv* env, jobject obj, jstring jkey, | ||
| 122 | jint value) { | ||
| 123 | auto setting = getSetting<int>(env, jkey); | ||
| 124 | if (setting == nullptr) { | ||
| 125 | return; | ||
| 126 | } | ||
| 127 | setting->SetGlobal(true); | ||
| 128 | setting->SetValue(value); | ||
| 129 | } | ||
| 130 | |||
| 131 | jfloat Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getFloat(JNIEnv* env, jobject obj, jstring jkey, | ||
| 132 | jboolean getDefault) { | ||
| 133 | auto setting = getSetting<float>(env, jkey); | ||
| 134 | if (setting == nullptr) { | ||
| 135 | return -1; | ||
| 136 | } | ||
| 137 | setting->SetGlobal(true); | ||
| 138 | |||
| 139 | if (static_cast<bool>(getDefault)) { | ||
| 140 | return setting->GetDefault(); | ||
| 141 | } | ||
| 142 | |||
| 143 | return setting->GetValue(); | ||
| 144 | } | ||
| 145 | |||
| 146 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setFloat(JNIEnv* env, jobject obj, jstring jkey, | ||
| 147 | jfloat value) { | ||
| 148 | auto setting = getSetting<float>(env, jkey); | ||
| 149 | if (setting == nullptr) { | ||
| 150 | return; | ||
| 151 | } | ||
| 152 | setting->SetGlobal(true); | ||
| 153 | setting->SetValue(value); | ||
| 154 | } | ||
| 155 | |||
| 156 | jlong Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getLong(JNIEnv* env, jobject obj, jstring jkey, | ||
| 157 | jboolean getDefault) { | ||
| 158 | auto setting = getSetting<long>(env, jkey); | ||
| 159 | if (setting == nullptr) { | ||
| 160 | return -1; | ||
| 161 | } | ||
| 162 | setting->SetGlobal(true); | ||
| 163 | |||
| 164 | if (static_cast<bool>(getDefault)) { | ||
| 165 | return setting->GetDefault(); | ||
| 166 | } | ||
| 167 | |||
| 168 | return setting->GetValue(); | ||
| 169 | } | ||
| 170 | |||
| 171 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setLong(JNIEnv* env, jobject obj, jstring jkey, | ||
| 172 | jlong value) { | ||
| 173 | auto setting = getSetting<long>(env, jkey); | ||
| 174 | if (setting == nullptr) { | ||
| 175 | return; | ||
| 176 | } | ||
| 177 | setting->SetGlobal(true); | ||
| 178 | setting->SetValue(value); | ||
| 179 | } | ||
| 180 | |||
| 181 | jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getString(JNIEnv* env, jobject obj, jstring jkey, | ||
| 182 | jboolean getDefault) { | ||
| 183 | auto setting = getSetting<std::string>(env, jkey); | ||
| 184 | if (setting == nullptr) { | ||
| 185 | return ToJString(env, ""); | ||
| 186 | } | ||
| 187 | setting->SetGlobal(true); | ||
| 188 | |||
| 189 | if (static_cast<bool>(getDefault)) { | ||
| 190 | return ToJString(env, setting->GetDefault()); | ||
| 191 | } | ||
| 192 | |||
| 193 | return ToJString(env, setting->GetValue()); | ||
| 194 | } | ||
| 195 | |||
| 196 | void Java_org_yuzu_yuzu_1emu_utils_NativeConfig_setString(JNIEnv* env, jobject obj, jstring jkey, | ||
| 197 | jstring value) { | ||
| 198 | auto setting = getSetting<std::string>(env, jkey); | ||
| 199 | if (setting == nullptr) { | ||
| 200 | return; | ||
| 201 | } | ||
| 202 | |||
| 203 | setting->SetGlobal(true); | ||
| 204 | setting->SetValue(GetJString(env, value)); | ||
| 205 | } | ||
| 206 | |||
| 207 | jboolean Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getIsRuntimeModifiable(JNIEnv* env, jobject obj, | ||
| 208 | jstring jkey) { | ||
| 209 | auto key = GetJString(env, jkey); | ||
| 210 | auto setting = Settings::values.linkage.by_key[key]; | ||
| 211 | if (setting != 0) { | ||
| 212 | return setting->RuntimeModfiable(); | ||
| 213 | } | ||
| 214 | LOG_ERROR(Frontend, "[Android Native] Could not find setting - {}", key); | ||
| 215 | return true; | ||
| 216 | } | ||
| 217 | |||
| 218 | jstring Java_org_yuzu_yuzu_1emu_utils_NativeConfig_getConfigHeader(JNIEnv* env, jobject obj, | ||
| 219 | jint jcategory) { | ||
| 220 | auto category = static_cast<Settings::Category>(jcategory); | ||
| 221 | return ToJString(env, Settings::TranslateCategory(category)); | ||
| 222 | } | ||
| 223 | |||
| 224 | } // extern "C" | ||
diff --git a/src/android/app/src/main/jni/uisettings.cpp b/src/android/app/src/main/jni/uisettings.cpp new file mode 100644 index 000000000..f2f0bad50 --- /dev/null +++ b/src/android/app/src/main/jni/uisettings.cpp | |||
| @@ -0,0 +1,10 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "uisettings.h" | ||
| 5 | |||
| 6 | namespace AndroidSettings { | ||
| 7 | |||
| 8 | Values values; | ||
| 9 | |||
| 10 | } // namespace AndroidSettings | ||
diff --git a/src/android/app/src/main/jni/uisettings.h b/src/android/app/src/main/jni/uisettings.h new file mode 100644 index 000000000..494654af7 --- /dev/null +++ b/src/android/app/src/main/jni/uisettings.h | |||
| @@ -0,0 +1,29 @@ | |||
| 1 | // SPDX-FileCopyrightText: 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <common/settings_common.h> | ||
| 7 | #include "common/common_types.h" | ||
| 8 | #include "common/settings_setting.h" | ||
| 9 | |||
| 10 | namespace AndroidSettings { | ||
| 11 | |||
| 12 | struct Values { | ||
| 13 | Settings::Linkage linkage; | ||
| 14 | |||
| 15 | // Android | ||
| 16 | Settings::Setting<bool> picture_in_picture{linkage, true, "picture_in_picture", | ||
| 17 | Settings::Category::Android}; | ||
| 18 | Settings::Setting<s32> screen_layout{linkage, | ||
| 19 | 5, | ||
| 20 | "screen_layout", | ||
| 21 | Settings::Category::Android, | ||
| 22 | Settings::Specialization::Default, | ||
| 23 | true, | ||
| 24 | true}; | ||
| 25 | }; | ||
| 26 | |||
| 27 | extern Values values; | ||
| 28 | |||
| 29 | } // namespace AndroidSettings | ||
diff --git a/src/android/app/src/main/res/values/arrays.xml b/src/android/app/src/main/res/values/arrays.xml index 200b99185..dc10159c9 100644 --- a/src/android/app/src/main/res/values/arrays.xml +++ b/src/android/app/src/main/res/values/arrays.xml | |||
| @@ -243,10 +243,10 @@ | |||
| 243 | <item>@string/cubeb</item> | 243 | <item>@string/cubeb</item> |
| 244 | <item>@string/string_null</item> | 244 | <item>@string/string_null</item> |
| 245 | </string-array> | 245 | </string-array> |
| 246 | <string-array name="outputEngineValues"> | 246 | <integer-array name="outputEngineValues"> |
| 247 | <item>auto</item> | 247 | <item>0</item> |
| 248 | <item>cubeb</item> | 248 | <item>1</item> |
| 249 | <item>null</item> | 249 | <item>3</item> |
| 250 | </string-array> | 250 | </integer-array> |
| 251 | 251 | ||
| 252 | </resources> | 252 | </resources> |
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml index de1b2909b..df76563fc 100644 --- a/src/android/app/src/main/res/values/strings.xml +++ b/src/android/app/src/main/res/values/strings.xml | |||
| @@ -200,6 +200,7 @@ | |||
| 200 | <string name="ini_saved">Saved settings</string> | 200 | <string name="ini_saved">Saved settings</string> |
| 201 | <string name="gameid_saved">Saved settings for %1$s</string> | 201 | <string name="gameid_saved">Saved settings for %1$s</string> |
| 202 | <string name="error_saving">Error saving %1$s.ini: %2$s</string> | 202 | <string name="error_saving">Error saving %1$s.ini: %2$s</string> |
| 203 | <string name="unimplemented_menu">Unimplemented Menu</string> | ||
| 203 | <string name="loading">Loading…</string> | 204 | <string name="loading">Loading…</string> |
| 204 | <string name="reset_setting_confirmation">Do you want to reset this setting back to its default value?</string> | 205 | <string name="reset_setting_confirmation">Do you want to reset this setting back to its default value?</string> |
| 205 | <string name="reset_to_default">Reset to default</string> | 206 | <string name="reset_to_default">Reset to default</string> |
diff --git a/src/common/settings.cpp b/src/common/settings.cpp index 524056841..4ecaf550b 100644 --- a/src/common/settings.cpp +++ b/src/common/settings.cpp | |||
| @@ -159,6 +159,8 @@ float Volume() { | |||
| 159 | 159 | ||
| 160 | const char* TranslateCategory(Category category) { | 160 | const char* TranslateCategory(Category category) { |
| 161 | switch (category) { | 161 | switch (category) { |
| 162 | case Category::Android: | ||
| 163 | return "Android"; | ||
| 162 | case Category::Audio: | 164 | case Category::Audio: |
| 163 | return "Audio"; | 165 | return "Audio"; |
| 164 | case Category::Core: | 166 | case Category::Core: |
diff --git a/src/common/settings_common.cpp b/src/common/settings_common.cpp index 137b65d5f..5960b78aa 100644 --- a/src/common/settings_common.cpp +++ b/src/common/settings_common.cpp | |||
| @@ -14,6 +14,7 @@ BasicSetting::BasicSetting(Linkage& linkage, const std::string& name, enum Categ | |||
| 14 | : label{name}, category{category_}, id{linkage.count}, save{save_}, | 14 | : label{name}, category{category_}, id{linkage.count}, save{save_}, |
| 15 | runtime_modifiable{runtime_modifiable_}, specialization{specialization_}, | 15 | runtime_modifiable{runtime_modifiable_}, specialization{specialization_}, |
| 16 | other_setting{other_setting_} { | 16 | other_setting{other_setting_} { |
| 17 | linkage.by_key.insert({name, this}); | ||
| 17 | linkage.by_category[category].push_back(this); | 18 | linkage.by_category[category].push_back(this); |
| 18 | linkage.count++; | 19 | linkage.count++; |
| 19 | } | 20 | } |
diff --git a/src/common/settings_common.h b/src/common/settings_common.h index 3082e0ce1..5b170dfd5 100644 --- a/src/common/settings_common.h +++ b/src/common/settings_common.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | namespace Settings { | 12 | namespace Settings { |
| 13 | 13 | ||
| 14 | enum class Category : u32 { | 14 | enum class Category : u32 { |
| 15 | Android, | ||
| 15 | Audio, | 16 | Audio, |
| 16 | Core, | 17 | Core, |
| 17 | Cpu, | 18 | Cpu, |
| @@ -68,6 +69,7 @@ public: | |||
| 68 | explicit Linkage(u32 initial_count = 0); | 69 | explicit Linkage(u32 initial_count = 0); |
| 69 | ~Linkage(); | 70 | ~Linkage(); |
| 70 | std::map<Category, std::vector<BasicSetting*>> by_category{}; | 71 | std::map<Category, std::vector<BasicSetting*>> by_category{}; |
| 72 | std::map<std::string, Settings::BasicSetting*> by_key{}; | ||
| 71 | std::vector<std::function<void()>> restore_functions{}; | 73 | std::vector<std::function<void()>> restore_functions{}; |
| 72 | u32 count; | 74 | u32 count; |
| 73 | }; | 75 | }; |