Merge pull request #11662 from t895/kotlin-settings

Android: Convert Settings to Kotlin
This commit is contained in:
JosJuice 2023-03-19 17:15:22 +01:00 committed by GitHub
commit 002a96adb0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
110 changed files with 6893 additions and 6613 deletions

View File

@ -160,7 +160,7 @@ class CheatsActivity : AppCompatActivity(), PanelSlideListener {
fun loadGameSpecificSettings(): Settings { fun loadGameSpecificSettings(): Settings {
val settings = Settings() val settings = Settings()
settings.loadSettings(gameId, revision, isWii) settings.loadSettings(gameId!!, revision, isWii)
return settings return settings
} }

View File

@ -43,7 +43,7 @@ abstract class SettingDisabledWarningFragment(
super.onResume() super.onResume()
val activity = requireActivity() as CheatsActivity val activity = requireActivity() as CheatsActivity
activity.loadGameSpecificSettings().use { activity.loadGameSpecificSettings().use {
val cheatsEnabled = setting.getBoolean() val cheatsEnabled = setting.boolean
requireView().visibility = if (cheatsEnabled) View.GONE else View.VISIBLE requireView().visibility = if (cheatsEnabled) View.GONE else View.VISIBLE
} }
} }

View File

@ -46,8 +46,8 @@ public class InputDeviceSetting extends StringSingleChoiceSetting
{ {
String[] devices = ControllerInterface.getAllDeviceStrings(); String[] devices = ControllerInterface.getAllDeviceStrings();
mChoices = devices; setChoices(devices);
mValues = devices; setValues(devices);
} }
@Override @Override

View File

@ -2,7 +2,6 @@
package org.dolphinemu.dolphinemu.features.input.ui package org.dolphinemu.dolphinemu.features.input.ui
import android.os.Build
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
@ -14,6 +13,7 @@ import com.google.android.material.divider.MaterialDividerItemDecoration
import org.dolphinemu.dolphinemu.R import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.databinding.DialogInputProfilesBinding import org.dolphinemu.dolphinemu.databinding.DialogInputProfilesBinding
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag
import org.dolphinemu.dolphinemu.utils.SerializableHelper.serializable
class ProfileDialog : BottomSheetDialogFragment() { class ProfileDialog : BottomSheetDialogFragment() {
private var presenter: ProfileDialogPresenter? = null private var presenter: ProfileDialogPresenter? = null
@ -22,11 +22,7 @@ class ProfileDialog : BottomSheetDialogFragment() {
private val binding get() = _binding!! private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
val menuTag: MenuTag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { val menuTag = requireArguments().serializable<MenuTag>(KEY_MENU_TAG)
requireArguments().getSerializable(KEY_MENU_TAG, MenuTag::class.java) as MenuTag
} else {
requireArguments().getSerializable(KEY_MENU_TAG) as MenuTag
}
presenter = ProfileDialogPresenter(this, menuTag) presenter = ProfileDialogPresenter(this, menuTag)

View File

@ -1,12 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import androidx.annotation.NonNull;
public interface AbstractBooleanSetting extends AbstractSetting
{
boolean getBoolean();
void setBoolean(@NonNull Settings settings, boolean newValue);
}

View File

@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
interface AbstractBooleanSetting : AbstractSetting {
val boolean: Boolean
fun setBoolean(settings: Settings, newValue: Boolean)
}

View File

@ -1,12 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import androidx.annotation.NonNull;
public interface AbstractFloatSetting extends AbstractSetting
{
float getFloat();
void setFloat(@NonNull Settings settings, float newValue);
}

View File

@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
interface AbstractFloatSetting : AbstractSetting {
val float: Float
fun setFloat(settings: Settings, newValue: Float)
}

View File

@ -1,12 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import androidx.annotation.NonNull;
public interface AbstractIntSetting extends AbstractSetting
{
int getInt();
void setInt(@NonNull Settings settings, int newValue);
}

View File

@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
interface AbstractIntSetting : AbstractSetting {
val int: Int
fun setInt(settings: Settings, newValue: Int)
}

View File

@ -1,14 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import androidx.annotation.NonNull;
public interface AbstractSetting
{
boolean isOverridden();
boolean isRuntimeEditable();
boolean delete(@NonNull Settings settings);
}

View File

@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
interface AbstractSetting {
val isOverridden: Boolean
val isRuntimeEditable: Boolean
fun delete(settings: Settings): Boolean
}

View File

@ -1,13 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import androidx.annotation.NonNull;
public interface AbstractStringSetting extends AbstractSetting
{
@NonNull
String getString();
void setString(@NonNull Settings settings, @NonNull String newValue);
}

View File

@ -0,0 +1,9 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
interface AbstractStringSetting : AbstractSetting {
val string: String
fun setString(settings: Settings, newValue: String)
}

View File

@ -1,62 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import androidx.annotation.NonNull;
public class AdHocBooleanSetting implements AbstractBooleanSetting
{
private final String mFile;
private final String mSection;
private final String mKey;
private final boolean mDefaultValue;
public AdHocBooleanSetting(String file, String section, String key, boolean defaultValue)
{
mFile = file;
mSection = section;
mKey = key;
mDefaultValue = defaultValue;
if (!NativeConfig.isSettingSaveable(file, section, key))
{
throw new IllegalArgumentException("File/section/key is unknown or legacy");
}
}
@Override
public boolean isOverridden()
{
return NativeConfig.isOverridden(mFile, mSection, mKey);
}
@Override
public boolean isRuntimeEditable()
{
return true;
}
@Override
public boolean delete(@NonNull Settings settings)
{
return NativeConfig.deleteKey(settings.getWriteLayer(), mFile, mSection, mKey);
}
@Override
public boolean getBoolean()
{
return NativeConfig.getBoolean(NativeConfig.LAYER_ACTIVE, mFile, mSection, mKey, mDefaultValue);
}
@Override
public void setBoolean(@NonNull Settings settings, boolean newValue)
{
NativeConfig.setBoolean(settings.getWriteLayer(), mFile, mSection, mKey, newValue);
}
public static boolean getBooleanGlobal(String file, String section, String key,
boolean defaultValue)
{
return NativeConfig.getBoolean(NativeConfig.LAYER_ACTIVE, file, section, key, defaultValue);
}
}

View File

@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
class AdHocBooleanSetting(
private val file: String,
private val section: String,
private val key: String,
private val defaultValue: Boolean
) : AbstractBooleanSetting {
init {
require(
NativeConfig.isSettingSaveable(
file,
section,
key
)
) { "File/section/key is unknown or legacy" }
}
override val isOverridden: Boolean
get() = NativeConfig.isOverridden(file, section, key)
override val isRuntimeEditable: Boolean = true
override fun delete(settings: Settings): Boolean {
return NativeConfig.deleteKey(settings.writeLayer, file, section, key)
}
override val boolean: Boolean
get() = NativeConfig.getBoolean(NativeConfig.LAYER_ACTIVE, file, section, key, defaultValue)
override fun setBoolean(settings: Settings, newValue: Boolean) {
NativeConfig.setBoolean(settings.writeLayer, file, section, key, newValue)
}
}

View File

@ -1,61 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import androidx.annotation.NonNull;
public class AdHocStringSetting implements AbstractStringSetting
{
private final String mFile;
private final String mSection;
private final String mKey;
private final String mDefaultValue;
public AdHocStringSetting(String file, String section, String key, String defaultValue)
{
mFile = file;
mSection = section;
mKey = key;
mDefaultValue = defaultValue;
if (!NativeConfig.isSettingSaveable(file, section, key))
{
throw new IllegalArgumentException("File/section/key is unknown or legacy");
}
}
@Override
public boolean isOverridden()
{
return NativeConfig.isOverridden(mFile, mSection, mKey);
}
@Override
public boolean isRuntimeEditable()
{
return true;
}
@Override
public boolean delete(@NonNull Settings settings)
{
return NativeConfig.deleteKey(settings.getWriteLayer(), mFile, mSection, mKey);
}
@NonNull @Override
public String getString()
{
return NativeConfig.getString(NativeConfig.LAYER_ACTIVE, mFile, mSection, mKey, mDefaultValue);
}
@Override
public void setString(@NonNull Settings settings, @NonNull String newValue)
{
NativeConfig.setString(settings.getWriteLayer(), mFile, mSection, mKey, newValue);
}
public static String getStringGlobal(String file, String section, String key, String defaultValue)
{
return NativeConfig.getString(NativeConfig.LAYER_ACTIVE, file, section, key, defaultValue);
}
}

View File

@ -0,0 +1,36 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
class AdHocStringSetting(
private val file: String,
private val section: String,
private val key: String,
private val defaultValue: String
) : AbstractStringSetting {
init {
require(
NativeConfig.isSettingSaveable(
file,
section,
key
)
) { "File/section/key is unknown or legacy" }
}
override val isOverridden: Boolean
get() = NativeConfig.isOverridden(file, section, key)
override val isRuntimeEditable: Boolean = true
override fun delete(settings: Settings): Boolean {
return NativeConfig.deleteKey(settings.writeLayer, file, section, key)
}
override val string: String
get() = NativeConfig.getString(NativeConfig.LAYER_ACTIVE, file, section, key, defaultValue)
override fun setString(settings: Settings, newValue: String) {
NativeConfig.setString(settings.writeLayer, file, section, key, newValue)
}
}

View File

@ -1,371 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public enum BooleanSetting implements AbstractBooleanSetting
{
// These entries have the same names and order as in C++, just for consistency.
MAIN_SKIP_IPL(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SkipIPL", true),
MAIN_DSP_HLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "DSPHLE", true),
MAIN_FASTMEM(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "Fastmem", true),
MAIN_CPU_THREAD(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "CPUThread", true),
MAIN_SYNC_ON_SKIP_IDLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SyncOnSkipIdle", true),
MAIN_ENABLE_CHEATS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EnableCheats", false),
MAIN_OVERRIDE_REGION_SETTINGS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE,
"OverrideRegionSettings", false),
MAIN_AUDIO_STRETCH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AudioStretch", false),
MAIN_BBA_XLINK_CHAT_OSD(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "BBA_XLINK_CHAT_OSD",
false),
MAIN_ADAPTER_RUMBLE_0(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AdapterRumble0", true),
MAIN_ADAPTER_RUMBLE_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AdapterRumble1", true),
MAIN_ADAPTER_RUMBLE_2(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AdapterRumble2", true),
MAIN_ADAPTER_RUMBLE_3(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AdapterRumble3", true),
MAIN_SIMULATE_KONGA_0(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SimulateKonga0", false),
MAIN_SIMULATE_KONGA_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SimulateKonga1", false),
MAIN_SIMULATE_KONGA_2(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SimulateKonga2", false),
MAIN_SIMULATE_KONGA_3(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SimulateKonga3", false),
MAIN_WII_SD_CARD(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "WiiSDCard", true),
MAIN_WII_SD_CARD_ENABLE_FOLDER_SYNC(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE,
"WiiSDCardEnableFolderSync", false),
MAIN_WIIMOTE_CONTINUOUS_SCANNING(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE,
"WiimoteContinuousScanning", false),
MAIN_WIIMOTE_ENABLE_SPEAKER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE,
"WiimoteEnableSpeaker", false),
MAIN_MMU(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "MMU", false),
MAIN_PAUSE_ON_PANIC(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "PauseOnPanic", false),
MAIN_ACCURATE_CPU_CACHE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AccurateCPUCache",
false),
MAIN_SYNC_GPU(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SyncGPU", false),
MAIN_FAST_DISC_SPEED(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "FastDiscSpeed",
false),
MAIN_OVERCLOCK_ENABLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "OverclockEnable", false),
MAIN_RAM_OVERRIDE_ENABLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "RAMOverrideEnable",
false),
MAIN_CUSTOM_RTC_ENABLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EnableCustomRTC",
false),
MAIN_AUTO_DISC_CHANGE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AutoDiscChange", false),
MAIN_ALLOW_SD_WRITES(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "WiiSDCardAllowWrites",
true),
MAIN_ENABLE_SAVESTATES(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EnableSaveStates",
false),
MAIN_DSP_JIT(Settings.FILE_DOLPHIN, Settings.SECTION_INI_DSP, "EnableJIT", true),
MAIN_EXPAND_TO_CUTOUT_AREA(Settings.FILE_DOLPHIN, Settings.SECTION_INI_INTERFACE,
"ExpandToCutoutArea", false),
MAIN_USE_PANIC_HANDLERS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_INTERFACE,
"UsePanicHandlers", true),
MAIN_OSD_MESSAGES(Settings.FILE_DOLPHIN, Settings.SECTION_INI_INTERFACE,
"OnScreenDisplayMessages", true),
MAIN_ANALYTICS_ENABLED(Settings.FILE_DOLPHIN, Settings.SECTION_ANALYTICS, "Enabled", false),
MAIN_ANALYTICS_PERMISSION_ASKED(Settings.FILE_DOLPHIN, Settings.SECTION_ANALYTICS,
"PermissionAsked", false),
MAIN_RECURSIVE_ISO_PATHS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL,
"RecursiveISOPaths", false),
MAIN_USE_GAME_COVERS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL,
"UseGameCovers", true),
MAIN_DEBUG_JIT_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitOff", false),
MAIN_DEBUG_JIT_LOAD_STORE_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitLoadStoreOff",
false),
MAIN_DEBUG_JIT_LOAD_STORE_FLOATING_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG,
"JitLoadStoreFloatingOff", false),
MAIN_DEBUG_JIT_LOAD_STORE_PAIRED_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG,
"JitLoadStorePairedOff", false),
MAIN_DEBUG_JIT_FLOATING_POINT_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG,
"JitFloatingPointOff", false),
MAIN_DEBUG_JIT_INTEGER_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitIntegerOff", false),
MAIN_DEBUG_JIT_PAIRED_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitPairedOff", false),
MAIN_DEBUG_JIT_SYSTEM_REGISTERS_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG,
"JitSystemRegistersOff", false),
MAIN_DEBUG_JIT_BRANCH_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitBranchOff", false),
MAIN_DEBUG_JIT_REGISTER_CACHE_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG,
"JitRegisterCacheOff", false),
MAIN_EMULATE_SKYLANDER_PORTAL(Settings.FILE_DOLPHIN, Settings.SECTION_EMULATED_USB_DEVICES,
"EmulateSkylanderPortal", false),
MAIN_SHOW_GAME_TITLES(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID,
"ShowGameTitles", true),
MAIN_USE_BLACK_BACKGROUNDS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID,
"UseBlackBackgrounds", false),
MAIN_JOYSTICK_REL_CENTER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID,
"JoystickRelCenter", true),
MAIN_SHOW_INPUT_OVERLAY(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID,
"ShowInputOverlay", true),
MAIN_IR_ALWAYS_RECENTER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID,
"IRAlwaysRecenter", false),
MAIN_BUTTON_TOGGLE_GC_0(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonA", true),
MAIN_BUTTON_TOGGLE_GC_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonB", true),
MAIN_BUTTON_TOGGLE_GC_2(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonX", true),
MAIN_BUTTON_TOGGLE_GC_3(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonY", true),
MAIN_BUTTON_TOGGLE_GC_4(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonZ", true),
MAIN_BUTTON_TOGGLE_GC_5(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonStart", true),
MAIN_BUTTON_TOGGLE_GC_6(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCTriggerL", true),
MAIN_BUTTON_TOGGLE_GC_7(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCTriggerR", true),
MAIN_BUTTON_TOGGLE_GC_8(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCDPad", true),
MAIN_BUTTON_TOGGLE_GC_9(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCStickMain", true),
MAIN_BUTTON_TOGGLE_GC_10(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCStickC", true),
MAIN_BUTTON_TOGGLE_CLASSIC_0(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonA", true),
MAIN_BUTTON_TOGGLE_CLASSIC_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonB", true),
MAIN_BUTTON_TOGGLE_CLASSIC_2(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonX", true),
MAIN_BUTTON_TOGGLE_CLASSIC_3(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonY", true),
MAIN_BUTTON_TOGGLE_CLASSIC_4(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonPlus", true),
MAIN_BUTTON_TOGGLE_CLASSIC_5(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonMinus", true),
MAIN_BUTTON_TOGGLE_CLASSIC_6(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonHome", true),
MAIN_BUTTON_TOGGLE_CLASSIC_7(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicTriggerL", true),
MAIN_BUTTON_TOGGLE_CLASSIC_8(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicTriggerR", true),
MAIN_BUTTON_TOGGLE_CLASSIC_9(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonZL", true),
MAIN_BUTTON_TOGGLE_CLASSIC_10(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonZR", true),
MAIN_BUTTON_TOGGLE_CLASSIC_11(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicDPad", true),
MAIN_BUTTON_TOGGLE_CLASSIC_12(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicStickLeft", true),
MAIN_BUTTON_TOGGLE_CLASSIC_13(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicStickRight", true),
MAIN_BUTTON_TOGGLE_WII_0(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButtonA", true),
MAIN_BUTTON_TOGGLE_WII_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButtonB", true),
MAIN_BUTTON_TOGGLE_WII_2(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButton1", true),
MAIN_BUTTON_TOGGLE_WII_3(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButton2", true),
MAIN_BUTTON_TOGGLE_WII_4(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButtonPlus", true),
MAIN_BUTTON_TOGGLE_WII_5(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButtonMinus", true),
MAIN_BUTTON_TOGGLE_WII_6(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButtonHome", true),
MAIN_BUTTON_TOGGLE_WII_7(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteDPad", true),
MAIN_BUTTON_TOGGLE_WII_8(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleNunchukC", true),
MAIN_BUTTON_TOGGLE_WII_9(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleNunchukZ", true),
MAIN_BUTTON_TOGGLE_WII_10(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleNunchukStick", true),
SYSCONF_SCREENSAVER(Settings.FILE_SYSCONF, "IPL", "SSV", false),
SYSCONF_WIDESCREEN(Settings.FILE_SYSCONF, "IPL", "AR", true),
SYSCONF_PROGRESSIVE_SCAN(Settings.FILE_SYSCONF, "IPL", "PGS", true),
SYSCONF_PAL60(Settings.FILE_SYSCONF, "IPL", "E60", true),
SYSCONF_WIIMOTE_MOTOR(Settings.FILE_SYSCONF, "BT", "MOT", true),
GFX_WIDESCREEN_HACK(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "wideScreenHack", false),
GFX_CROP(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "Crop", false),
GFX_SHOW_FPS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowFPS", false),
GFX_SHOW_FTIMES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowFTimes", false),
GFX_SHOW_VPS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowVPS", false),
GFX_SHOW_VTIMES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowVTimes", false),
GFX_SHOW_GRAPHS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowGraphs", false),
GFX_SHOW_SPEED(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowSpeed", false),
GFX_SHOW_SPEED_COLORS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowSpeedColors", true),
GFX_LOG_RENDER_TIME_TO_FILE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"LogRenderTimeToFile", false),
GFX_OVERLAY_STATS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "OverlayStats", false),
GFX_DUMP_TEXTURES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DumpTextures", false),
GFX_DUMP_MIP_TEXTURES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DumpMipTextures", false),
GFX_DUMP_BASE_TEXTURES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DumpBaseTextures",
false),
GFX_HIRES_TEXTURES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "HiresTextures", false),
GFX_CACHE_HIRES_TEXTURES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "CacheHiresTextures",
false),
GFX_DUMP_EFB_TARGET(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DumpEFBTarget", false),
GFX_DUMP_XFB_TARGET(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DumpXFBTarget", false),
GFX_INTERNAL_RESOLUTION_FRAME_DUMPS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"InternalResolutionFrameDumps", false),
GFX_ENABLE_GPU_TEXTURE_DECODING(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"EnableGPUTextureDecoding", false),
GFX_ENABLE_PIXEL_LIGHTING(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"EnablePixelLighting", false),
GFX_FAST_DEPTH_CALC(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "FastDepthCalc", true),
GFX_TEXFMT_OVERLAY_ENABLE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "TexFmtOverlayEnable",
false),
GFX_ENABLE_WIREFRAME(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "WireFrame", false),
GFX_DISABLE_FOG(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DisableFog", false),
GFX_ENABLE_VALIDATION_LAYER(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"EnableValidationLayer", false),
GFX_BACKEND_MULTITHREADING(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"BackendMultithreading", true),
GFX_WAIT_FOR_SHADERS_BEFORE_STARTING(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"WaitForShadersBeforeStarting", false),
GFX_SAVE_TEXTURE_CACHE_TO_STATE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"SaveTextureCacheToState", true),
GFX_PREFER_VS_FOR_LINE_POINT_EXPANSION(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"PreferVSForLinePointExpansion", false),
GFX_CPU_CULL(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "CPUCull", false),
GFX_MODS_ENABLE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "EnableMods", false),
GFX_ENHANCE_FORCE_TRUE_COLOR(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS,
"ForceTrueColor", true),
GFX_ENHANCE_DISABLE_COPY_FILTER(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS,
"DisableCopyFilter", true),
GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS,
"ArbitraryMipmapDetection", true),
GFX_STEREO_SWAP_EYES(Settings.FILE_GFX, Settings.SECTION_STEREOSCOPY, "StereoSwapEyes", false),
GFX_HACK_EFB_ACCESS_ENABLE(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "EFBAccessEnable",
true),
GFX_HACK_EFB_DEFER_INVALIDATION(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS,
"EFBAccessDeferInvalidation", false),
GFX_HACK_BBOX_ENABLE(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "BBoxEnable", false),
GFX_HACK_SKIP_EFB_COPY_TO_RAM(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS,
"EFBToTextureEnable", true),
GFX_HACK_SKIP_XFB_COPY_TO_RAM(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS,
"XFBToTextureEnable", true),
GFX_HACK_DISABLE_COPY_TO_VRAM(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "DisableCopyToVRAM",
false),
GFX_HACK_DEFER_EFB_COPIES(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "DeferEFBCopies", true),
GFX_HACK_IMMEDIATE_XFB(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "ImmediateXFBEnable",
false),
GFX_HACK_SKIP_DUPLICATE_XFBS(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "SkipDuplicateXFBs",
true),
GFX_HACK_COPY_EFB_SCALED(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "EFBScaledCopy", true),
GFX_HACK_EFB_EMULATE_FORMAT_CHANGES(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS,
"EFBEmulateFormatChanges", false),
GFX_HACK_VERTEX_ROUNDING(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "VertexRounding", false),
GFX_HACK_VI_SKIP(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "VISkip", false),
GFX_HACK_FAST_TEXTURE_SAMPLING(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS,
"FastTextureSampling", true),
LOGGER_WRITE_TO_FILE(Settings.FILE_LOGGER, Settings.SECTION_LOGGER_OPTIONS, "WriteToFile", false);
private static final BooleanSetting[] NOT_RUNTIME_EDITABLE_ARRAY = new BooleanSetting[]{
MAIN_DSP_HLE,
MAIN_CPU_THREAD,
MAIN_ENABLE_CHEATS,
MAIN_OVERRIDE_REGION_SETTINGS,
MAIN_MMU,
MAIN_PAUSE_ON_PANIC,
MAIN_ACCURATE_CPU_CACHE,
MAIN_RAM_OVERRIDE_ENABLE,
MAIN_CUSTOM_RTC_ENABLE,
MAIN_DSP_JIT,
MAIN_EMULATE_SKYLANDER_PORTAL,
};
private static final Set<BooleanSetting> NOT_RUNTIME_EDITABLE =
new HashSet<>(Arrays.asList(NOT_RUNTIME_EDITABLE_ARRAY));
private final String mFile;
private final String mSection;
private final String mKey;
private final boolean mDefaultValue;
BooleanSetting(String file, String section, String key, boolean defaultValue)
{
mFile = file;
mSection = section;
mKey = key;
mDefaultValue = defaultValue;
}
@Override
public boolean isOverridden()
{
return NativeConfig.isOverridden(mFile, mSection, mKey);
}
@Override
public boolean isRuntimeEditable()
{
if (mFile.equals(Settings.FILE_SYSCONF))
return false;
for (BooleanSetting setting : NOT_RUNTIME_EDITABLE)
{
if (setting == this)
return false;
}
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
}
@Override
public boolean delete(@NonNull Settings settings)
{
if (!NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
throw new UnsupportedOperationException(
"Unsupported setting: " + mFile + ", " + mSection + ", " + mKey);
}
return NativeConfig.deleteKey(settings.getWriteLayer(), mFile, mSection, mKey);
}
@Override
public boolean getBoolean()
{
return NativeConfig.getBoolean(NativeConfig.LAYER_ACTIVE, mFile, mSection, mKey, mDefaultValue);
}
@Override
public void setBoolean(@NonNull Settings settings, boolean newValue)
{
if (!NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
throw new UnsupportedOperationException(
"Unsupported setting: " + mFile + ", " + mSection + ", " + mKey);
}
NativeConfig.setBoolean(settings.getWriteLayer(), mFile, mSection, mKey, newValue);
}
public void setBoolean(int layer, boolean newValue)
{
if (!NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
throw new UnsupportedOperationException(
"Unsupported setting: " + mFile + ", " + mSection + ", " + mKey);
}
NativeConfig.setBoolean(layer, mFile, mSection, mKey, newValue);
}
public static BooleanSetting getSettingForAdapterRumble(int channel)
{
return new BooleanSetting[]{MAIN_ADAPTER_RUMBLE_0, MAIN_ADAPTER_RUMBLE_1, MAIN_ADAPTER_RUMBLE_2,
MAIN_ADAPTER_RUMBLE_3}[channel];
}
public static BooleanSetting getSettingForSimulateKonga(int channel)
{
return new BooleanSetting[]{MAIN_SIMULATE_KONGA_0, MAIN_SIMULATE_KONGA_1, MAIN_SIMULATE_KONGA_2,
MAIN_SIMULATE_KONGA_3}[channel];
}
}

View File

@ -0,0 +1,747 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
import java.util.*
enum class BooleanSetting(
private val file: String,
private val section: String,
private val key: String,
private val defaultValue: Boolean
) : AbstractBooleanSetting {
// These entries have the same names and order as in C++, just for consistency.
MAIN_SKIP_IPL(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SkipIPL", true),
MAIN_DSP_HLE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "DSPHLE", true),
MAIN_FASTMEM(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "Fastmem", true),
MAIN_CPU_THREAD(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "CPUThread", true),
MAIN_SYNC_ON_SKIP_IDLE(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"SyncOnSkipIdle",
true
),
MAIN_ENABLE_CHEATS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EnableCheats", false),
MAIN_OVERRIDE_REGION_SETTINGS(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"OverrideRegionSettings",
false
),
MAIN_AUDIO_STRETCH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AudioStretch", false),
MAIN_BBA_XLINK_CHAT_OSD(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"BBA_XLINK_CHAT_OSD",
false
),
MAIN_ADAPTER_RUMBLE_0(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AdapterRumble0", true),
MAIN_ADAPTER_RUMBLE_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AdapterRumble1", true),
MAIN_ADAPTER_RUMBLE_2(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AdapterRumble2", true),
MAIN_ADAPTER_RUMBLE_3(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "AdapterRumble3", true),
MAIN_SIMULATE_KONGA_0(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"SimulateKonga0",
false
),
MAIN_SIMULATE_KONGA_1(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"SimulateKonga1",
false
),
MAIN_SIMULATE_KONGA_2(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"SimulateKonga2",
false
),
MAIN_SIMULATE_KONGA_3(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"SimulateKonga3",
false
),
MAIN_WII_SD_CARD(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "WiiSDCard", true),
MAIN_WII_SD_CARD_ENABLE_FOLDER_SYNC(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"WiiSDCardEnableFolderSync",
false
),
MAIN_WIIMOTE_CONTINUOUS_SCANNING(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"WiimoteContinuousScanning",
false
),
MAIN_WIIMOTE_ENABLE_SPEAKER(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"WiimoteEnableSpeaker",
false
),
MAIN_MMU(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "MMU", false),
MAIN_PAUSE_ON_PANIC(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "PauseOnPanic", false),
MAIN_ACCURATE_CPU_CACHE(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"AccurateCPUCache",
false
),
MAIN_SYNC_GPU(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SyncGPU", false),
MAIN_FAST_DISC_SPEED(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "FastDiscSpeed", false),
MAIN_OVERCLOCK_ENABLE(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"OverclockEnable",
false
),
MAIN_RAM_OVERRIDE_ENABLE(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"RAMOverrideEnable",
false
),
MAIN_CUSTOM_RTC_ENABLE(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"EnableCustomRTC",
false
),
MAIN_AUTO_DISC_CHANGE(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"AutoDiscChange",
false
),
MAIN_ALLOW_SD_WRITES(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"WiiSDCardAllowWrites",
true
),
MAIN_ENABLE_SAVESTATES(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"EnableSaveStates",
false
),
MAIN_DSP_JIT(Settings.FILE_DOLPHIN, Settings.SECTION_INI_DSP, "EnableJIT", true),
MAIN_EXPAND_TO_CUTOUT_AREA(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_INTERFACE,
"ExpandToCutoutArea",
false
),
MAIN_USE_PANIC_HANDLERS(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_INTERFACE,
"UsePanicHandlers",
true
),
MAIN_OSD_MESSAGES(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_INTERFACE,
"OnScreenDisplayMessages",
true
),
MAIN_ANALYTICS_ENABLED(Settings.FILE_DOLPHIN, Settings.SECTION_ANALYTICS, "Enabled", false),
MAIN_ANALYTICS_PERMISSION_ASKED(
Settings.FILE_DOLPHIN,
Settings.SECTION_ANALYTICS,
"PermissionAsked",
false
),
MAIN_RECURSIVE_ISO_PATHS(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_GENERAL,
"RecursiveISOPaths",
false
),
MAIN_USE_GAME_COVERS(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_GENERAL,
"UseGameCovers",
true
),
MAIN_DEBUG_JIT_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitOff", false),
MAIN_DEBUG_JIT_LOAD_STORE_OFF(
Settings.FILE_DOLPHIN,
Settings.SECTION_DEBUG,
"JitLoadStoreOff",
false
),
MAIN_DEBUG_JIT_LOAD_STORE_FLOATING_OFF(
Settings.FILE_DOLPHIN,
Settings.SECTION_DEBUG,
"JitLoadStoreFloatingOff",
false
),
MAIN_DEBUG_JIT_LOAD_STORE_PAIRED_OFF(
Settings.FILE_DOLPHIN,
Settings.SECTION_DEBUG,
"JitLoadStorePairedOff",
false
),
MAIN_DEBUG_JIT_FLOATING_POINT_OFF(
Settings.FILE_DOLPHIN,
Settings.SECTION_DEBUG,
"JitFloatingPointOff",
false
),
MAIN_DEBUG_JIT_INTEGER_OFF(
Settings.FILE_DOLPHIN,
Settings.SECTION_DEBUG,
"JitIntegerOff",
false
),
MAIN_DEBUG_JIT_PAIRED_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitPairedOff", false),
MAIN_DEBUG_JIT_SYSTEM_REGISTERS_OFF(
Settings.FILE_DOLPHIN,
Settings.SECTION_DEBUG,
"JitSystemRegistersOff",
false
),
MAIN_DEBUG_JIT_BRANCH_OFF(Settings.FILE_DOLPHIN, Settings.SECTION_DEBUG, "JitBranchOff", false),
MAIN_DEBUG_JIT_REGISTER_CACHE_OFF(
Settings.FILE_DOLPHIN,
Settings.SECTION_DEBUG,
"JitRegisterCacheOff",
false
),
MAIN_EMULATE_SKYLANDER_PORTAL(
Settings.FILE_DOLPHIN,
Settings.SECTION_EMULATED_USB_DEVICES,
"EmulateSkylanderPortal",
false
),
MAIN_SHOW_GAME_TITLES(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID,
"ShowGameTitles",
true
),
MAIN_USE_BLACK_BACKGROUNDS(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID,
"UseBlackBackgrounds",
false
),
MAIN_JOYSTICK_REL_CENTER(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID,
"JoystickRelCenter",
true
),
MAIN_SHOW_INPUT_OVERLAY(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID,
"ShowInputOverlay",
true
),
MAIN_IR_ALWAYS_RECENTER(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID,
"IRAlwaysRecenter",
false
),
MAIN_BUTTON_TOGGLE_GC_0(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonA",
true
),
MAIN_BUTTON_TOGGLE_GC_1(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonB",
true
),
MAIN_BUTTON_TOGGLE_GC_2(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonX",
true
),
MAIN_BUTTON_TOGGLE_GC_3(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonY",
true
),
MAIN_BUTTON_TOGGLE_GC_4(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonZ",
true
),
MAIN_BUTTON_TOGGLE_GC_5(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCButtonStart",
true
),
MAIN_BUTTON_TOGGLE_GC_6(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCTriggerL",
true
),
MAIN_BUTTON_TOGGLE_GC_7(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCTriggerR",
true
),
MAIN_BUTTON_TOGGLE_GC_8(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCDPad",
true
),
MAIN_BUTTON_TOGGLE_GC_9(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCStickMain",
true
),
MAIN_BUTTON_TOGGLE_GC_10(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleGCStickC",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_0(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonA",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_1(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonB",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_2(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonX",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_3(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonY",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_4(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonPlus",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_5(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonMinus",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_6(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonHome",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_7(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicTriggerL",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_8(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicTriggerR",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_9(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonZL",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_10(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicButtonZR",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_11(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicDPad",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_12(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicStickLeft",
true
),
MAIN_BUTTON_TOGGLE_CLASSIC_13(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleClassicStickRight",
true
),
MAIN_BUTTON_TOGGLE_WII_0(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButtonA",
true
),
MAIN_BUTTON_TOGGLE_WII_1(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButtonB",
true
),
MAIN_BUTTON_TOGGLE_WII_2(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButton1",
true
),
MAIN_BUTTON_TOGGLE_WII_3(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButton2",
true
),
MAIN_BUTTON_TOGGLE_WII_4(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButtonPlus",
true
),
MAIN_BUTTON_TOGGLE_WII_5(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButtonMinus",
true
),
MAIN_BUTTON_TOGGLE_WII_6(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteButtonHome",
true
),
MAIN_BUTTON_TOGGLE_WII_7(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleWiimoteDPad",
true
),
MAIN_BUTTON_TOGGLE_WII_8(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleNunchukC",
true
),
MAIN_BUTTON_TOGGLE_WII_9(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleNunchukZ",
true
),
MAIN_BUTTON_TOGGLE_WII_10(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"ButtonToggleNunchukStick",
true
),
SYSCONF_SCREENSAVER(Settings.FILE_SYSCONF, "IPL", "SSV", false),
SYSCONF_WIDESCREEN(Settings.FILE_SYSCONF, "IPL", "AR", true),
SYSCONF_PROGRESSIVE_SCAN(Settings.FILE_SYSCONF, "IPL", "PGS", true),
SYSCONF_PAL60(Settings.FILE_SYSCONF, "IPL", "E60", true),
SYSCONF_WIIMOTE_MOTOR(Settings.FILE_SYSCONF, "BT", "MOT", true),
GFX_WIDESCREEN_HACK(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "wideScreenHack", false),
GFX_CROP(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "Crop", false),
GFX_SHOW_FPS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowFPS", false),
GFX_SHOW_FTIMES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowFTimes", false),
GFX_SHOW_VPS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowVPS", false),
GFX_SHOW_VTIMES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowVTimes", false),
GFX_SHOW_GRAPHS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowGraphs", false),
GFX_SHOW_SPEED(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "ShowSpeed", false),
GFX_SHOW_SPEED_COLORS(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"ShowSpeedColors",
true
),
GFX_LOG_RENDER_TIME_TO_FILE(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"LogRenderTimeToFile",
false
),
GFX_OVERLAY_STATS(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "OverlayStats", false),
GFX_DUMP_TEXTURES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DumpTextures", false),
GFX_DUMP_MIP_TEXTURES(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"DumpMipTextures",
false
),
GFX_DUMP_BASE_TEXTURES(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"DumpBaseTextures",
false
),
GFX_HIRES_TEXTURES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "HiresTextures", false),
GFX_CACHE_HIRES_TEXTURES(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"CacheHiresTextures",
false
),
GFX_DUMP_EFB_TARGET(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DumpEFBTarget", false),
GFX_DUMP_XFB_TARGET(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DumpXFBTarget", false),
GFX_INTERNAL_RESOLUTION_FRAME_DUMPS(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"InternalResolutionFrameDumps",
false
),
GFX_ENABLE_GPU_TEXTURE_DECODING(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"EnableGPUTextureDecoding",
false
),
GFX_ENABLE_PIXEL_LIGHTING(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"EnablePixelLighting",
false
),
GFX_FAST_DEPTH_CALC(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "FastDepthCalc", true),
GFX_TEXFMT_OVERLAY_ENABLE(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"TexFmtOverlayEnable",
false
),
GFX_ENABLE_WIREFRAME(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "WireFrame", false),
GFX_DISABLE_FOG(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "DisableFog", false),
GFX_ENABLE_VALIDATION_LAYER(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"EnableValidationLayer",
false
),
GFX_BACKEND_MULTITHREADING(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"BackendMultithreading",
true
),
GFX_WAIT_FOR_SHADERS_BEFORE_STARTING(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"WaitForShadersBeforeStarting",
false
),
GFX_SAVE_TEXTURE_CACHE_TO_STATE(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"SaveTextureCacheToState",
true
),
GFX_PREFER_VS_FOR_LINE_POINT_EXPANSION(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"PreferVSForLinePointExpansion",
false
),
GFX_CPU_CULL(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "CPUCull", false),
GFX_MODS_ENABLE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "EnableMods", false),
GFX_ENHANCE_FORCE_TRUE_COLOR(
Settings.FILE_GFX,
Settings.SECTION_GFX_ENHANCEMENTS,
"ForceTrueColor",
true
),
GFX_ENHANCE_DISABLE_COPY_FILTER(
Settings.FILE_GFX,
Settings.SECTION_GFX_ENHANCEMENTS,
"DisableCopyFilter",
true
),
GFX_ENHANCE_ARBITRARY_MIPMAP_DETECTION(
Settings.FILE_GFX,
Settings.SECTION_GFX_ENHANCEMENTS,
"ArbitraryMipmapDetection",
true
),
GFX_STEREO_SWAP_EYES(Settings.FILE_GFX, Settings.SECTION_STEREOSCOPY, "StereoSwapEyes", false),
GFX_HACK_EFB_ACCESS_ENABLE(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"EFBAccessEnable",
true
),
GFX_HACK_EFB_DEFER_INVALIDATION(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"EFBAccessDeferInvalidation",
false
),
GFX_HACK_BBOX_ENABLE(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "BBoxEnable", false),
GFX_HACK_SKIP_EFB_COPY_TO_RAM(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"EFBToTextureEnable",
true
),
GFX_HACK_SKIP_XFB_COPY_TO_RAM(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"XFBToTextureEnable",
true
),
GFX_HACK_DISABLE_COPY_TO_VRAM(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"DisableCopyToVRAM",
false
),
GFX_HACK_DEFER_EFB_COPIES(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"DeferEFBCopies",
true
),
GFX_HACK_IMMEDIATE_XFB(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"ImmediateXFBEnable",
false
),
GFX_HACK_SKIP_DUPLICATE_XFBS(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"SkipDuplicateXFBs",
true
),
GFX_HACK_COPY_EFB_SCALED(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "EFBScaledCopy", true),
GFX_HACK_EFB_EMULATE_FORMAT_CHANGES(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"EFBEmulateFormatChanges",
false
),
GFX_HACK_VERTEX_ROUNDING(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"VertexRounding",
false
),
GFX_HACK_VI_SKIP(Settings.FILE_GFX, Settings.SECTION_GFX_HACKS, "VISkip", false),
GFX_HACK_FAST_TEXTURE_SAMPLING(
Settings.FILE_GFX,
Settings.SECTION_GFX_HACKS,
"FastTextureSampling",
true
),
LOGGER_WRITE_TO_FILE(
Settings.FILE_LOGGER,
Settings.SECTION_LOGGER_OPTIONS,
"WriteToFile",
false
);
override val isOverridden: Boolean
get() = NativeConfig.isOverridden(file, section, key)
override val isRuntimeEditable: Boolean
get() {
if (file == Settings.FILE_SYSCONF) return false
for (setting in NOT_RUNTIME_EDITABLE) {
if (setting == this) return false
}
return NativeConfig.isSettingSaveable(file, section, key)
}
override fun delete(settings: Settings): Boolean {
if (!NativeConfig.isSettingSaveable(file, section, key)) {
throw UnsupportedOperationException("Unsupported setting: $file, $section, $key")
}
return NativeConfig.deleteKey(settings.writeLayer, file, section, key)
}
override val boolean: Boolean
get() = NativeConfig.getBoolean(
NativeConfig.LAYER_ACTIVE,
file,
section,
key,
defaultValue
)
override fun setBoolean(settings: Settings, newValue: Boolean) {
if (!NativeConfig.isSettingSaveable(file, section, key)) {
throw UnsupportedOperationException("Unsupported setting: $file, $section, $key")
}
NativeConfig.setBoolean(settings.writeLayer, file, section, key, newValue)
}
fun setBoolean(layer: Int, newValue: Boolean) {
if (!NativeConfig.isSettingSaveable(file, section, key)) {
throw UnsupportedOperationException("Unsupported setting: $file, $section, $key")
}
NativeConfig.setBoolean(layer, file, section, key, newValue)
}
companion object {
private val NOT_RUNTIME_EDITABLE_ARRAY = arrayOf(
MAIN_DSP_HLE,
MAIN_CPU_THREAD,
MAIN_ENABLE_CHEATS,
MAIN_OVERRIDE_REGION_SETTINGS,
MAIN_MMU,
MAIN_PAUSE_ON_PANIC,
MAIN_ACCURATE_CPU_CACHE,
MAIN_RAM_OVERRIDE_ENABLE,
MAIN_CUSTOM_RTC_ENABLE,
MAIN_DSP_JIT,
MAIN_EMULATE_SKYLANDER_PORTAL
)
private val NOT_RUNTIME_EDITABLE: Set<BooleanSetting> =
HashSet(listOf(*NOT_RUNTIME_EDITABLE_ARRAY))
@JvmStatic
fun getSettingForAdapterRumble(channel: Int): BooleanSetting {
return arrayOf(
MAIN_ADAPTER_RUMBLE_0,
MAIN_ADAPTER_RUMBLE_1,
MAIN_ADAPTER_RUMBLE_2,
MAIN_ADAPTER_RUMBLE_3
)[channel]
}
@JvmStatic
fun getSettingForSimulateKonga(channel: Int): BooleanSetting {
return arrayOf(
MAIN_SIMULATE_KONGA_0,
MAIN_SIMULATE_KONGA_1,
MAIN_SIMULATE_KONGA_2,
MAIN_SIMULATE_KONGA_3
)[channel]
}
}
}

View File

@ -1,73 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import androidx.annotation.NonNull;
public enum FloatSetting implements AbstractFloatSetting
{
// These entries have the same names and order as in C++, just for consistency.
MAIN_EMULATION_SPEED(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EmulationSpeed", 1.0f),
MAIN_OVERCLOCK(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "Overclock", 1.0f);
private final String mFile;
private final String mSection;
private final String mKey;
private final float mDefaultValue;
FloatSetting(String file, String section, String key, float defaultValue)
{
mFile = file;
mSection = section;
mKey = key;
mDefaultValue = defaultValue;
}
@Override
public boolean isOverridden()
{
return NativeConfig.isOverridden(mFile, mSection, mKey);
}
@Override
public boolean isRuntimeEditable()
{
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
}
@Override
public boolean delete(@NonNull Settings settings)
{
if (!NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
throw new UnsupportedOperationException(
"Unsupported setting: " + mFile + ", " + mSection + ", " + mKey);
}
return NativeConfig.deleteKey(settings.getWriteLayer(), mFile, mSection, mKey);
}
@Override
public float getFloat()
{
return NativeConfig.getFloat(NativeConfig.LAYER_ACTIVE, mFile, mSection, mKey, mDefaultValue);
}
@Override
public void setFloat(@NonNull Settings settings, float newValue)
{
if (!NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
throw new UnsupportedOperationException(
"Unsupported setting: " + mFile + ", " + mSection + ", " + mKey);
}
NativeConfig.setFloat(settings.getWriteLayer(), mFile, mSection, mKey, newValue);
}
public void setFloat(int layer, float newValue)
{
NativeConfig.setFloat(layer, mFile, mSection, mKey, newValue);
}
}

View File

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
enum class FloatSetting(
private val file: String,
private val section: String,
private val key: String,
private val defaultValue: Float
) : AbstractFloatSetting {
// These entries have the same names and order as in C++, just for consistency.
MAIN_EMULATION_SPEED(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "EmulationSpeed", 1.0f),
MAIN_OVERCLOCK(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "Overclock", 1.0f);
override val isOverridden: Boolean
get() = NativeConfig.isOverridden(file, section, key)
override val isRuntimeEditable: Boolean
get() = NativeConfig.isSettingSaveable(file, section, key)
override fun delete(settings: Settings): Boolean {
if (!NativeConfig.isSettingSaveable(file, section, key)) {
throw UnsupportedOperationException("Unsupported setting: $file, $section, $key")
}
return NativeConfig.deleteKey(settings.writeLayer, file, section, key)
}
override val float: Float
get() = NativeConfig.getFloat(NativeConfig.LAYER_ACTIVE, file, section, key, defaultValue)
override fun setFloat(settings: Settings, newValue: Float) {
if (!NativeConfig.isSettingSaveable(file, section, key)) {
throw UnsupportedOperationException("Unsupported setting: $file, $section, $key")
}
NativeConfig.setFloat(settings.writeLayer, file, section, key, newValue)
}
fun setFloat(layer: Int, newValue: Float) {
NativeConfig.setFloat(layer, file, section, key, newValue)
}
}

View File

@ -1,196 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import android.content.pm.ActivityInfo;
import androidx.annotation.NonNull;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.overlay.InputOverlayPointer;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public enum IntSetting implements AbstractIntSetting
{
// These entries have the same names and order as in C++, just for consistency.
MAIN_CPU_CORE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "CPUCore",
NativeLibrary.DefaultCPUCore()),
MAIN_GC_LANGUAGE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SelectedLanguage", 0),
MAIN_MEM1_SIZE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "MEM1Size", 0x01800000),
MAIN_MEM2_SIZE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "MEM2Size", 0x04000000),
MAIN_SLOT_A(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SlotA", 8),
MAIN_SLOT_B(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SlotB", 255),
MAIN_SERIAL_PORT_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SerialPort1", 255),
MAIN_FALLBACK_REGION(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "FallbackRegion", 2),
MAIN_SI_DEVICE_0(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SIDevice0", 6),
MAIN_SI_DEVICE_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SIDevice1", 0),
MAIN_SI_DEVICE_2(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SIDevice2", 0),
MAIN_SI_DEVICE_3(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SIDevice3", 0),
MAIN_AUDIO_VOLUME(Settings.FILE_DOLPHIN, Settings.SECTION_INI_DSP, "Volume", 100),
MAIN_OVERLAY_GC_CONTROLLER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID,
"OverlayGCController", 0), // Defaults to GameCube controller 1
MAIN_OVERLAY_WII_CONTROLLER(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID,
"OverlayWiiController", 4), // Defaults to Wii Remote 1
MAIN_CONTROL_SCALE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "ControlScale", 50),
MAIN_CONTROL_OPACITY(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "ControlOpacity", 65),
MAIN_EMULATION_ORIENTATION(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID,
"EmulationOrientation", ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE),
MAIN_INTERFACE_THEME(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "InterfaceTheme", 0),
MAIN_INTERFACE_THEME_MODE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID,
"InterfaceThemeMode", -1),
MAIN_LAST_PLATFORM_TAB(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "LastPlatformTab", 0),
MAIN_IR_MODE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "IRMode",
InputOverlayPointer.MODE_FOLLOW),
MAIN_DOUBLE_TAP_BUTTON(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"DoubleTapButton", NativeLibrary.ButtonType.WIIMOTE_BUTTON_A),
SYSCONF_LANGUAGE(Settings.FILE_SYSCONF, "IPL", "LNG", 0x01),
SYSCONF_SOUND_MODE(Settings.FILE_SYSCONF, "IPL", "SND", 0x01),
SYSCONF_SENSOR_BAR_POSITION(Settings.FILE_SYSCONF, "BT", "BAR", 0x01),
SYSCONF_SENSOR_BAR_SENSITIVITY(Settings.FILE_SYSCONF, "BT", "SENS", 0x03),
SYSCONF_SPEAKER_VOLUME(Settings.FILE_SYSCONF, "BT", "SPKV", 0x58),
GFX_ASPECT_RATIO(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "AspectRatio", 0),
GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"SafeTextureCacheColorSamples", 128),
GFX_PNG_COMPRESSION_LEVEL(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "PNGCompressionLevel",
6),
GFX_MSAA(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "MSAA", 1),
GFX_EFB_SCALE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "InternalResolution", 1),
GFX_SHADER_COMPILATION_MODE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS,
"ShaderCompilationMode", 0),
GFX_ENHANCE_FORCE_TEXTURE_FILTERING(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS,
"ForceTextureFiltering", 0),
GFX_ENHANCE_MAX_ANISOTROPY(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS, "MaxAnisotropy",
0),
GFX_STEREO_MODE(Settings.FILE_GFX, Settings.SECTION_STEREOSCOPY, "StereoMode", 0),
GFX_STEREO_DEPTH(Settings.FILE_GFX, Settings.SECTION_STEREOSCOPY, "StereoDepth", 20),
GFX_STEREO_CONVERGENCE_PERCENTAGE(Settings.FILE_GFX, Settings.SECTION_STEREOSCOPY,
"StereoConvergencePercentage", 100),
GFX_PERF_SAMP_WINDOW(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "PerfSampWindowMS", 1000),
LOGGER_VERBOSITY(Settings.FILE_LOGGER, Settings.SECTION_LOGGER_OPTIONS, "Verbosity", 1),
WIIMOTE_1_SOURCE(Settings.FILE_WIIMOTE, "Wiimote1", "Source", 1),
WIIMOTE_2_SOURCE(Settings.FILE_WIIMOTE, "Wiimote2", "Source", 0),
WIIMOTE_3_SOURCE(Settings.FILE_WIIMOTE, "Wiimote3", "Source", 0),
WIIMOTE_4_SOURCE(Settings.FILE_WIIMOTE, "Wiimote4", "Source", 0),
WIIMOTE_BB_SOURCE(Settings.FILE_WIIMOTE, "BalanceBoard", "Source", 0);
private static final IntSetting[] NOT_RUNTIME_EDITABLE_ARRAY = new IntSetting[]{
MAIN_CPU_CORE,
MAIN_GC_LANGUAGE,
MAIN_MEM1_SIZE,
MAIN_MEM2_SIZE,
MAIN_SLOT_A, // Can actually be changed, but specific code is required
MAIN_SLOT_B, // Can actually be changed, but specific code is required
MAIN_SERIAL_PORT_1,
MAIN_FALLBACK_REGION,
MAIN_SI_DEVICE_0, // Can actually be changed, but specific code is required
MAIN_SI_DEVICE_1, // Can actually be changed, but specific code is required
MAIN_SI_DEVICE_2, // Can actually be changed, but specific code is required
MAIN_SI_DEVICE_3, // Can actually be changed, but specific code is required
};
private static final Set<IntSetting> NOT_RUNTIME_EDITABLE =
new HashSet<>(Arrays.asList(NOT_RUNTIME_EDITABLE_ARRAY));
private final String mFile;
private final String mSection;
private final String mKey;
private final int mDefaultValue;
IntSetting(String file, String section, String key, int defaultValue)
{
mFile = file;
mSection = section;
mKey = key;
mDefaultValue = defaultValue;
}
@Override
public boolean isOverridden()
{
return NativeConfig.isOverridden(mFile, mSection, mKey);
}
@Override
public boolean isRuntimeEditable()
{
if (mFile.equals(Settings.FILE_SYSCONF))
return false;
for (IntSetting setting : NOT_RUNTIME_EDITABLE)
{
if (setting == this)
return false;
}
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
}
@Override
public boolean delete(@NonNull Settings settings)
{
if (!NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
throw new UnsupportedOperationException(
"Unsupported setting: " + mFile + ", " + mSection + ", " + mKey);
}
return NativeConfig.deleteKey(settings.getWriteLayer(), mFile, mSection, mKey);
}
@Override
public int getInt()
{
return NativeConfig.getInt(NativeConfig.LAYER_ACTIVE, mFile, mSection, mKey, mDefaultValue);
}
@Override
public void setInt(@NonNull Settings settings, int newValue)
{
if (!NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
throw new UnsupportedOperationException(
"Unsupported setting: " + mFile + ", " + mSection + ", " + mKey);
}
NativeConfig.setInt(settings.getWriteLayer(), mFile, mSection, mKey, newValue);
}
public void setInt(int layer, int newValue)
{
if (!NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
throw new UnsupportedOperationException(
"Unsupported setting: " + mFile + ", " + mSection + ", " + mKey);
}
NativeConfig.setInt(layer, mFile, mSection, mKey, newValue);
}
public static IntSetting getSettingForSIDevice(int channel)
{
return new IntSetting[]{MAIN_SI_DEVICE_0, MAIN_SI_DEVICE_1, MAIN_SI_DEVICE_2, MAIN_SI_DEVICE_3}
[channel];
}
public static IntSetting getSettingForWiimoteSource(int index)
{
return new IntSetting[]{WIIMOTE_1_SOURCE, WIIMOTE_2_SOURCE, WIIMOTE_3_SOURCE, WIIMOTE_4_SOURCE,
WIIMOTE_BB_SOURCE}[index];
}
}

View File

@ -0,0 +1,219 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
import android.content.pm.ActivityInfo
import org.dolphinemu.dolphinemu.NativeLibrary
import org.dolphinemu.dolphinemu.overlay.InputOverlayPointer
import java.util.*
enum class IntSetting(
private val file: String,
private val section: String,
private val key: String,
private val defaultValue: Int
) : AbstractIntSetting {
// These entries have the same names and order as in C++, just for consistency.
MAIN_CPU_CORE(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"CPUCore",
NativeLibrary.DefaultCPUCore()
),
MAIN_GC_LANGUAGE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SelectedLanguage", 0),
MAIN_MEM1_SIZE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "MEM1Size", 0x01800000),
MAIN_MEM2_SIZE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "MEM2Size", 0x04000000),
MAIN_SLOT_A(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SlotA", 8),
MAIN_SLOT_B(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SlotB", 255),
MAIN_SERIAL_PORT_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SerialPort1", 255),
MAIN_FALLBACK_REGION(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "FallbackRegion", 2),
MAIN_SI_DEVICE_0(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SIDevice0", 6),
MAIN_SI_DEVICE_1(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SIDevice1", 0),
MAIN_SI_DEVICE_2(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SIDevice2", 0),
MAIN_SI_DEVICE_3(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "SIDevice3", 0),
MAIN_AUDIO_VOLUME(Settings.FILE_DOLPHIN, Settings.SECTION_INI_DSP, "Volume", 100),
MAIN_OVERLAY_GC_CONTROLLER(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID,
"OverlayGCController",
0
),
// Defaults to GameCube controller 1
MAIN_OVERLAY_WII_CONTROLLER(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID,
"OverlayWiiController",
4
),
// Defaults to Wii Remote 1
MAIN_CONTROL_SCALE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "ControlScale", 50),
MAIN_CONTROL_OPACITY(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "ControlOpacity", 65),
MAIN_EMULATION_ORIENTATION(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID,
"EmulationOrientation",
ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE
),
MAIN_INTERFACE_THEME(Settings.FILE_DOLPHIN, Settings.SECTION_INI_ANDROID, "InterfaceTheme", 0),
MAIN_INTERFACE_THEME_MODE(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID,
"InterfaceThemeMode",
-1
),
MAIN_LAST_PLATFORM_TAB(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID,
"LastPlatformTab",
0
),
MAIN_IR_MODE(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID,
"IRMode",
InputOverlayPointer.MODE_FOLLOW
),
MAIN_DOUBLE_TAP_BUTTON(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_ANDROID_OVERLAY_BUTTONS,
"DoubleTapButton",
NativeLibrary.ButtonType.WIIMOTE_BUTTON_A
),
SYSCONF_LANGUAGE(Settings.FILE_SYSCONF, "IPL", "LNG", 0x01),
SYSCONF_SOUND_MODE(Settings.FILE_SYSCONF, "IPL", "SND", 0x01),
SYSCONF_SENSOR_BAR_POSITION(Settings.FILE_SYSCONF, "BT", "BAR", 0x01),
SYSCONF_SENSOR_BAR_SENSITIVITY(Settings.FILE_SYSCONF, "BT", "SENS", 0x03),
SYSCONF_SPEAKER_VOLUME(Settings.FILE_SYSCONF, "BT", "SPKV", 0x58),
GFX_ASPECT_RATIO(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "AspectRatio", 0),
GFX_SAFE_TEXTURE_CACHE_COLOR_SAMPLES(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"SafeTextureCacheColorSamples",
128
),
GFX_PNG_COMPRESSION_LEVEL(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"PNGCompressionLevel",
6
),
GFX_MSAA(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "MSAA", 1),
GFX_EFB_SCALE(Settings.FILE_GFX, Settings.SECTION_GFX_SETTINGS, "InternalResolution", 1),
GFX_SHADER_COMPILATION_MODE(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"ShaderCompilationMode",
0
),
GFX_ENHANCE_FORCE_TEXTURE_FILTERING(
Settings.FILE_GFX,
Settings.SECTION_GFX_ENHANCEMENTS,
"ForceTextureFiltering",
0
),
GFX_ENHANCE_MAX_ANISOTROPY(
Settings.FILE_GFX,
Settings.SECTION_GFX_ENHANCEMENTS,
"MaxAnisotropy",
0
),
GFX_STEREO_MODE(Settings.FILE_GFX, Settings.SECTION_STEREOSCOPY, "StereoMode", 0),
GFX_STEREO_DEPTH(Settings.FILE_GFX, Settings.SECTION_STEREOSCOPY, "StereoDepth", 20),
GFX_STEREO_CONVERGENCE_PERCENTAGE(
Settings.FILE_GFX,
Settings.SECTION_STEREOSCOPY,
"StereoConvergencePercentage",
100
),
GFX_PERF_SAMP_WINDOW(
Settings.FILE_GFX,
Settings.SECTION_GFX_SETTINGS,
"PerfSampWindowMS",
1000
),
LOGGER_VERBOSITY(Settings.FILE_LOGGER, Settings.SECTION_LOGGER_OPTIONS, "Verbosity", 1),
WIIMOTE_1_SOURCE(Settings.FILE_WIIMOTE, "Wiimote1", "Source", 1),
WIIMOTE_2_SOURCE(Settings.FILE_WIIMOTE, "Wiimote2", "Source", 0),
WIIMOTE_3_SOURCE(Settings.FILE_WIIMOTE, "Wiimote3", "Source", 0),
WIIMOTE_4_SOURCE(Settings.FILE_WIIMOTE, "Wiimote4", "Source", 0),
WIIMOTE_BB_SOURCE(Settings.FILE_WIIMOTE, "BalanceBoard", "Source", 0);
override val isOverridden: Boolean
get() = NativeConfig.isOverridden(file, section, key)
override val isRuntimeEditable: Boolean
get() {
if (file == Settings.FILE_SYSCONF) return false
for (setting in NOT_RUNTIME_EDITABLE) {
if (setting == this) return false
}
return NativeConfig.isSettingSaveable(file, section, key)
}
override fun delete(settings: Settings): Boolean {
if (!NativeConfig.isSettingSaveable(file, section, key)) {
throw UnsupportedOperationException("Unsupported setting: $file, $section, $key")
}
return NativeConfig.deleteKey(settings.writeLayer, file, section, key)
}
override val int: Int
get() = NativeConfig.getInt(NativeConfig.LAYER_ACTIVE, file, section, key, defaultValue)
override fun setInt(settings: Settings, newValue: Int) {
if (!NativeConfig.isSettingSaveable(file, section, key)) {
throw UnsupportedOperationException("Unsupported setting: $file, $section, $key")
}
NativeConfig.setInt(settings.writeLayer, file, section, key, newValue)
}
fun setInt(layer: Int, newValue: Int) {
if (!NativeConfig.isSettingSaveable(file, section, key)) {
throw UnsupportedOperationException("Unsupported setting: $file, $section, $key")
}
NativeConfig.setInt(layer, file, section, key, newValue)
}
companion object {
private val NOT_RUNTIME_EDITABLE_ARRAY = arrayOf(
MAIN_CPU_CORE,
MAIN_GC_LANGUAGE,
MAIN_MEM1_SIZE,
MAIN_MEM2_SIZE,
MAIN_SLOT_A,
MAIN_SLOT_B,
MAIN_SERIAL_PORT_1,
MAIN_FALLBACK_REGION,
MAIN_SI_DEVICE_0,
MAIN_SI_DEVICE_1,
MAIN_SI_DEVICE_2,
MAIN_SI_DEVICE_3
)
private val NOT_RUNTIME_EDITABLE: Set<IntSetting> =
HashSet(listOf(*NOT_RUNTIME_EDITABLE_ARRAY))
@JvmStatic
fun getSettingForSIDevice(channel: Int): IntSetting {
return arrayOf(
MAIN_SI_DEVICE_0,
MAIN_SI_DEVICE_1,
MAIN_SI_DEVICE_2,
MAIN_SI_DEVICE_3
)[channel]
}
@JvmStatic
fun getSettingForWiimoteSource(index: Int): IntSetting {
return arrayOf(
WIIMOTE_1_SOURCE,
WIIMOTE_2_SOURCE,
WIIMOTE_3_SOURCE,
WIIMOTE_4_SOURCE,
WIIMOTE_BB_SOURCE
)[index]
}
}
}

View File

@ -1,51 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
public class NativeConfig
{
public static final int LAYER_BASE_OR_CURRENT = 0;
public static final int LAYER_BASE = 1;
public static final int LAYER_LOCAL_GAME = 2;
public static final int LAYER_ACTIVE = 3;
public static final int LAYER_CURRENT = 4;
public static native boolean isSettingSaveable(String file, String section, String key);
public static native void loadGameInis(String gameId, int revision);
public static native void unloadGameInis();
public static native void save(int layer);
public static native void deleteAllKeys(int layer);
public static native boolean isOverridden(String file, String section, String key);
public static native boolean deleteKey(int layer, String file, String section, String key);
public static native boolean exists(int layer, String file, String section, String key);
public static native String getString(int layer, String file, String section, String key,
String defaultValue);
public static native boolean getBoolean(int layer, String file, String section, String key,
boolean defaultValue);
public static native int getInt(int layer, String file, String section, String key,
int defaultValue);
public static native float getFloat(int layer, String file, String section, String key,
float defaultValue);
public static native void setString(int layer, String file, String section, String key,
String value);
public static native void setBoolean(int layer, String file, String section, String key,
boolean value);
public static native void setInt(int layer, String file, String section, String key, int value);
public static native void setFloat(int layer, String file, String section, String key,
float value);
}

View File

@ -0,0 +1,107 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
object NativeConfig {
const val LAYER_BASE_OR_CURRENT = 0
const val LAYER_BASE = 1
const val LAYER_LOCAL_GAME = 2
const val LAYER_ACTIVE = 3
const val LAYER_CURRENT = 4
@JvmStatic
external fun isSettingSaveable(file: String, section: String, key: String): Boolean
@JvmStatic
external fun loadGameInis(gameId: String, revision: Int)
@JvmStatic
external fun unloadGameInis()
@JvmStatic
external fun save(layer: Int)
@JvmStatic
external fun deleteAllKeys(layer: Int)
@JvmStatic
external fun isOverridden(file: String, section: String, key: String): Boolean
@JvmStatic
external fun deleteKey(layer: Int, file: String, section: String, key: String): Boolean
@JvmStatic
external fun exists(layer: Int, file: String, section: String, key: String): Boolean
@JvmStatic
external fun getString(
layer: Int,
file: String,
section: String,
key: String,
defaultValue: String
): String
@JvmStatic
external fun getBoolean(
layer: Int,
file: String,
section: String,
key: String,
defaultValue: Boolean
): Boolean
@JvmStatic
external fun getInt(
layer: Int,
file: String,
section: String,
key: String,
defaultValue: Int
): Int
@JvmStatic
external fun getFloat(
layer: Int,
file: String,
section: String,
key: String,
defaultValue: Float
): Float
@JvmStatic
external fun setString(
layer: Int,
file: String,
section: String,
key: String,
value: String?
)
@JvmStatic
external fun setBoolean(
layer: Int,
file: String,
section: String,
key: String,
value: Boolean
)
@JvmStatic
external fun setInt(
layer: Int,
file: String,
section: String,
key: String,
value: Int
)
@JvmStatic
external fun setFloat(
layer: Int,
file: String,
section: String,
key: String,
value: Float
)
}

View File

@ -1,17 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import androidx.annotation.NonNull;
public class PostProcessing
{
@NonNull
public static native String[] getShaderList();
@NonNull
public static native String[] getAnaglyphShaderList();
@NonNull
public static native String[] getPassiveShaderList();
}

View File

@ -0,0 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
object PostProcessing {
@JvmStatic
val shaderList: Array<String?>
external get
@JvmStatic
val anaglyphShaderList: Array<String?>
external get
@JvmStatic
val passiveShaderList: Array<String?>
external get
}

View File

@ -6,21 +6,18 @@ class ScaledIntSetting(
private val scale: Int, private val scale: Int,
private val setting: AbstractIntSetting private val setting: AbstractIntSetting
) : AbstractIntSetting { ) : AbstractIntSetting {
override fun isOverridden(): Boolean { override val isOverridden: Boolean
return setting.isOverridden() get() = setting.isOverridden
}
override fun isRuntimeEditable(): Boolean { override val isRuntimeEditable: Boolean
return setting.isRuntimeEditable get() = setting.isRuntimeEditable
}
override fun delete(settings: Settings): Boolean { override fun delete(settings: Settings): Boolean {
return setting.delete(settings) return setting.delete(settings)
} }
override fun getInt(): Int { override val int: Int
return setting.getInt() / scale get() = setting.int / scale
}
override fun setInt(settings: Settings, newValue: Int) { override fun setInt(settings: Settings, newValue: Int) {
return setting.setInt(settings, newValue * scale) return setting.setInt(settings, newValue * scale)

View File

@ -1,181 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import android.content.Context;
import android.text.TextUtils;
import android.widget.Toast;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.input.model.MappingCommon;
import org.dolphinemu.dolphinemu.services.GameFileCacheManager;
import java.io.Closeable;
public class Settings implements Closeable
{
public static final String FILE_DOLPHIN = "Dolphin";
public static final String FILE_SYSCONF = "SYSCONF";
public static final String FILE_GFX = "GFX";
public static final String FILE_LOGGER = "Logger";
public static final String FILE_WIIMOTE = "WiimoteNew";
public static final String FILE_GAME_SETTINGS_ONLY = "GameSettingsOnly";
public static final String SECTION_INI_ANDROID = "Android";
public static final String SECTION_INI_ANDROID_OVERLAY_BUTTONS = "AndroidOverlayButtons";
public static final String SECTION_INI_GENERAL = "General";
public static final String SECTION_INI_CORE = "Core";
public static final String SECTION_INI_INTERFACE = "Interface";
public static final String SECTION_INI_DSP = "DSP";
public static final String SECTION_LOGGER_LOGS = "Logs";
public static final String SECTION_LOGGER_OPTIONS = "Options";
public static final String SECTION_GFX_SETTINGS = "Settings";
public static final String SECTION_GFX_ENHANCEMENTS = "Enhancements";
public static final String SECTION_GFX_HACKS = "Hacks";
public static final String SECTION_DEBUG = "Debug";
public static final String SECTION_EMULATED_USB_DEVICES = "EmulatedUSBDevices";
public static final String SECTION_STEREOSCOPY = "Stereoscopy";
public static final String SECTION_BINDINGS = "Android";
public static final String SECTION_PROFILE = "Profile";
public static final String SECTION_ANALYTICS = "Analytics";
private String mGameId;
private int mRevision;
private boolean mIsWii;
private boolean mSettingsLoaded = false;
private boolean mLoadedRecursiveIsoPathsValue = false;
public boolean isGameSpecific()
{
return !TextUtils.isEmpty(mGameId);
}
public boolean isWii()
{
return mIsWii;
}
public int getWriteLayer()
{
return isGameSpecific() ? NativeConfig.LAYER_LOCAL_GAME : NativeConfig.LAYER_BASE_OR_CURRENT;
}
public boolean areSettingsLoaded()
{
return mSettingsLoaded;
}
public void loadSettings()
{
// The value of isWii doesn't matter if we don't have any SettingsActivity
loadSettings(true);
}
public void loadSettings(boolean isWii)
{
mIsWii = isWii;
mSettingsLoaded = true;
if (isGameSpecific())
{
// Loading game INIs while the core is running will mess with the game INIs loaded by the core
if (NativeLibrary.IsRunning())
throw new IllegalStateException("Attempted to load game INI while emulating");
NativeConfig.loadGameInis(mGameId, mRevision);
}
mLoadedRecursiveIsoPathsValue = BooleanSetting.MAIN_RECURSIVE_ISO_PATHS.getBoolean();
}
public void loadSettings(String gameId, int revision, boolean isWii)
{
mGameId = gameId;
mRevision = revision;
loadSettings(isWii);
}
public void saveSettings(Context context)
{
if (!isGameSpecific())
{
if (context != null)
Toast.makeText(context, R.string.settings_saved, Toast.LENGTH_SHORT).show();
MappingCommon.save();
NativeConfig.save(NativeConfig.LAYER_BASE);
NativeLibrary.ReloadLoggerConfig();
NativeLibrary.UpdateGCAdapterScanThread();
if (mLoadedRecursiveIsoPathsValue != BooleanSetting.MAIN_RECURSIVE_ISO_PATHS.getBoolean())
{
// Refresh game library
GameFileCacheManager.startRescan();
}
}
else
{
// custom game settings
if (context != null)
{
Toast.makeText(context, context.getString(R.string.settings_saved_game_specific, mGameId),
Toast.LENGTH_SHORT).show();
}
NativeConfig.save(NativeConfig.LAYER_LOCAL_GAME);
}
}
public void clearGameSettings()
{
NativeConfig.deleteAllKeys(NativeConfig.LAYER_LOCAL_GAME);
}
public boolean gameIniContainsJunk()
{
// Older versions of Android Dolphin would copy the entire contents of most of the global INIs
// into any game INI that got saved (with some of the sections renamed to match the game INI
// section names). The problems with this are twofold:
//
// 1. The user game INIs will contain entries that Dolphin doesn't support reading from
// game INIs. This is annoying when editing game INIs manually but shouldn't really be
// a problem for those who only use the GUI.
//
// 2. Global settings will stick around in user game INIs. For instance, if someone wants to
// change the texture cache accuracy to safe for all games, they have to edit not only the
// global settings but also every single game INI they have created, since the old value of
// the texture cache accuracy setting has been copied into every user game INI.
//
// These problems are serious enough that we should detect and delete such INI files.
// Problem 1 is easy to detect, but due to the nature of problem 2, it's unfortunately not
// possible to know which lines were added intentionally by the user and which lines were added
// unintentionally, which is why we have to delete the whole file in order to fix everything.
if (!isGameSpecific())
return false;
return NativeConfig.exists(NativeConfig.LAYER_LOCAL_GAME, FILE_DOLPHIN, SECTION_INI_INTERFACE,
"ThemeName");
}
@Override
public void close()
{
if (isGameSpecific())
{
NativeConfig.unloadGameInis();
}
}
}

View File

@ -0,0 +1,144 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
import android.content.Context
import android.text.TextUtils
import android.widget.Toast
import org.dolphinemu.dolphinemu.NativeLibrary
import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.features.input.model.MappingCommon
import org.dolphinemu.dolphinemu.services.GameFileCacheManager
import java.io.Closeable
class Settings : Closeable {
private var gameId: String = ""
private var revision = 0
var isWii = false
private set
private var settingsLoaded = false
private var loadedRecursiveIsoPathsValue = false
private val isGameSpecific: Boolean
get() = !TextUtils.isEmpty(gameId)
val writeLayer: Int
get() = if (isGameSpecific) NativeConfig.LAYER_LOCAL_GAME else NativeConfig.LAYER_BASE_OR_CURRENT
fun areSettingsLoaded(): Boolean {
return settingsLoaded
}
@JvmOverloads
fun loadSettings(isWii: Boolean = true) {
this.isWii = isWii
settingsLoaded = true
if (isGameSpecific) {
// Loading game INIs while the core is running will mess with the game INIs loaded by the core
check(!NativeLibrary.IsRunning()) { "Attempted to load game INI while emulating" }
NativeConfig.loadGameInis(gameId, revision)
}
loadedRecursiveIsoPathsValue = BooleanSetting.MAIN_RECURSIVE_ISO_PATHS.boolean
}
fun loadSettings(gameId: String, revision: Int, isWii: Boolean) {
this.gameId = gameId
this.revision = revision
loadSettings(isWii)
}
fun saveSettings(context: Context?) {
if (!isGameSpecific) {
if (context != null) Toast.makeText(
context,
R.string.settings_saved,
Toast.LENGTH_SHORT
).show()
MappingCommon.save()
NativeConfig.save(NativeConfig.LAYER_BASE)
NativeLibrary.ReloadLoggerConfig()
NativeLibrary.UpdateGCAdapterScanThread()
if (loadedRecursiveIsoPathsValue != BooleanSetting.MAIN_RECURSIVE_ISO_PATHS.boolean) {
// Refresh game library
GameFileCacheManager.startRescan()
}
} else {
// custom game settings
if (context != null) {
Toast.makeText(
context, context.getString(R.string.settings_saved_game_specific, gameId),
Toast.LENGTH_SHORT
).show()
}
NativeConfig.save(NativeConfig.LAYER_LOCAL_GAME)
}
}
fun clearGameSettings() {
NativeConfig.deleteAllKeys(NativeConfig.LAYER_LOCAL_GAME)
}
fun gameIniContainsJunk(): Boolean {
// Older versions of Android Dolphin would copy the entire contents of most of the global INIs
// into any game INI that got saved (with some of the sections renamed to match the game INI
// section names). The problems with this are twofold:
//
// 1. The user game INIs will contain entries that Dolphin doesn't support reading from
// game INIs. This is annoying when editing game INIs manually but shouldn't really be
// a problem for those who only use the GUI.
//
// 2. Global settings will stick around in user game INIs. For instance, if someone wants to
// change the texture cache accuracy to safe for all games, they have to edit not only the
// global settings but also every single game INI they have created, since the old value of
// the texture cache accuracy Setting has been copied into every user game INI.
//
// These problems are serious enough that we should detect and delete such INI files.
// Problem 1 is easy to detect, but due to the nature of problem 2, it's unfortunately not
// possible to know which lines were added intentionally by the user and which lines were added
// unintentionally, which is why we have to delete the whole file in order to fix everything.
return if (!isGameSpecific) false else NativeConfig.exists(
NativeConfig.LAYER_LOCAL_GAME,
FILE_DOLPHIN,
SECTION_INI_INTERFACE,
"ThemeName"
)
}
override fun close() {
if (isGameSpecific) {
NativeConfig.unloadGameInis()
}
}
companion object {
const val FILE_DOLPHIN = "Dolphin"
const val FILE_SYSCONF = "SYSCONF"
const val FILE_GFX = "GFX"
const val FILE_LOGGER = "Logger"
const val FILE_WIIMOTE = "WiimoteNew"
const val FILE_GAME_SETTINGS_ONLY = "GameSettingsOnly"
const val SECTION_INI_ANDROID = "Android"
const val SECTION_INI_ANDROID_OVERLAY_BUTTONS = "AndroidOverlayButtons"
const val SECTION_INI_GENERAL = "General"
const val SECTION_INI_CORE = "Core"
const val SECTION_INI_INTERFACE = "Interface"
const val SECTION_INI_DSP = "DSP"
const val SECTION_LOGGER_LOGS = "Logs"
const val SECTION_LOGGER_OPTIONS = "Options"
const val SECTION_GFX_SETTINGS = "Settings"
const val SECTION_GFX_ENHANCEMENTS = "Enhancements"
const val SECTION_GFX_HACKS = "Hacks"
const val SECTION_DEBUG = "Debug"
const val SECTION_EMULATED_USB_DEVICES = "EmulatedUSBDevices"
const val SECTION_STEREOSCOPY = "Stereoscopy"
const val SECTION_ANALYTICS = "Analytics"
}
}

View File

@ -1,113 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model;
import androidx.annotation.NonNull;
import org.dolphinemu.dolphinemu.NativeLibrary;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public enum StringSetting implements AbstractStringSetting
{
// These entries have the same names and order as in C++, just for consistency.
MAIN_DEFAULT_ISO(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "DefaultISO", ""),
MAIN_BBA_MAC(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "BBA_MAC", ""),
MAIN_BBA_XLINK_IP(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "BBA_XLINK_IP", ""),
// Schthack PSO Server - https://schtserv.com/
MAIN_BBA_BUILTIN_DNS(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "BBA_BUILTIN_DNS",
"149.56.167.128"),
MAIN_CUSTOM_RTC_VALUE(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "CustomRTCValue",
"0x386d4380"),
MAIN_GFX_BACKEND(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "GFXBackend",
NativeLibrary.GetDefaultGraphicsBackendName()),
MAIN_DUMP_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "DumpPath", ""),
MAIN_LOAD_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "LoadPath", ""),
MAIN_RESOURCEPACK_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "ResourcePackPath",
""),
MAIN_FS_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "NANDRootPath", ""),
MAIN_WII_SD_CARD_IMAGE_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "WiiSDCardPath",
""),
MAIN_WII_SD_CARD_SYNC_FOLDER_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL,
"WiiSDCardSyncFolder", ""),
MAIN_WFS_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "WFSPath", ""),
GFX_ENHANCE_POST_SHADER(Settings.FILE_GFX, Settings.SECTION_GFX_ENHANCEMENTS,
"PostProcessingShader", "");
private static final StringSetting[] NOT_RUNTIME_EDITABLE_ARRAY = new StringSetting[]{
MAIN_CUSTOM_RTC_VALUE,
MAIN_GFX_BACKEND,
};
private static final Set<StringSetting> NOT_RUNTIME_EDITABLE =
new HashSet<>(Arrays.asList(NOT_RUNTIME_EDITABLE_ARRAY));
private final String mFile;
private final String mSection;
private final String mKey;
private final String mDefaultValue;
StringSetting(String file, String section, String key, String defaultValue)
{
mFile = file;
mSection = section;
mKey = key;
mDefaultValue = defaultValue;
}
@Override
public boolean isOverridden()
{
return NativeConfig.isOverridden(mFile, mSection, mKey);
}
@Override
public boolean isRuntimeEditable()
{
for (StringSetting setting : NOT_RUNTIME_EDITABLE)
{
if (setting == this)
return false;
}
return NativeConfig.isSettingSaveable(mFile, mSection, mKey);
}
@Override
public boolean delete(@NonNull Settings settings)
{
return NativeConfig.deleteKey(settings.getWriteLayer(), mFile, mSection, mKey);
}
@NonNull @Override
public String getString()
{
if (!NativeConfig.isSettingSaveable(mFile, mSection, mKey))
{
throw new UnsupportedOperationException(
"Unsupported setting: " + mFile + ", " + mSection + ", " + mKey);
}
return NativeConfig.getString(NativeConfig.LAYER_ACTIVE, mFile, mSection, mKey, mDefaultValue);
}
@Override
public void setString(@NonNull Settings settings, @NonNull String newValue)
{
NativeConfig.setString(settings.getWriteLayer(), mFile, mSection, mKey, newValue);
}
public void setString(int layer, String newValue)
{
NativeConfig.setString(layer, mFile, mSection, mKey, newValue);
}
}

View File

@ -0,0 +1,104 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model
import org.dolphinemu.dolphinemu.NativeLibrary
import java.util.*
enum class StringSetting(
private val file: String,
private val section: String,
private val key: String,
private val defaultValue: String
) : AbstractStringSetting {
// These entries have the same names and order as in C++, just for consistency.
MAIN_DEFAULT_ISO(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "DefaultISO", ""),
MAIN_BBA_MAC(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "BBA_MAC", ""),
MAIN_BBA_XLINK_IP(Settings.FILE_DOLPHIN, Settings.SECTION_INI_CORE, "BBA_XLINK_IP", ""),
// Schthack PSO Server - https://schtserv.com/
MAIN_BBA_BUILTIN_DNS(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"BBA_BUILTIN_DNS",
"149.56.167.128"
),
MAIN_CUSTOM_RTC_VALUE(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"CustomRTCValue",
"0x386d4380"
),
MAIN_GFX_BACKEND(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_CORE,
"GFXBackend",
NativeLibrary.GetDefaultGraphicsBackendName()
),
MAIN_DUMP_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "DumpPath", ""),
MAIN_LOAD_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "LoadPath", ""),
MAIN_RESOURCEPACK_PATH(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_GENERAL,
"ResourcePackPath",
""
),
MAIN_FS_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "NANDRootPath", ""),
MAIN_WII_SD_CARD_IMAGE_PATH(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_GENERAL,
"WiiSDCardPath",
""
),
MAIN_WII_SD_CARD_SYNC_FOLDER_PATH(
Settings.FILE_DOLPHIN,
Settings.SECTION_INI_GENERAL,
"WiiSDCardSyncFolder",
""
),
MAIN_WFS_PATH(Settings.FILE_DOLPHIN, Settings.SECTION_INI_GENERAL, "WFSPath", ""),
GFX_ENHANCE_POST_SHADER(
Settings.FILE_GFX,
Settings.SECTION_GFX_ENHANCEMENTS,
"PostProcessingShader",
""
);
override val isOverridden: Boolean
get() = NativeConfig.isOverridden(file, section, key)
override val isRuntimeEditable: Boolean
get() {
for (setting in NOT_RUNTIME_EDITABLE) {
if (setting == this) return false
}
return NativeConfig.isSettingSaveable(file, section, key)
}
override fun delete(settings: Settings): Boolean {
return NativeConfig.deleteKey(settings.writeLayer, file, section, key)
}
override val string: String
get() = if (!NativeConfig.isSettingSaveable(file, section, key)) {
throw UnsupportedOperationException("Unsupported setting: $file, $section, $key")
} else NativeConfig.getString(NativeConfig.LAYER_ACTIVE, file, section, key, defaultValue)
override fun setString(settings: Settings, newValue: String) {
NativeConfig.setString(settings.writeLayer, file, section, key, newValue)
}
fun setString(layer: Int, newValue: String?) {
NativeConfig.setString(layer, file, section, key, newValue)
}
companion object {
private val NOT_RUNTIME_EDITABLE_ARRAY = arrayOf(
MAIN_CUSTOM_RTC_VALUE,
MAIN_GFX_BACKEND
)
private val NOT_RUNTIME_EDITABLE: Set<StringSetting> =
HashSet(listOf(*NOT_RUNTIME_EDITABLE_ARRAY))
}
}

View File

@ -3,29 +3,22 @@
package org.dolphinemu.dolphinemu.features.settings.model.view package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings import org.dolphinemu.dolphinemu.features.settings.model.Settings
class DateTimeChoiceSetting( class DateTimeChoiceSetting(
context: Context, context: Context,
private val setting: AbstractStringSetting, override val setting: AbstractStringSetting,
nameId: Int, nameId: Int,
descriptionId: Int descriptionId: Int
) : SettingsItem(context, nameId, descriptionId) { ) : SettingsItem(context, nameId, descriptionId) {
override fun getType(): Int { override val type: Int = TYPE_DATETIME_CHOICE
return TYPE_DATETIME_CHOICE
}
override fun getSetting(): AbstractSetting {
return setting
}
fun setSelectedValue(settings: Settings, selection: String) { fun setSelectedValue(settings: Settings, selection: String) {
setting.setString(settings, selection) setting.setString(settings, selection)
} }
fun getSelectedValue(): String { fun getSelectedValue(): String {
return setting.getString() return setting.string
} }
} }

View File

@ -1,60 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public final class FilePicker extends SettingsItem
{
private AbstractStringSetting mSetting;
private int mRequestType;
private String mDefaultPathRelativeToUserDirectory;
public FilePicker(Context context, AbstractStringSetting setting, int titleId, int descriptionId,
int requestType, @Nullable String defaultPathRelativeToUserDirectory)
{
super(context, titleId, descriptionId);
mSetting = setting;
mRequestType = requestType;
mDefaultPathRelativeToUserDirectory = defaultPathRelativeToUserDirectory;
}
public String getSelectedValue()
{
return mSetting.getString();
}
public void setSelectedValue(Settings settings, String selection)
{
mSetting.setString(settings, selection);
}
public int getRequestType()
{
return mRequestType;
}
@Nullable
public String getDefaultPathRelativeToUserDirectory()
{
return mDefaultPathRelativeToUserDirectory;
}
@Override
public int getType()
{
return TYPE_FILE_PICKER;
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -0,0 +1,26 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
class FilePicker(
context: Context,
override var setting: AbstractStringSetting,
titleId: Int,
descriptionId: Int,
val requestType: Int,
val defaultPathRelativeToUserDirectory: String?
) : SettingsItem(context, titleId, descriptionId) {
override val type: Int = TYPE_FILE_PICKER
fun getSelectedValue() : String {
return setting.string
}
fun setSelectedValue(settings: Settings, selection: String) {
setting.setString(settings, selection)
}
}

View File

@ -1,44 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractFloatSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public class FloatSliderSetting extends SliderSetting
{
protected AbstractFloatSetting mSetting;
public FloatSliderSetting(Context context, AbstractFloatSetting setting, int titleId,
int descriptionId, int min, int max, String units, int stepSize)
{
super(context, titleId, descriptionId, min, max, units, stepSize);
mSetting = setting;
}
public FloatSliderSetting(AbstractFloatSetting setting, CharSequence name,
CharSequence description, int min, int max, String units)
{
super(name, description, min, max, units);
mSetting = setting;
}
public int getSelectedValue()
{
return Math.round(mSetting.getFloat());
}
public void setSelectedValue(Settings settings, float selection)
{
mSetting.setFloat(settings, selection);
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -0,0 +1,47 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractFloatSetting
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
import kotlin.math.roundToInt
open class FloatSliderSetting : SliderSetting {
var floatSetting: AbstractFloatSetting
override val setting: AbstractSetting
get() = floatSetting
constructor(
context: Context,
setting: AbstractFloatSetting,
titleId: Int,
descriptionId: Int,
min: Int,
max: Int,
units: String?,
stepSize: Int
) : super(context, titleId, descriptionId, min, max, units, stepSize) {
floatSetting = setting
}
constructor(
setting: AbstractFloatSetting,
name: CharSequence,
description: CharSequence?,
min: Int,
max: Int,
units: String?
) : super(name, description, min, max, units) {
floatSetting = setting
}
override val selectedValue: Int
get() = floatSetting.float.roundToInt()
open fun setSelectedValue(settings: Settings?, selection: Float) {
floatSetting.setFloat(settings!!, selection)
}
}

View File

@ -1,32 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
public class HeaderSetting extends SettingsItem
{
public HeaderSetting(Context context, int titleId, int descriptionId)
{
super(context, titleId, descriptionId);
}
public HeaderSetting(CharSequence title, CharSequence description)
{
super(title, description);
}
@Override
public int getType()
{
return SettingsItem.TYPE_HEADER;
}
@Override
public AbstractSetting getSetting()
{
return null;
}
}

View File

@ -0,0 +1,20 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
open class HeaderSetting : SettingsItem {
override val setting: AbstractSetting? = null
constructor(
context: Context,
titleId: Int,
descriptionId: Int
) : super(context, titleId, descriptionId)
constructor(title: CharSequence, description: CharSequence?) : super(title, description)
override val type: Int = TYPE_HEADER
}

View File

@ -1,19 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
public final class HyperLinkHeaderSetting extends HeaderSetting
{
public HyperLinkHeaderSetting(Context context, int titleId, int descriptionId)
{
super(context, titleId, descriptionId);
}
@Override
public int getType()
{
return SettingsItem.TYPE_HYPERLINK_HEADER;
}
}

View File

@ -0,0 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
class HyperLinkHeaderSetting(
context: Context,
titleId: Int,
descriptionId: Int
) : HeaderSetting(context, titleId, descriptionId)

View File

@ -1,72 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public class InputStringSetting extends SettingsItem
{
private AbstractStringSetting mSetting;
private MenuTag mMenuTag;
public InputStringSetting(Context context, AbstractStringSetting setting, int titleId,
int descriptionId, MenuTag menuTag)
{
super(context, titleId, descriptionId);
mSetting = setting;
mMenuTag = menuTag;
}
public InputStringSetting(Context context, AbstractStringSetting setting, int titleId,
int descriptionId)
{
this(context, setting, titleId, descriptionId, null);
}
public InputStringSetting(Context context, AbstractStringSetting setting, int titleId,
int descriptionId, int choicesId, int valuesId, MenuTag menuTag)
{
super(context, titleId, descriptionId);
mSetting = setting;
mMenuTag = menuTag;
}
public InputStringSetting(Context context, AbstractStringSetting setting, int titleId,
int descriptionId, int choicesId, int valuesId)
{
this(context, setting, titleId, descriptionId, choicesId, valuesId, null);
}
public String getSelectedValue()
{
return mSetting.getString();
}
public MenuTag getMenuTag()
{
return mMenuTag;
}
public void setSelectedValue(Settings settings, String selection)
{
mSetting.setString(settings, selection);
}
@Override
public int getType()
{
return TYPE_STRING;
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
class InputStringSetting(
context: Context,
setting: AbstractStringSetting,
titleId: Int,
descriptionId: Int,
) : SettingsItem(context, titleId, descriptionId) {
override val type: Int = TYPE_STRING
private var stringSetting: AbstractStringSetting = setting
override val setting: AbstractSetting
get() = stringSetting
val selectedValue: String
get() = stringSetting.string
fun setSelectedValue(settings: Settings, selection: String) {
stringSetting.setString(settings, selection)
}
}

View File

@ -1,37 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public final class IntSliderSetting extends SliderSetting
{
private AbstractIntSetting mSetting;
public IntSliderSetting(Context context, AbstractIntSetting setting, int titleId,
int descriptionId, int min, int max, String units, int stepSize)
{
super(context, titleId, descriptionId, min, max, units, stepSize);
mSetting = setting;
}
public int getSelectedValue()
{
return mSetting.getInt();
}
public void setSelectedValue(Settings settings, int selection)
{
mSetting.setInt(settings, selection);
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -0,0 +1,29 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
class IntSliderSetting(
context: Context,
private val intSetting: AbstractIntSetting,
titleId: Int,
descriptionId: Int,
min: Int,
max: Int,
units: String?,
stepSize: Int
) : SliderSetting(context, titleId, descriptionId, min, max, units, stepSize) {
override val setting: AbstractSetting
get() = intSetting
override val selectedValue: Int
get() = intSetting.int
fun setSelectedValue(settings: Settings?, selection: Int) {
intSetting.setInt(settings!!, selection)
}
}

View File

@ -1,36 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public final class InvertedSwitchSetting extends SwitchSetting
{
public InvertedSwitchSetting(Context context, AbstractBooleanSetting setting, int titleId,
int descriptionId)
{
super(context, setting, titleId, descriptionId);
}
@Override
public boolean isChecked()
{
return !mSetting.getBoolean();
}
@Override
public void setChecked(Settings settings, boolean checked)
{
mSetting.setBoolean(settings, !checked);
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -0,0 +1,25 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
class InvertedSwitchSetting(
context: Context,
setting: AbstractBooleanSetting,
titleId: Int,
descriptionId: Int
) : SwitchSetting(context, setting, titleId, descriptionId) {
override val setting: AbstractSetting
get() = booleanSetting
override val isChecked: Boolean
get() = !booleanSetting.boolean
override fun setChecked(settings: Settings?, checked: Boolean) {
booleanSetting.setBoolean(settings!!, !checked)
}
}

View File

@ -1,23 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import org.dolphinemu.dolphinemu.features.settings.model.AdHocBooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public class LogSwitchSetting extends SwitchSetting
{
String mKey;
public LogSwitchSetting(String key, CharSequence title, CharSequence description)
{
super(new AdHocBooleanSetting(Settings.FILE_LOGGER, Settings.SECTION_LOGGER_LOGS, key, false),
title, description);
mKey = key;
}
public String getKey()
{
return mKey;
}
}

View File

@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import org.dolphinemu.dolphinemu.features.settings.model.AdHocBooleanSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
class LogSwitchSetting(
var key: String,
title: CharSequence?,
description: CharSequence?
) : SwitchSetting(
AdHocBooleanSetting(
Settings.FILE_LOGGER,
Settings.SECTION_LOGGER_LOGS,
key,
false
),
title,
description
)

View File

@ -1,36 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractFloatSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public final class PercentSliderSetting extends FloatSliderSetting
{
public PercentSliderSetting(Context context, AbstractFloatSetting setting, int titleId,
int descriptionId, int min, int max, String units, int stepSize)
{
super(context, setting, titleId, descriptionId, min, max, units, stepSize);
}
@Override
public int getSelectedValue()
{
return Math.round(mSetting.getFloat() * 100);
}
@Override
public void setSelectedValue(Settings settings, float selection)
{
mSetting.setFloat(settings, selection / 100);
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractFloatSetting
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
import kotlin.math.roundToInt
class PercentSliderSetting(
context: Context,
override val setting: AbstractFloatSetting,
titleId: Int,
descriptionId: Int,
min: Int,
max: Int,
units: String?,
stepSize: Int
) : FloatSliderSetting(context, setting, titleId, descriptionId, min, max, units, stepSize) {
override val selectedValue: Int
get() = (floatSetting.float * 100).roundToInt()
override fun setSelectedValue(settings: Settings?, selection: Float) {
floatSetting.setFloat(settings!!, selection / 100)
}
}

View File

@ -1,59 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
public final class RunRunnable extends SettingsItem
{
private final int mAlertText;
private final int mToastTextAfterRun;
private final boolean mWorksDuringEmulation;
private final Runnable mRunnable;
public RunRunnable(Context context, int titleId, int descriptionId, int alertText,
int toastTextAfterRun, boolean worksDuringEmulation, Runnable runnable)
{
super(context, titleId, descriptionId);
mAlertText = alertText;
mToastTextAfterRun = toastTextAfterRun;
mWorksDuringEmulation = worksDuringEmulation;
mRunnable = runnable;
}
public int getAlertText()
{
return mAlertText;
}
public int getToastTextAfterRun()
{
return mToastTextAfterRun;
}
public Runnable getRunnable()
{
return mRunnable;
}
@Override
public int getType()
{
return TYPE_RUN_RUNNABLE;
}
@Override
public AbstractSetting getSetting()
{
return null;
}
@Override
public boolean isEditable()
{
return mWorksDuringEmulation || !NativeLibrary.IsRunning();
}
}

View File

@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.NativeLibrary
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
class RunRunnable(
context: Context,
titleId: Int,
descriptionId: Int,
val alertText: Int,
val toastTextAfterRun: Int,
private val worksDuringEmulation: Boolean,
val runnable: Runnable
) : SettingsItem(context, titleId, descriptionId) {
override val type: Int = TYPE_RUN_RUNNABLE
override val setting: AbstractSetting? = null
override val isEditable: Boolean
get() = worksDuringEmulation || !NativeLibrary.IsRunning()
}

View File

@ -1,107 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
/**
* ViewModel abstraction for an Item in the RecyclerView powering SettingsFragments.
* Most of them correspond to a single line in an INI file, but there are a few with multiple
* analogues and a few with none (Headers, for example, do not correspond to anything on disk.)
*/
public abstract class SettingsItem
{
public static final int TYPE_HEADER = 0;
public static final int TYPE_SWITCH = 1;
public static final int TYPE_SINGLE_CHOICE = 2;
public static final int TYPE_SLIDER = 3;
public static final int TYPE_SUBMENU = 4;
public static final int TYPE_INPUT_MAPPING_CONTROL = 5;
public static final int TYPE_STRING_SINGLE_CHOICE = 6;
public static final int TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS = 8;
public static final int TYPE_FILE_PICKER = 9;
public static final int TYPE_RUN_RUNNABLE = 10;
public static final int TYPE_STRING = 11;
public static final int TYPE_HYPERLINK_HEADER = 12;
public static final int TYPE_DATETIME_CHOICE = 13;
private final CharSequence mName;
private final CharSequence mDescription;
/**
* Base constructor.
*
* @param name A text string to be displayed as this setting's name.
* @param description A text string to be displayed as this setting's description.
*/
public SettingsItem(CharSequence name, CharSequence description)
{
mName = name;
mDescription = description;
}
/**
* @param nameId Resource ID for a text string to be displayed as this setting's name.
* @param descriptionId Resource ID for a text string to be displayed as this setting's description.
*/
public SettingsItem(Context context, int nameId, int descriptionId)
{
mName = nameId == 0 ? "" : context.getText(nameId);
mDescription = descriptionId == 0 ? "" : context.getText(descriptionId);
}
public CharSequence getName()
{
return mName;
}
public CharSequence getDescription()
{
return mDescription;
}
/**
* Used by {@link SettingsAdapter}'s onCreateViewHolder()
* method to determine which type of ViewHolder should be created.
*
* @return An integer (ideally, one of the constants defined in this file)
*/
public abstract int getType();
protected abstract AbstractSetting getSetting();
public boolean isOverridden()
{
AbstractSetting setting = getSetting();
return setting != null && setting.isOverridden();
}
public boolean isEditable()
{
if (!NativeLibrary.IsRunning())
return true;
AbstractSetting setting = getSetting();
return setting != null && setting.isRuntimeEditable();
}
public boolean hasSetting()
{
return getSetting() != null;
}
public boolean canClear()
{
return hasSetting();
}
public void clear(Settings settings)
{
getSetting().delete(settings);
}
}

View File

@ -0,0 +1,89 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.NativeLibrary
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
/**
* ViewModel abstraction for an Item in the RecyclerView powering SettingsFragments.
* Most of them correspond to a single line in an INI file, but there are a few with multiple
* analogues and a few with none (Headers, for example, do not correspond to anything on disk.)
*/
abstract class SettingsItem {
val name: CharSequence
val description: CharSequence?
/**
* Base constructor.
*
* @param name A text string to be displayed as this Setting's name.
* @param description A text string to be displayed as this Setting's description.
*/
constructor(name: CharSequence, description: CharSequence?) {
this.name = name
this.description = description
}
/**
* @param nameId Resource ID for a text string to be displayed as this Setting's name.
* @param descriptionId Resource ID for a text string to be displayed as this Setting's description.
*/
constructor(context: Context, nameId: Int, descriptionId: Int) {
name = if (nameId == 0) "" else context.getText(nameId)
description = if (descriptionId == 0) "" else context.getText(descriptionId)
}
/**
* Used by [SettingsAdapter]'s onCreateViewHolder()
* method to determine which type of ViewHolder should be created.
*
* @return An integer (ideally, one of the constants defined in this file)
*/
abstract val type: Int
abstract val setting: AbstractSetting?
val isOverridden: Boolean
get() {
val setting = setting
return setting != null && setting.isOverridden
}
open val isEditable: Boolean
get() {
if (!NativeLibrary.IsRunning()) return true
val setting = setting
return setting != null && setting.isRuntimeEditable
}
private fun hasSetting(): Boolean {
return setting != null
}
open fun canClear(): Boolean {
return hasSetting()
}
open fun clear(settings: Settings) {
setting!!.delete(settings)
}
companion object {
const val TYPE_HEADER = 0
const val TYPE_SWITCH = 1
const val TYPE_SINGLE_CHOICE = 2
const val TYPE_SLIDER = 3
const val TYPE_SUBMENU = 4
const val TYPE_INPUT_MAPPING_CONTROL = 5
const val TYPE_STRING_SINGLE_CHOICE = 6
const val TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS = 8
const val TYPE_FILE_PICKER = 9
const val TYPE_RUN_RUNNABLE = 10
const val TYPE_STRING = 11
const val TYPE_HYPERLINK_HEADER = 12
const val TYPE_DATETIME_CHOICE = 13
}
}

View File

@ -1,72 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public final class SingleChoiceSetting extends SettingsItem
{
private AbstractIntSetting mSetting;
private int mChoicesId;
private int mValuesId;
private MenuTag menuTag;
public SingleChoiceSetting(Context context, AbstractIntSetting setting, int titleId,
int descriptionId, int choicesId, int valuesId, MenuTag menuTag)
{
super(context, titleId, descriptionId);
mSetting = setting;
mValuesId = valuesId;
mChoicesId = choicesId;
this.menuTag = menuTag;
}
public SingleChoiceSetting(Context context, AbstractIntSetting setting, int titleId,
int descriptionId, int choicesId, int valuesId)
{
this(context, setting, titleId, descriptionId, choicesId, valuesId, null);
}
public int getChoicesId()
{
return mChoicesId;
}
public int getValuesId()
{
return mValuesId;
}
public int getSelectedValue()
{
return mSetting.getInt();
}
public MenuTag getMenuTag()
{
return menuTag;
}
public void setSelectedValue(Settings settings, int selection)
{
mSetting.setInt(settings, selection);
}
@Override
public int getType()
{
return TYPE_SINGLE_CHOICE;
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -0,0 +1,30 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag
class SingleChoiceSetting(
context: Context,
private val intSetting: AbstractIntSetting,
titleId: Int,
descriptionId: Int,
val choicesId: Int,
val valuesId: Int,
val menuTag: MenuTag? = null
) : SettingsItem(context, titleId, descriptionId) {
override val type: Int = TYPE_SINGLE_CHOICE
override val setting: AbstractSetting
get() = intSetting
val selectedValue: Int
get() = intSetting.int
fun setSelectedValue(settings: Settings?, selection: Int) {
intSetting.setInt(settings!!, selection)
}
}

View File

@ -1,89 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public final class SingleChoiceSettingDynamicDescriptions extends SettingsItem
{
private AbstractIntSetting mSetting;
private int mChoicesId;
private int mValuesId;
private int mDescriptionChoicesId;
private int mDescriptionValuesId;
private MenuTag menuTag;
public SingleChoiceSettingDynamicDescriptions(Context context, AbstractIntSetting setting,
int titleId, int descriptionId, int choicesId, int valuesId, int descriptionChoicesId,
int descriptionValuesId, MenuTag menuTag)
{
super(context, titleId, descriptionId);
mSetting = setting;
mValuesId = valuesId;
mChoicesId = choicesId;
mDescriptionChoicesId = descriptionChoicesId;
mDescriptionValuesId = descriptionValuesId;
this.menuTag = menuTag;
}
public SingleChoiceSettingDynamicDescriptions(Context context, AbstractIntSetting setting,
int titleId, int descriptionId, int choicesId, int valuesId, int descriptionChoicesId,
int descriptionValuesId)
{
this(context, setting, titleId, descriptionId, choicesId, valuesId, descriptionChoicesId,
descriptionValuesId, null);
}
public int getChoicesId()
{
return mChoicesId;
}
public int getValuesId()
{
return mValuesId;
}
public int getDescriptionChoicesId()
{
return mDescriptionChoicesId;
}
public int getDescriptionValuesId()
{
return mDescriptionValuesId;
}
public int getSelectedValue()
{
return mSetting.getInt();
}
public MenuTag getMenuTag()
{
return menuTag;
}
public void setSelectedValue(Settings settings, int selection)
{
mSetting.setInt(settings, selection);
}
@Override
public int getType()
{
return TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS;
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
class SingleChoiceSettingDynamicDescriptions(
context: Context,
override val setting: AbstractIntSetting,
titleId: Int,
descriptionId: Int,
val choicesId: Int,
val valuesId: Int,
val descriptionChoicesId: Int,
val descriptionValuesId: Int,
) : SettingsItem(context, titleId, descriptionId) {
override val type: Int = TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS
val selectedValue: Int
get() = setting.int
fun setSelectedValue(settings: Settings, selection: Int) {
setting.setInt(settings, selection)
}
}

View File

@ -1,61 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public abstract class SliderSetting extends SettingsItem
{
private int mMin;
private int mMax;
private String mUnits;
private int mStepSize;
public SliderSetting(Context context, int nameId, int descriptionId, int min, int max,
String units, int stepSize)
{
super(context, nameId, descriptionId);
mMin = min;
mMax = max;
mUnits = units;
mStepSize = stepSize;
}
public SliderSetting(CharSequence name, CharSequence description, int min, int max, String units)
{
super(name, description);
mMin = min;
mMax = max;
mUnits = units;
}
public abstract int getSelectedValue();
public int getMin()
{
return mMin;
}
public int getMax()
{
return mMax;
}
public String getUnits()
{
return mUnits;
}
public int getStepSize()
{
return mStepSize;
}
@Override
public int getType()
{
return TYPE_SLIDER;
}
}

View File

@ -0,0 +1,47 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
abstract class SliderSetting : SettingsItem {
override val type: Int = TYPE_SLIDER
var min: Int
private set
var max: Int
private set
var units: String?
private set
var stepSize = 0
private set
constructor(
context: Context,
nameId: Int,
descriptionId: Int,
min: Int,
max: Int,
units: String?,
stepSize: Int
) : super(context, nameId, descriptionId) {
this.min = min
this.max = max
this.units = units
this.stepSize = stepSize
}
constructor(
name: CharSequence,
description: CharSequence?,
min: Int,
max: Int,
units: String?
) : super(name, description) {
this.min = min
this.max = max
this.units = units
}
abstract val selectedValue: Int
}

View File

@ -1,153 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.DolphinApplication;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public class StringSingleChoiceSetting extends SettingsItem
{
private final AbstractStringSetting mSetting;
protected String[] mChoices;
protected String[] mValues;
private final MenuTag mMenuTag;
private int mNoChoicesAvailableString = 0;
public StringSingleChoiceSetting(Context context, AbstractStringSetting setting, int titleId,
int descriptionId, String[] choices, String[] values, MenuTag menuTag)
{
super(context, titleId, descriptionId);
mSetting = setting;
mChoices = choices;
mValues = values;
mMenuTag = menuTag;
}
public StringSingleChoiceSetting(Context context, AbstractStringSetting setting, int titleId,
int descriptionId, String[] choices, String[] values)
{
this(context, setting, titleId, descriptionId, choices, values, null);
}
public StringSingleChoiceSetting(Context context, AbstractStringSetting setting, int titleId,
int descriptionId, String[] choices, String[] values, int noChoicesAvailableString)
{
this(context, setting, titleId, descriptionId, choices, values, null);
mNoChoicesAvailableString = noChoicesAvailableString;
}
public StringSingleChoiceSetting(Context context, AbstractStringSetting setting, int titleId,
int descriptionId, int choicesId, int valuesId, MenuTag menuTag)
{
super(context, titleId, descriptionId);
mSetting = setting;
mChoices = DolphinApplication.getAppContext().getResources().getStringArray(choicesId);
mValues = DolphinApplication.getAppContext().getResources().getStringArray(valuesId);
mMenuTag = menuTag;
}
public StringSingleChoiceSetting(Context context, AbstractStringSetting setting, int titleId,
int descriptionId, int choicesId, int valuesId)
{
this(context, setting, titleId, descriptionId, choicesId, valuesId, null);
}
public String[] getChoices()
{
return mChoices;
}
public String[] getValues()
{
return mValues;
}
public String getChoiceAt(int index)
{
if (mChoices == null)
return null;
if (index >= 0 && index < mChoices.length)
{
return mChoices[index];
}
return "";
}
public String getValueAt(int index)
{
if (mValues == null)
return null;
if (index >= 0 && index < mValues.length)
{
return mValues[index];
}
return "";
}
public String getSelectedChoice()
{
return getChoiceAt(getSelectedValueIndex());
}
public String getSelectedValue()
{
return mSetting.getString();
}
public int getSelectedValueIndex()
{
String selectedValue = getSelectedValue();
for (int i = 0; i < mValues.length; i++)
{
if (mValues[i].equals(selectedValue))
{
return i;
}
}
return -1;
}
public MenuTag getMenuTag()
{
return mMenuTag;
}
public int getNoChoicesAvailableString()
{
return mNoChoicesAvailableString;
}
public void setSelectedValue(Settings settings, String selection)
{
mSetting.setString(settings, selection);
}
public void refreshChoicesAndValues()
{
}
@Override
public int getType()
{
return TYPE_STRING_SINGLE_CHOICE;
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -0,0 +1,110 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.DolphinApplication
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
import org.dolphinemu.dolphinemu.features.settings.model.AbstractStringSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag
open class StringSingleChoiceSetting : SettingsItem {
override val type: Int = TYPE_SINGLE_CHOICE
private val stringSetting: AbstractStringSetting?
override val setting: AbstractSetting?
get() = stringSetting
var choices: Array<String?>?
protected set
var values: Array<String?>?
protected set
val menuTag: MenuTag?
var noChoicesAvailableString = 0
private set
open val selectedChoice: String?
get() = getChoiceAt(selectedValueIndex)
open val selectedValue: String
get() = stringSetting!!.string
@JvmOverloads
constructor(
context: Context,
setting: AbstractStringSetting?,
titleId: Int,
descriptionId: Int,
choices: Array<String?>?,
values: Array<String?>?,
menuTag: MenuTag? = null
) : super(context, titleId, descriptionId) {
stringSetting = setting
this.choices = choices
this.values = values
this.menuTag = menuTag
}
constructor(
context: Context,
setting: AbstractStringSetting,
titleId: Int,
descriptionId: Int,
choices: Array<String?>,
values: Array<String?>,
noChoicesAvailableString: Int
) : this(context, setting, titleId, descriptionId, choices, values) {
this.noChoicesAvailableString = noChoicesAvailableString
}
@JvmOverloads
constructor(
context: Context,
setting: AbstractStringSetting,
titleId: Int,
descriptionId: Int,
choicesId: Int,
valuesId: Int,
menuTag: MenuTag? = null
) : super(context, titleId, descriptionId) {
stringSetting = setting
choices = DolphinApplication.getAppContext().resources.getStringArray(choicesId)
values = DolphinApplication.getAppContext().resources.getStringArray(valuesId)
this.menuTag = menuTag
}
fun getChoiceAt(index: Int): String? {
if (choices == null) return null
return if (index >= 0 && index < choices!!.size) {
choices!![index]
} else ""
}
fun getValueAt(index: Int): String? {
if (values == null) return null
return if (index >= 0 && index < values!!.size) {
values!![index]
} else ""
}
val selectedValueIndex: Int
get() {
val selectedValue = selectedValue
for (i in values!!.indices) {
if (values!![i] == selectedValue) {
return i
}
}
return -1
}
open fun setSelectedValue(settings: Settings?, selection: String?) {
stringSetting!!.setString(settings!!, selection!!)
}
open fun refreshChoicesAndValues() {}
}

View File

@ -1,36 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
public final class SubmenuSetting extends SettingsItem
{
private MenuTag mMenuKey;
public SubmenuSetting(Context context, int titleId, MenuTag menuKey)
{
super(context, titleId, 0);
mMenuKey = menuKey;
}
public MenuTag getMenuKey()
{
return mMenuKey;
}
@Override
public int getType()
{
return TYPE_SUBMENU;
}
@Override
public AbstractSetting getSetting()
{
return null;
}
}

View File

@ -0,0 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag
class SubmenuSetting(
context: Context,
titleId: Int,
val menuKey: MenuTag
) : SettingsItem(context, titleId, 0) {
override val type: Int = TYPE_SUBMENU
override val setting: AbstractSetting? = null
}

View File

@ -1,50 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view;
import android.content.Context;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public class SwitchSetting extends SettingsItem
{
protected AbstractBooleanSetting mSetting;
public SwitchSetting(Context context, AbstractBooleanSetting setting, int titleId,
int descriptionId)
{
super(context, titleId, descriptionId);
mSetting = setting;
}
public SwitchSetting(AbstractBooleanSetting setting, CharSequence title,
CharSequence description)
{
super(title, description);
mSetting = setting;
}
public boolean isChecked()
{
return mSetting.getBoolean();
}
public void setChecked(Settings settings, boolean checked)
{
mSetting.setBoolean(settings, checked);
}
@Override
public int getType()
{
return TYPE_SWITCH;
}
@Override
public AbstractSetting getSetting()
{
return mSetting;
}
}

View File

@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.model.view
import android.content.Context
import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting
import org.dolphinemu.dolphinemu.features.settings.model.AbstractSetting
import org.dolphinemu.dolphinemu.features.settings.model.Settings
open class SwitchSetting : SettingsItem {
override val type: Int = TYPE_SWITCH
protected var booleanSetting: AbstractBooleanSetting
override val setting: AbstractSetting
get() = booleanSetting
constructor(
context: Context,
setting: AbstractBooleanSetting,
titleId: Int,
descriptionId: Int
) : super(context, titleId, descriptionId) {
booleanSetting = setting
}
constructor(
setting: AbstractBooleanSetting,
title: CharSequence?,
description: CharSequence?
) : super(title!!, description) {
booleanSetting = setting
}
open val isChecked: Boolean
get() = booleanSetting.boolean
open fun setChecked(settings: Settings?, checked: Boolean) {
booleanSetting.setBoolean(settings!!, checked)
}
}

View File

@ -1,165 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui;
import androidx.annotation.NonNull;
import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController;
public enum MenuTag
{
SETTINGS("settings"),
CONFIG("config"),
CONFIG_GENERAL("config_general"),
CONFIG_INTERFACE("config_interface"),
CONFIG_AUDIO("config_audio"),
CONFIG_PATHS("config_paths"),
CONFIG_GAME_CUBE("config_gamecube"),
CONFIG_SERIALPORT1("config_serialport1"),
CONFIG_WII("config_wii"),
CONFIG_ADVANCED("config_advanced"),
CONFIG_LOG("config_log"),
DEBUG("debug"),
GRAPHICS("graphics"),
ENHANCEMENTS("enhancements"),
STEREOSCOPY("stereoscopy"),
HACKS("hacks"),
STATISTICS("statistics"),
ADVANCED_GRAPHICS("advanced_graphics"),
GCPAD_TYPE("gc_pad_type"),
WIIMOTE("wiimote"),
WIIMOTE_EXTENSION("wiimote_extension"),
GCPAD_1("gcpad", 0),
GCPAD_2("gcpad", 1),
GCPAD_3("gcpad", 2),
GCPAD_4("gcpad", 3),
WIIMOTE_1("wiimote", 0),
WIIMOTE_2("wiimote", 1),
WIIMOTE_3("wiimote", 2),
WIIMOTE_4("wiimote", 3),
WIIMOTE_EXTENSION_1("wiimote_extension", 0),
WIIMOTE_EXTENSION_2("wiimote_extension", 1),
WIIMOTE_EXTENSION_3("wiimote_extension", 2),
WIIMOTE_EXTENSION_4("wiimote_extension", 3),
WIIMOTE_GENERAL_1("wiimote_general", 0),
WIIMOTE_GENERAL_2("wiimote_general", 1),
WIIMOTE_GENERAL_3("wiimote_general", 2),
WIIMOTE_GENERAL_4("wiimote_general", 3),
WIIMOTE_MOTION_SIMULATION_1("wiimote_motion_simulation", 0),
WIIMOTE_MOTION_SIMULATION_2("wiimote_motion_simulation", 1),
WIIMOTE_MOTION_SIMULATION_3("wiimote_motion_simulation", 2),
WIIMOTE_MOTION_SIMULATION_4("wiimote_motion_simulation", 3),
WIIMOTE_MOTION_INPUT_1("wiimote_motion_input", 0),
WIIMOTE_MOTION_INPUT_2("wiimote_motion_input", 1),
WIIMOTE_MOTION_INPUT_3("wiimote_motion_input", 2),
WIIMOTE_MOTION_INPUT_4("wiimote_motion_input", 3);
private String tag;
private int subType = -1;
MenuTag(String tag)
{
this.tag = tag;
}
MenuTag(String tag, int subtype)
{
this.tag = tag;
this.subType = subtype;
}
@NonNull
@Override
public String toString()
{
if (subType != -1)
{
return tag + subType;
}
return tag;
}
public String getTag()
{
return tag;
}
public int getSubType()
{
return subType;
}
public EmulatedController getCorrespondingEmulatedController()
{
if (isGCPadMenu())
return EmulatedController.getGcPad(getSubType());
else if (isWiimoteMenu())
return EmulatedController.getWiimote(getSubType());
else
throw new UnsupportedOperationException();
}
public boolean isSerialPort1Menu()
{
return this == CONFIG_SERIALPORT1;
}
public boolean isGCPadMenu()
{
return this == GCPAD_1 || this == GCPAD_2 || this == GCPAD_3 || this == GCPAD_4;
}
public boolean isWiimoteMenu()
{
return this == WIIMOTE_1 || this == WIIMOTE_2 || this == WIIMOTE_3 || this == WIIMOTE_4;
}
public boolean isWiimoteExtensionMenu()
{
return this == WIIMOTE_EXTENSION_1 || this == WIIMOTE_EXTENSION_2
|| this == WIIMOTE_EXTENSION_3 || this == WIIMOTE_EXTENSION_4;
}
public static MenuTag getGCPadMenuTag(int subtype)
{
return getMenuTag("gcpad", subtype);
}
public static MenuTag getWiimoteMenuTag(int subtype)
{
return getMenuTag("wiimote", subtype);
}
public static MenuTag getWiimoteExtensionMenuTag(int subtype)
{
return getMenuTag("wiimote_extension", subtype);
}
public static MenuTag getWiimoteGeneralMenuTag(int subtype)
{
return getMenuTag("wiimote_general", subtype);
}
public static MenuTag getWiimoteMotionSimulationMenuTag(int subtype)
{
return getMenuTag("wiimote_motion_simulation", subtype);
}
public static MenuTag getWiimoteMotionInputMenuTag(int subtype)
{
return getMenuTag("wiimote_motion_input", subtype);
}
private static MenuTag getMenuTag(String tag, int subtype)
{
for (MenuTag menuTag : MenuTag.values())
{
if (menuTag.tag.equals(tag) && menuTag.subType == subtype)
return menuTag;
}
throw new IllegalArgumentException("You are asking for a menu that is not available or " +
"passing a wrong subtype");
}
}

View File

@ -0,0 +1,132 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui
import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController
enum class MenuTag {
SETTINGS("settings"),
CONFIG("config"),
CONFIG_GENERAL("config_general"),
CONFIG_INTERFACE("config_interface"),
CONFIG_AUDIO("config_audio"),
CONFIG_PATHS("config_paths"),
CONFIG_GAME_CUBE("config_gamecube"),
CONFIG_SERIALPORT1("config_serialport1"),
CONFIG_WII("config_wii"),
CONFIG_ADVANCED("config_advanced"),
CONFIG_LOG("config_log"),
DEBUG("debug"),
GRAPHICS("graphics"),
ENHANCEMENTS("enhancements"),
STEREOSCOPY("stereoscopy"),
HACKS("hacks"),
STATISTICS("statistics"),
ADVANCED_GRAPHICS("advanced_graphics"),
GCPAD_TYPE("gc_pad_type"),
WIIMOTE("wiimote"),
WIIMOTE_EXTENSION("wiimote_extension"),
GCPAD_1("gcpad", 0),
GCPAD_2("gcpad", 1),
GCPAD_3("gcpad", 2),
GCPAD_4("gcpad", 3),
WIIMOTE_1("wiimote", 0),
WIIMOTE_2("wiimote", 1),
WIIMOTE_3("wiimote", 2),
WIIMOTE_4("wiimote", 3),
WIIMOTE_EXTENSION_1("wiimote_extension", 0),
WIIMOTE_EXTENSION_2("wiimote_extension", 1),
WIIMOTE_EXTENSION_3("wiimote_extension", 2),
WIIMOTE_EXTENSION_4("wiimote_extension", 3),
WIIMOTE_GENERAL_1("wiimote_general", 0),
WIIMOTE_GENERAL_2("wiimote_general", 1),
WIIMOTE_GENERAL_3("wiimote_general", 2),
WIIMOTE_GENERAL_4("wiimote_general", 3),
WIIMOTE_MOTION_SIMULATION_1("wiimote_motion_simulation", 0),
WIIMOTE_MOTION_SIMULATION_2("wiimote_motion_simulation", 1),
WIIMOTE_MOTION_SIMULATION_3("wiimote_motion_simulation", 2),
WIIMOTE_MOTION_SIMULATION_4("wiimote_motion_simulation", 3),
WIIMOTE_MOTION_INPUT_1("wiimote_motion_input", 0),
WIIMOTE_MOTION_INPUT_2("wiimote_motion_input", 1),
WIIMOTE_MOTION_INPUT_3("wiimote_motion_input", 2),
WIIMOTE_MOTION_INPUT_4("wiimote_motion_input", 3);
var tag: String
private set
var subType = -1
private set
constructor(tag: String) {
this.tag = tag
}
constructor(tag: String, subtype: Int) {
this.tag = tag
subType = subtype
}
override fun toString(): String {
return if (subType != -1) {
tag + subType
} else tag
}
val correspondingEmulatedController: EmulatedController
get() = if (isGCPadMenu) EmulatedController.getGcPad(subType) else if (isWiimoteMenu) EmulatedController.getWiimote(
subType
) else throw UnsupportedOperationException()
val isSerialPort1Menu: Boolean
get() = this == CONFIG_SERIALPORT1
val isGCPadMenu: Boolean
get() = this == GCPAD_1 || this == GCPAD_2 || this == GCPAD_3 || this == GCPAD_4
val isWiimoteMenu: Boolean
get() = this == WIIMOTE_1 || this == WIIMOTE_2 || this == WIIMOTE_3 || this == WIIMOTE_4
val isWiimoteExtensionMenu: Boolean
get() = this == WIIMOTE_EXTENSION_1 || this == WIIMOTE_EXTENSION_2 || this == WIIMOTE_EXTENSION_3 || this == WIIMOTE_EXTENSION_4
companion object {
@JvmStatic
fun getGCPadMenuTag(subtype: Int): MenuTag {
return getMenuTag("gcpad", subtype)
}
@JvmStatic
fun getWiimoteMenuTag(subtype: Int): MenuTag {
return getMenuTag("wiimote", subtype)
}
@JvmStatic
fun getWiimoteExtensionMenuTag(subtype: Int): MenuTag {
return getMenuTag("wiimote_extension", subtype)
}
@JvmStatic
fun getWiimoteGeneralMenuTag(subtype: Int): MenuTag {
return getMenuTag("wiimote_general", subtype)
}
@JvmStatic
fun getWiimoteMotionSimulationMenuTag(subtype: Int): MenuTag {
return getMenuTag("wiimote_motion_simulation", subtype)
}
@JvmStatic
fun getWiimoteMotionInputMenuTag(subtype: Int): MenuTag {
return getMenuTag("wiimote_motion_input", subtype)
}
private fun getMenuTag(tag: String, subtype: Int): MenuTag {
for (menuTag in values()) {
if (menuTag.tag == tag && menuTag.subType == subtype) return menuTag
}
throw IllegalArgumentException(
"You are asking for a menu that is not available or " +
"passing a wrong subtype"
)
}
}
}

View File

@ -1,401 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
import com.google.android.material.appbar.CollapsingToolbarLayout;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ActivitySettingsBinding;
import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
import org.dolphinemu.dolphinemu.utils.InsetsHelper;
import org.dolphinemu.dolphinemu.utils.ThemeHelper;
import java.util.Set;
public final class SettingsActivity extends AppCompatActivity implements SettingsActivityView
{
private static final String ARG_MENU_TAG = "menu_tag";
private static final String ARG_GAME_ID = "game_id";
private static final String ARG_REVISION = "revision";
private static final String ARG_IS_WII = "is_wii";
private static final String KEY_MAPPING_ALL_DEVICES = "all_devices";
private static final String FRAGMENT_TAG = "settings";
private static final String FRAGMENT_DIALOG_TAG = "settings_dialog";
private SettingsActivityPresenter mPresenter;
private AlertDialog dialog;
private CollapsingToolbarLayout mToolbarLayout;
private ActivitySettingsBinding mBinding;
private boolean mMappingAllDevices = false;
public static void launch(Context context, MenuTag menuTag, String gameId, int revision,
boolean isWii)
{
Intent settings = new Intent(context, SettingsActivity.class);
settings.putExtra(ARG_MENU_TAG, menuTag);
settings.putExtra(ARG_GAME_ID, gameId);
settings.putExtra(ARG_REVISION, revision);
settings.putExtra(ARG_IS_WII, isWii);
context.startActivity(settings);
}
public static void launch(Context context, MenuTag menuTag)
{
Intent settings = new Intent(context, SettingsActivity.class);
settings.putExtra(ARG_MENU_TAG, menuTag);
settings.putExtra(ARG_IS_WII, !NativeLibrary.IsRunning() || NativeLibrary.IsEmulatingWii());
context.startActivity(settings);
}
@Override
protected void onCreate(Bundle savedInstanceState)
{
ThemeHelper.setTheme(this);
super.onCreate(savedInstanceState);
// If we came here from the game list, we don't want to rescan when returning to the game list.
// But if we came here after UserDataActivity restarted the app, we do want to rescan.
if (savedInstanceState == null)
{
MainPresenter.skipRescanningLibrary();
}
else
{
mMappingAllDevices = savedInstanceState.getBoolean(KEY_MAPPING_ALL_DEVICES);
}
mBinding = ActivitySettingsBinding.inflate(getLayoutInflater());
setContentView(mBinding.getRoot());
WindowCompat.setDecorFitsSystemWindows(getWindow(), false);
Intent launcher = getIntent();
String gameID = launcher.getStringExtra(ARG_GAME_ID);
if (gameID == null)
gameID = "";
int revision = launcher.getIntExtra(ARG_REVISION, 0);
boolean isWii = launcher.getBooleanExtra(ARG_IS_WII, true);
MenuTag menuTag = (MenuTag) launcher.getSerializableExtra(ARG_MENU_TAG);
mPresenter = new SettingsActivityPresenter(this, getSettings());
mPresenter.onCreate(savedInstanceState, menuTag, gameID, revision, isWii, this);
mToolbarLayout = mBinding.toolbarSettingsLayout;
setSupportActionBar(mBinding.toolbarSettings);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// TODO: Remove this when CollapsingToolbarLayouts are fixed by Google
// https://github.com/material-components/material-components-android/issues/1310
ViewCompat.setOnApplyWindowInsetsListener(mToolbarLayout, null);
setInsets();
ThemeHelper.enableScrollTint(this, mBinding.toolbarSettings, mBinding.appbarSettings);
}
@Override
public boolean onCreateOptionsMenu(Menu menu)
{
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_settings, menu);
return true;
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState)
{
// Critical: If super method is not called, rotations will be busted.
super.onSaveInstanceState(outState);
mPresenter.saveState(outState);
outState.putBoolean(KEY_MAPPING_ALL_DEVICES, mMappingAllDevices);
}
@Override
protected void onStart()
{
super.onStart();
mPresenter.onStart();
}
/**
* If this is called, the user has left the settings screen (potentially through the
* home button) and will expect their changes to be persisted.
*/
@Override
protected void onStop()
{
super.onStop();
mPresenter.onStop(isFinishing());
}
@Override
protected void onDestroy()
{
super.onDestroy();
mPresenter.onDestroy();
}
@Override
public void showSettingsFragment(MenuTag menuTag, Bundle extras, boolean addToStack,
String gameID)
{
if (!addToStack && getFragment() != null)
return;
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
if (addToStack)
{
if (areSystemAnimationsEnabled())
{
transaction.setCustomAnimations(
R.anim.anim_settings_fragment_in,
R.anim.anim_settings_fragment_out,
0,
R.anim.anim_pop_settings_fragment_out);
}
transaction.addToBackStack(null);
}
transaction.replace(R.id.frame_content_settings,
SettingsFragment.newInstance(menuTag, gameID, extras), FRAGMENT_TAG);
transaction.commit();
}
@Override
public void showDialogFragment(DialogFragment fragment)
{
fragment.show(getSupportFragmentManager(), FRAGMENT_DIALOG_TAG);
}
private boolean areSystemAnimationsEnabled()
{
float duration = Settings.Global.getFloat(
getContentResolver(),
Settings.Global.ANIMATOR_DURATION_SCALE, 1);
float transition = Settings.Global.getFloat(
getContentResolver(),
Settings.Global.TRANSITION_ANIMATION_SCALE, 1);
return duration != 0 && transition != 0;
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent result)
{
super.onActivityResult(requestCode, resultCode, result);
// If the user picked a file, as opposed to just backing out.
if (resultCode == RESULT_OK)
{
if (requestCode != MainPresenter.REQUEST_DIRECTORY)
{
Uri uri = canonicalizeIfPossible(result.getData());
Set<String> validExtensions = requestCode == MainPresenter.REQUEST_GAME_FILE ?
FileBrowserHelper.GAME_EXTENSIONS : FileBrowserHelper.RAW_EXTENSION;
int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION;
if (requestCode != MainPresenter.REQUEST_GAME_FILE)
flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
int takeFlags = flags & result.getFlags();
FileBrowserHelper.runAfterExtensionCheck(this, uri, validExtensions, () ->
{
getContentResolver().takePersistableUriPermission(uri, takeFlags);
getFragment().getAdapter().onFilePickerConfirmation(uri.toString());
});
}
else
{
String path = FileBrowserHelper.getSelectedPath(result);
getFragment().getAdapter().onFilePickerConfirmation(path);
}
}
}
@NonNull
private Uri canonicalizeIfPossible(@NonNull Uri uri)
{
Uri canonicalizedUri = getContentResolver().canonicalize(uri);
return canonicalizedUri != null ? canonicalizedUri : uri;
}
@Override
public void showLoading()
{
if (dialog == null)
{
dialog = new MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.load_settings))
.setView(R.layout.dialog_indeterminate_progress)
.create();
}
dialog.show();
}
@Override
public void hideLoading()
{
dialog.dismiss();
}
@Override
public void showGameIniJunkDeletionQuestion()
{
new MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.game_ini_junk_title))
.setMessage(getString(R.string.game_ini_junk_question))
.setPositiveButton(R.string.yes, (dialogInterface, i) -> mPresenter.clearGameSettings())
.setNegativeButton(R.string.no, null)
.show();
}
@Override
public org.dolphinemu.dolphinemu.features.settings.model.Settings getSettings()
{
return new ViewModelProvider(this).get(SettingsViewModel.class).getSettings();
}
@Override
public void onSettingsFileLoaded(
org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
{
SettingsFragmentView fragment = getFragment();
if (fragment != null)
{
fragment.onSettingsFileLoaded(settings);
}
}
@Override
public void onSettingsFileNotFound()
{
SettingsFragmentView fragment = getFragment();
if (fragment != null)
{
fragment.loadDefaultSettings();
}
}
@Override
public void showToastMessage(String message)
{
Toast.makeText(this, message, Toast.LENGTH_SHORT).show();
}
@Override
public void onSettingChanged()
{
mPresenter.onSettingChanged();
}
@Override
public void onControllerSettingsChanged()
{
getFragment().onControllerSettingsChanged();
}
@Override
public void onMenuTagAction(@NonNull MenuTag menuTag, int value)
{
mPresenter.onMenuTagAction(menuTag, value);
}
@Override
public boolean hasMenuTagActionForValue(@NonNull MenuTag menuTag, int value)
{
return mPresenter.hasMenuTagActionForValue(menuTag, value);
}
@Override
public boolean onSupportNavigateUp()
{
onBackPressed();
return true;
}
private SettingsFragment getFragment()
{
return (SettingsFragment) getSupportFragmentManager().findFragmentByTag(FRAGMENT_TAG);
}
public void setToolbarTitle(String title)
{
mBinding.toolbarSettingsLayout.setTitle(title);
}
@Override
public void setMappingAllDevices(boolean allDevices)
{
mMappingAllDevices = allDevices;
}
@Override
public boolean isMappingAllDevices()
{
return mMappingAllDevices;
}
@Override
public int setOldControllerSettingsWarningVisibility(boolean visible)
{
// We use INVISIBLE instead of GONE to avoid getting a stale height for the return value
mBinding.oldControllerSettingsWarning.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
return visible ? mBinding.oldControllerSettingsWarning.getHeight() : 0;
}
private void setInsets()
{
ViewCompat.setOnApplyWindowInsetsListener(mBinding.appbarSettings, (v, windowInsets) ->
{
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
InsetsHelper.insetAppBar(insets, mBinding.appbarSettings);
mBinding.frameContentSettings.setPadding(insets.left, 0, insets.right, 0);
int textPadding = getResources().getDimensionPixelSize(R.dimen.spacing_large);
mBinding.oldControllerSettingsWarning.setPadding(textPadding + insets.left, textPadding,
textPadding + insets.right, textPadding + insets.bottom);
InsetsHelper.applyNavbarWorkaround(insets.bottom, mBinding.workaroundView);
ThemeHelper.setNavigationBarColor(this,
MaterialColors.getColor(mBinding.appbarSettings, R.attr.colorSurface));
return windowInsets;
});
}
}

View File

@ -0,0 +1,323 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.ViewModelProvider
import com.google.android.material.appbar.CollapsingToolbarLayout
import com.google.android.material.color.MaterialColors
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.dolphinemu.dolphinemu.NativeLibrary
import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.databinding.ActivitySettingsBinding
import org.dolphinemu.dolphinemu.features.settings.model.Settings
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsFragment.Companion.newInstance
import org.dolphinemu.dolphinemu.ui.main.MainPresenter
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper
import org.dolphinemu.dolphinemu.utils.InsetsHelper
import org.dolphinemu.dolphinemu.utils.SerializableHelper.serializable
import org.dolphinemu.dolphinemu.utils.ThemeHelper.enableScrollTint
import org.dolphinemu.dolphinemu.utils.ThemeHelper.setNavigationBarColor
import org.dolphinemu.dolphinemu.utils.ThemeHelper.setTheme
class SettingsActivity : AppCompatActivity(), SettingsActivityView {
private var presenter: SettingsActivityPresenter? = null
private var dialog: AlertDialog? = null
private var toolbarLayout: CollapsingToolbarLayout? = null
private var binding: ActivitySettingsBinding? = null
override var isMappingAllDevices = false
override val settings: Settings
get() = ViewModelProvider(this)[SettingsViewModel::class.java].settings
private val fragment: SettingsFragment?
get() = supportFragmentManager.findFragmentByTag(FRAGMENT_TAG) as SettingsFragment?
override fun onCreate(savedInstanceState: Bundle?) {
setTheme(this)
super.onCreate(savedInstanceState)
// If we came here from the game list, we don't want to rescan when returning to the game list.
// But if we came here after UserDataActivity restarted the app, we do want to rescan.
if (savedInstanceState == null) {
MainPresenter.skipRescanningLibrary()
} else {
isMappingAllDevices = savedInstanceState.getBoolean(KEY_MAPPING_ALL_DEVICES)
}
binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding!!.root)
WindowCompat.setDecorFitsSystemWindows(window, false)
val launcher = intent
var gameID = launcher.getStringExtra(ARG_GAME_ID)
if (gameID == null) gameID = ""
val revision = launcher.getIntExtra(ARG_REVISION, 0)
val isWii = launcher.getBooleanExtra(ARG_IS_WII, true)
val menuTag = launcher.serializable<MenuTag>(ARG_MENU_TAG)
presenter = SettingsActivityPresenter(this, settings)
presenter!!.onCreate(savedInstanceState, menuTag, gameID, revision, isWii, this)
toolbarLayout = binding!!.toolbarSettingsLayout
setSupportActionBar(binding!!.toolbarSettings)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
// TODO: Remove this when CollapsingToolbarLayouts are fixed by Google
// https://github.com/material-components/material-components-android/issues/1310
ViewCompat.setOnApplyWindowInsetsListener(toolbarLayout!!, null)
setInsets()
enableScrollTint(this, binding!!.toolbarSettings, binding!!.appbarSettings)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
val inflater = menuInflater
inflater.inflate(R.menu.menu_settings, menu)
return true
}
override fun onSaveInstanceState(outState: Bundle) {
// Critical: If super method is not called, rotations will be busted.
super.onSaveInstanceState(outState)
presenter!!.saveState(outState)
outState.putBoolean(KEY_MAPPING_ALL_DEVICES, isMappingAllDevices)
}
override fun onStart() {
super.onStart()
presenter!!.onStart()
}
/**
* If this is called, the user has left the settings screen (potentially through the
* home button) and will expect their changes to be persisted.
*/
override fun onStop() {
super.onStop()
presenter!!.onStop(isFinishing)
}
override fun onDestroy() {
super.onDestroy()
presenter!!.onDestroy()
}
override fun showSettingsFragment(
menuTag: MenuTag,
extras: Bundle?,
addToStack: Boolean,
gameId: String
) {
if (!addToStack && fragment != null) return
val transaction = supportFragmentManager.beginTransaction()
if (addToStack) {
if (areSystemAnimationsEnabled()) {
transaction.setCustomAnimations(
R.anim.anim_settings_fragment_in,
R.anim.anim_settings_fragment_out,
0,
R.anim.anim_pop_settings_fragment_out
)
}
transaction.addToBackStack(null)
}
transaction.replace(
R.id.frame_content_settings,
newInstance(menuTag, gameId, extras), FRAGMENT_TAG
)
transaction.commit()
}
override fun showDialogFragment(fragment: DialogFragment) {
fragment.show(supportFragmentManager, FRAGMENT_DIALOG_TAG)
}
private fun areSystemAnimationsEnabled(): Boolean {
val duration = android.provider.Settings.Global.getFloat(
contentResolver,
android.provider.Settings.Global.ANIMATOR_DURATION_SCALE,
1f
)
val transition = android.provider.Settings.Global.getFloat(
contentResolver,
android.provider.Settings.Global.TRANSITION_ANIMATION_SCALE,
1f
)
return duration != 0f && transition != 0f
}
override fun onActivityResult(requestCode: Int, resultCode: Int, result: Intent?) {
super.onActivityResult(requestCode, resultCode, result)
// If the user picked a file, as opposed to just backing out.
if (resultCode == RESULT_OK) {
if (requestCode != MainPresenter.REQUEST_DIRECTORY) {
val uri = canonicalizeIfPossible(result!!.data!!)
val validExtensions: Set<String> =
if (requestCode == MainPresenter.REQUEST_GAME_FILE) FileBrowserHelper.GAME_EXTENSIONS else FileBrowserHelper.RAW_EXTENSION
var flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
if (requestCode != MainPresenter.REQUEST_GAME_FILE) flags =
flags or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
val takeFlags = flags and result.flags
FileBrowserHelper.runAfterExtensionCheck(this, uri, validExtensions) {
contentResolver.takePersistableUriPermission(uri, takeFlags)
fragment!!.adapter!!.onFilePickerConfirmation(uri.toString())
}
} else {
val path = FileBrowserHelper.getSelectedPath(result)
fragment!!.adapter!!.onFilePickerConfirmation(path!!)
}
}
}
private fun canonicalizeIfPossible(uri: Uri): Uri {
val canonicalizedUri = contentResolver.canonicalize(uri)
return canonicalizedUri ?: uri
}
override fun showLoading() {
if (dialog == null) {
dialog = MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.load_settings))
.setView(R.layout.dialog_indeterminate_progress)
.create()
}
dialog!!.show()
}
override fun hideLoading() {
dialog!!.dismiss()
}
override fun showGameIniJunkDeletionQuestion() {
MaterialAlertDialogBuilder(this)
.setTitle(getString(R.string.game_ini_junk_title))
.setMessage(getString(R.string.game_ini_junk_question))
.setPositiveButton(R.string.yes) { _: DialogInterface?, _: Int -> presenter!!.clearGameSettings() }
.setNegativeButton(R.string.no, null)
.show()
}
override fun onSettingsFileLoaded(settings: Settings) {
val fragment: SettingsFragmentView? = fragment
fragment?.onSettingsFileLoaded(settings)
}
override fun onSettingsFileNotFound() {
val fragment: SettingsFragmentView? = fragment
fragment?.loadDefaultSettings()
}
override fun showToastMessage(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
override fun onSettingChanged() {
presenter!!.onSettingChanged()
}
override fun onControllerSettingsChanged() {
fragment!!.onControllerSettingsChanged()
}
override fun onMenuTagAction(menuTag: MenuTag, value: Int) {
presenter!!.onMenuTagAction(menuTag, value)
}
override fun hasMenuTagActionForValue(menuTag: MenuTag, value: Int): Boolean {
return presenter!!.hasMenuTagActionForValue(menuTag, value)
}
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}
override fun setToolbarTitle(title: String) {
binding!!.toolbarSettingsLayout.title = title
}
override fun setOldControllerSettingsWarningVisibility(visible: Boolean): Int {
// We use INVISIBLE instead of GONE to avoid getting a stale height for the return value
binding!!.oldControllerSettingsWarning.visibility =
if (visible) View.VISIBLE else View.INVISIBLE
return if (visible) binding!!.oldControllerSettingsWarning.height else 0
}
private fun setInsets() {
ViewCompat.setOnApplyWindowInsetsListener(binding!!.appbarSettings) { _: View?, windowInsets: WindowInsetsCompat ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
InsetsHelper.insetAppBar(insets, binding!!.appbarSettings)
binding!!.frameContentSettings.setPadding(insets.left, 0, insets.right, 0)
val textPadding = resources.getDimensionPixelSize(R.dimen.spacing_large)
binding!!.oldControllerSettingsWarning.setPadding(
textPadding + insets.left,
textPadding,
textPadding + insets.right,
textPadding + insets.bottom
)
InsetsHelper.applyNavbarWorkaround(insets.bottom, binding!!.workaroundView)
setNavigationBarColor(
this,
MaterialColors.getColor(binding!!.appbarSettings, R.attr.colorSurface)
)
windowInsets
}
}
companion object {
private const val ARG_MENU_TAG = "menu_tag"
private const val ARG_GAME_ID = "game_id"
private const val ARG_REVISION = "revision"
private const val ARG_IS_WII = "is_wii"
private const val KEY_MAPPING_ALL_DEVICES = "all_devices"
private const val FRAGMENT_TAG = "settings"
private const val FRAGMENT_DIALOG_TAG = "settings_dialog"
@JvmStatic
fun launch(
context: Context,
menuTag: MenuTag?,
gameId: String?,
revision: Int,
isWii: Boolean
) {
val settings = Intent(context, SettingsActivity::class.java)
settings.putExtra(ARG_MENU_TAG, menuTag)
settings.putExtra(ARG_GAME_ID, gameId)
settings.putExtra(ARG_REVISION, revision)
settings.putExtra(ARG_IS_WII, isWii)
context.startActivity(settings)
}
@JvmStatic
fun launch(context: Context, menuTag: MenuTag?) {
val settings = Intent(context, SettingsActivity::class.java)
settings.putExtra(ARG_MENU_TAG, menuTag)
settings.putExtra(
ARG_IS_WII,
!NativeLibrary.IsRunning() || NativeLibrary.IsEmulatingWii()
)
context.startActivity(settings)
}
}
}

View File

@ -1,197 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui;
import android.os.Bundle;
import android.text.TextUtils;
import androidx.annotation.NonNull;
import androidx.core.app.ComponentActivity;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
import org.dolphinemu.dolphinemu.utils.Log;
public final class SettingsActivityPresenter
{
private static final String KEY_SHOULD_SAVE = "should_save";
private SettingsActivityView mView;
private Settings mSettings;
private boolean mShouldSave;
private MenuTag mMenuTag;
private String mGameId;
private int mRevision;
private boolean mIsWii;
private ComponentActivity mActivity;
SettingsActivityPresenter(SettingsActivityView view, Settings settings)
{
mView = view;
mSettings = settings;
}
public void onCreate(Bundle savedInstanceState, MenuTag menuTag, String gameId, int revision,
boolean isWii, ComponentActivity activity)
{
this.mMenuTag = menuTag;
this.mGameId = gameId;
this.mRevision = revision;
this.mIsWii = isWii;
this.mActivity = activity;
mShouldSave = savedInstanceState != null && savedInstanceState.getBoolean(KEY_SHOULD_SAVE);
}
public void onDestroy()
{
if (mSettings != null)
{
mSettings.close();
mSettings = null;
}
}
public void onStart()
{
prepareDolphinDirectoriesIfNeeded();
}
private void loadSettingsUI()
{
mView.hideLoading();
if (!mSettings.areSettingsLoaded())
{
if (!TextUtils.isEmpty(mGameId))
{
mSettings.loadSettings(mGameId, mRevision, mIsWii);
if (mSettings.gameIniContainsJunk())
{
mView.showGameIniJunkDeletionQuestion();
}
}
else
{
mSettings.loadSettings(mIsWii);
}
}
mView.showSettingsFragment(mMenuTag, null, false, mGameId);
mView.onSettingsFileLoaded(mSettings);
}
private void prepareDolphinDirectoriesIfNeeded()
{
mView.showLoading();
new AfterDirectoryInitializationRunner().runWithLifecycle(mActivity, this::loadSettingsUI);
}
public Settings getSettings()
{
return mSettings;
}
public void clearGameSettings()
{
mSettings.clearGameSettings();
onSettingChanged();
}
public void onStop(boolean finishing)
{
if (mSettings != null && finishing && mShouldSave)
{
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...");
mSettings.saveSettings(mActivity);
}
}
public void onSettingChanged()
{
mShouldSave = true;
}
public void saveState(Bundle outState)
{
outState.putBoolean(KEY_SHOULD_SAVE, mShouldSave);
}
public boolean shouldSave()
{
return mShouldSave;
}
public void onMenuTagAction(@NonNull MenuTag menuTag, int value)
{
if (menuTag.isSerialPort1Menu())
{
if (value != 0 && value != 255) // Not disabled or dummy
{
Bundle bundle = new Bundle();
bundle.putInt(SettingsFragmentPresenter.ARG_SERIALPORT1_TYPE, value);
mView.showSettingsFragment(menuTag, bundle, true, mGameId);
}
}
if (menuTag.isGCPadMenu())
{
if (value != 0) // Not disabled
{
Bundle bundle = new Bundle();
bundle.putInt(SettingsFragmentPresenter.ARG_CONTROLLER_TYPE, value);
mView.showSettingsFragment(menuTag, bundle, true, mGameId);
}
}
if (menuTag.isWiimoteMenu())
{
if (value == 1) // Emulated Wii Remote
{
mView.showSettingsFragment(menuTag, null, true, mGameId);
}
}
if (menuTag.isWiimoteExtensionMenu())
{
if (value != 0) // Not disabled
{
Bundle bundle = new Bundle();
bundle.putInt(SettingsFragmentPresenter.ARG_CONTROLLER_TYPE, value);
mView.showSettingsFragment(menuTag, bundle, true, mGameId);
}
}
}
public boolean hasMenuTagActionForValue(@NonNull MenuTag menuTag, int value)
{
if (menuTag.isSerialPort1Menu())
{
return (value != 0 && value != 255); // Not disabled or dummy
}
if (menuTag.isGCPadMenu())
{
return (value != 0); // Not disabled
}
if (menuTag.isWiimoteMenu())
{
return (value == 1); // Emulated Wii Remote
}
if (menuTag.isWiimoteExtensionMenu())
{
return (value != 0); // Not disabled
}
return false;
}
}

View File

@ -0,0 +1,147 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui
import android.os.Bundle
import android.text.TextUtils
import androidx.appcompat.app.AppCompatActivity
import org.dolphinemu.dolphinemu.features.settings.model.Settings
import org.dolphinemu.dolphinemu.utils.AfterDirectoryInitializationRunner
import org.dolphinemu.dolphinemu.utils.Log
class SettingsActivityPresenter(
private val activityView: SettingsActivityView,
var settings: Settings?
) {
private var shouldSave = false
private var menuTag: MenuTag? = null
private var gameId: String? = null
private var revision = 0
private var isWii = false
private lateinit var activity: AppCompatActivity
fun onCreate(
savedInstanceState: Bundle?,
menuTag: MenuTag?,
gameId: String?,
revision: Int,
isWii: Boolean,
activity: AppCompatActivity
) {
this.menuTag = menuTag
this.gameId = gameId
this.revision = revision
this.isWii = isWii
this.activity = activity
shouldSave = savedInstanceState != null && savedInstanceState.getBoolean(KEY_SHOULD_SAVE)
}
fun onDestroy() {
if (settings != null) {
settings!!.close()
settings = null
}
}
fun onStart() {
prepareDolphinDirectoriesIfNeeded()
}
private fun loadSettingsUI() {
activityView.hideLoading()
if (!settings!!.areSettingsLoaded()) {
if (!TextUtils.isEmpty(gameId)) {
settings!!.loadSettings(gameId!!, revision, isWii)
if (settings!!.gameIniContainsJunk()) {
activityView.showGameIniJunkDeletionQuestion()
}
} else {
settings!!.loadSettings(isWii)
}
}
activityView.showSettingsFragment(menuTag!!, null, false, gameId!!)
activityView.onSettingsFileLoaded(settings!!)
}
private fun prepareDolphinDirectoriesIfNeeded() {
activityView.showLoading()
AfterDirectoryInitializationRunner().runWithLifecycle(activity) { loadSettingsUI() }
}
fun clearGameSettings() {
settings!!.clearGameSettings()
onSettingChanged()
}
fun onStop(finishing: Boolean) {
if (settings != null && finishing && shouldSave) {
Log.debug("[SettingsActivity] Settings activity stopping. Saving settings to INI...")
settings!!.saveSettings(activity)
}
}
fun onSettingChanged() {
shouldSave = true
}
fun saveState(outState: Bundle) {
outState.putBoolean(KEY_SHOULD_SAVE, shouldSave)
}
fun onMenuTagAction(menuTag: MenuTag, value: Int) {
if (menuTag.isSerialPort1Menu) {
// Not disabled or dummy
if (value != 0 && value != 255) {
val bundle = Bundle()
bundle.putInt(SettingsFragmentPresenter.ARG_SERIALPORT1_TYPE, value)
activityView.showSettingsFragment(menuTag, bundle, true, gameId!!)
}
}
if (menuTag.isGCPadMenu) {
// Not disabled
if (value != 0)
{
val bundle = Bundle()
bundle.putInt(SettingsFragmentPresenter.ARG_CONTROLLER_TYPE, value)
activityView.showSettingsFragment(menuTag, bundle, true, gameId!!)
}
}
if (menuTag.isWiimoteMenu) {
// Emulated Wii Remote
if (value == 1) {
activityView.showSettingsFragment(menuTag, null, true, gameId!!)
}
}
if (menuTag.isWiimoteExtensionMenu) {
// Not disabled
if (value != 0) {
val bundle = Bundle()
bundle.putInt(SettingsFragmentPresenter.ARG_CONTROLLER_TYPE, value)
activityView.showSettingsFragment(menuTag, bundle, true, gameId!!)
}
}
}
fun hasMenuTagActionForValue(menuTag: MenuTag, value: Int): Boolean {
if (menuTag.isSerialPort1Menu) {
// Not disabled or dummy
return value != 0 && value != 255
}
if (menuTag.isGCPadMenu) {
// Not disabled
return value != 0
}
if (menuTag.isWiimoteMenu) {
// Emulated Wii Remote
return value == 1
}
return if (menuTag.isWiimoteExtensionMenu) {
// Not disabled
value != 0
} else false
}
companion object {
private const val KEY_SHOULD_SAVE = "should_save"
}
}

View File

@ -1,137 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
/**
* Abstraction for the Activity that manages SettingsFragments.
*/
public interface SettingsActivityView
{
/**
* Show a new SettingsFragment.
*
* @param menuTag Identifier for the settings group that should be displayed.
* @param addToStack Whether or not this fragment should replace a previous one.
*/
void showSettingsFragment(MenuTag menuTag, Bundle extras, boolean addToStack, String gameId);
/**
* Shows a DialogFragment.
*
* Only one can be shown at a time.
*/
void showDialogFragment(DialogFragment fragment);
/**
* Called by a contained Fragment to get access to the Setting HashMap
* loaded from disk, so that each Fragment doesn't need to perform its own
* read operation.
*
* @return A possibly null HashMap of Settings.
*/
Settings getSettings();
/**
* Called when an asynchronous load operation completes.
*
* @param settings The (possibly null) result of the ini load operation.
*/
void onSettingsFileLoaded(Settings settings);
/**
* Called when an asynchronous load operation fails.
*/
void onSettingsFileNotFound();
/**
* Display a popup text message on screen.
*
* @param message The contents of the onscreen message.
*/
void showToastMessage(String message);
/**
* End the activity.
*/
void finish();
/**
* Called by a containing Fragment to tell the Activity that a setting was changed;
* unless this has been called, the Activity will not save to disk.
*/
void onSettingChanged();
/**
* Refetches the values of all controller settings.
*
* To be used when loading an input profile or performing some other action that changes all
* controller settings at once.
*/
void onControllerSettingsChanged();
/**
* Called by a containing Fragment to tell the containing Activity that the user wants to open the
* MenuTag associated with a setting.
*
* @param menuTag The MenuTag of the setting.
* @param value The current value of the setting.
*/
void onMenuTagAction(@NonNull MenuTag menuTag, int value);
/**
* Returns whether anything will happen when the user wants to open the MenuTag associated with a
* setting, given the current value of the setting.
*
* @param menuTag The MenuTag of the setting.
* @param value The current value of the setting.
*/
boolean hasMenuTagActionForValue(@NonNull MenuTag menuTag, int value);
/**
* Show loading dialog while loading the settings
*/
void showLoading();
/**
* Hide the loading dialog
*/
void hideLoading();
/**
* Tell the user that there is junk in the game INI and ask if they want to delete the whole file.
*/
void showGameIniJunkDeletionQuestion();
/**
* Accesses the material toolbar layout and changes the title
*/
void setToolbarTitle(String title);
/**
* Sets whether the input mapping dialog should detect inputs from all devices,
* not just the device configured for the controller.
*/
void setMappingAllDevices(boolean allDevices);
/**
* Returns whether the input mapping dialog should detect inputs from all devices,
* not just the device configured for the controller.
*/
boolean isMappingAllDevices();
/**
* Shows or hides a warning telling the user that they're using incompatible controller settings.
* The warning is hidden by default.
*
* @param visible Whether the warning should be visible.
* @return The height of the warning view, or 0 if the view is now invisible.
*/
int setOldControllerSettingsWarningVisibility(boolean visible);
}

View File

@ -0,0 +1,135 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui
import android.os.Bundle
import androidx.fragment.app.DialogFragment
import org.dolphinemu.dolphinemu.features.settings.model.Settings
/**
* Abstraction for the Activity that manages SettingsFragments.
*/
interface SettingsActivityView {
/**
* Show a new SettingsFragment.
*
* @param menuTag Identifier for the settings group that should be displayed.
* @param addToStack Whether or not this fragment should replace a previous one.
*/
fun showSettingsFragment(
menuTag: MenuTag,
extras: Bundle?,
addToStack: Boolean,
gameId: String
)
/**
* Shows a DialogFragment.
*
* Only one can be shown at a time.
*/
fun showDialogFragment(fragment: DialogFragment)
/**
* Called by a contained Fragment to get access to the Setting HashMap
* loaded from disk, so that each Fragment doesn't need to perform its own
* read operation.
*
* @return A possibly null HashMap of Settings.
*/
val settings: Settings
/**
* Called when an asynchronous load operation completes.
*
* @param settings The (possibly null) result of the ini load operation.
*/
fun onSettingsFileLoaded(settings: Settings)
/**
* Called when an asynchronous load operation fails.
*/
fun onSettingsFileNotFound()
/**
* Display a popup text message on screen.
*
* @param message The contents of the onscreen message.
*/
fun showToastMessage(message: String)
/**
* End the activity.
*/
fun finish()
/**
* Called by a containing Fragment to tell the Activity that a Setting was changed;
* unless this has been called, the Activity will not save to disk.
*/
fun onSettingChanged()
/**
* Refetches the values of all controller settings.
*
* To be used when loading an input profile or performing some other action that changes all
* controller settings at once.
*/
fun onControllerSettingsChanged()
/**
* Called by a containing Fragment to tell the containing Activity that the user wants to open the
* MenuTag associated with a Setting.
*
* @param menuTag The MenuTag of the Setting.
* @param value The current value of the Setting.
*/
fun onMenuTagAction(menuTag: MenuTag, value: Int)
/**
* Returns whether anything will happen when the user wants to open the MenuTag associated with a
* Setting, given the current value of the Setting.
*
* @param menuTag The MenuTag of the Setting.
* @param value The current value of the Setting.
*/
fun hasMenuTagActionForValue(menuTag: MenuTag, value: Int): Boolean
/**
* Show loading dialog while loading the settings
*/
fun showLoading()
/**
* Hide the loading dialog
*/
fun hideLoading()
/**
* Tell the user that there is junk in the game INI and ask if they want to delete the whole file.
*/
fun showGameIniJunkDeletionQuestion()
/**
* Accesses the material toolbar layout and changes the title
*/
fun setToolbarTitle(title: String)
/**
* Returns whether the input mapping dialog should detect inputs from all devices,
* not just the device configured for the controller.
*/
/**
* Sets whether the input mapping dialog should detect inputs from all devices,
* not just the device configured for the controller.
*/
var isMappingAllDevices: Boolean
/**
* Shows or hides a warning telling the user that they're using incompatible controller settings.
* The warning is hidden by default.
*
* @param visible Whether the warning should be visible.
* @return The height of the warning view, or 0 if the view is now invisible.
*/
fun setOldControllerSettingsWarningVisibility(visible: Boolean): Int
}

View File

@ -1,703 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.provider.DocumentsContract;
import android.text.format.DateFormat;
import android.view.LayoutInflater;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.ColorInt;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.color.MaterialColors;
import com.google.android.material.datepicker.CalendarConstraints;
import com.google.android.material.datepicker.MaterialDatePicker;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.elevation.ElevationOverlayProvider;
import com.google.android.material.slider.Slider;
import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.timepicker.MaterialTimePicker;
import com.google.android.material.timepicker.TimeFormat;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.DialogAdvancedMappingBinding;
import org.dolphinemu.dolphinemu.databinding.DialogInputStringBinding;
import org.dolphinemu.dolphinemu.databinding.DialogSliderBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemMappingBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingSwitchBinding;
import org.dolphinemu.dolphinemu.databinding.ListItemSubmenuBinding;
import org.dolphinemu.dolphinemu.features.input.ui.AdvancedMappingDialog;
import org.dolphinemu.dolphinemu.features.input.ui.MotionAlertDialog;
import org.dolphinemu.dolphinemu.features.input.model.view.InputMappingControlSetting;
import org.dolphinemu.dolphinemu.features.input.ui.viewholder.InputMappingControlSettingViewHolder;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.view.DateTimeChoiceSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SwitchSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker;
import org.dolphinemu.dolphinemu.features.settings.model.view.FloatSliderSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.IntSliderSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSettingDynamicDescriptions;
import org.dolphinemu.dolphinemu.features.settings.model.view.SliderSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.InputStringSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.StringSingleChoiceSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SubmenuSetting;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.DateTimeSettingViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.FilePickerViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.HeaderHyperLinkViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.HeaderViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.InputStringSettingViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.RunRunnableViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SettingViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SingleChoiceViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SliderViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SubmenuViewHolder;
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SwitchSettingViewHolder;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
import org.dolphinemu.dolphinemu.utils.Log;
import org.dolphinemu.dolphinemu.utils.PermissionsHandler;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.TimeZone;
public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder>
implements DialogInterface.OnClickListener, Slider.OnChangeListener
{
private final SettingsFragmentView mView;
private final Context mContext;
private ArrayList<SettingsItem> mSettings;
private SettingsItem mClickedItem;
private int mClickedPosition;
private int mSeekbarProgress;
private AlertDialog mDialog;
private TextView mTextSliderValue;
public SettingsAdapter(SettingsFragmentView view, Context context)
{
mView = view;
mContext = context;
mClickedPosition = -1;
}
@NonNull
@Override
public SettingViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
{
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
switch (viewType)
{
case SettingsItem.TYPE_HEADER:
return new HeaderViewHolder(ListItemHeaderBinding.inflate(inflater), this);
case SettingsItem.TYPE_SWITCH:
return new SwitchSettingViewHolder(ListItemSettingSwitchBinding.inflate(inflater),
this);
case SettingsItem.TYPE_STRING_SINGLE_CHOICE:
case SettingsItem.TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS:
case SettingsItem.TYPE_SINGLE_CHOICE:
return new SingleChoiceViewHolder(ListItemSettingBinding.inflate(inflater), this);
case SettingsItem.TYPE_SLIDER:
return new SliderViewHolder(ListItemSettingBinding.inflate(inflater), this, mContext);
case SettingsItem.TYPE_SUBMENU:
return new SubmenuViewHolder(ListItemSubmenuBinding.inflate(inflater), this);
case SettingsItem.TYPE_INPUT_MAPPING_CONTROL:
return new InputMappingControlSettingViewHolder(ListItemMappingBinding.inflate(inflater),
this);
case SettingsItem.TYPE_FILE_PICKER:
return new FilePickerViewHolder(ListItemSettingBinding.inflate(inflater), this);
case SettingsItem.TYPE_RUN_RUNNABLE:
return new RunRunnableViewHolder(ListItemSettingBinding.inflate(inflater), this, mContext);
case SettingsItem.TYPE_STRING:
return new InputStringSettingViewHolder(ListItemSettingBinding.inflate(inflater), this);
case SettingsItem.TYPE_HYPERLINK_HEADER:
return new HeaderHyperLinkViewHolder(ListItemHeaderBinding.inflate(inflater), this);
case SettingsItem.TYPE_DATETIME_CHOICE:
return new DateTimeSettingViewHolder(ListItemSettingBinding.inflate(inflater), this);
default:
throw new IllegalArgumentException("Invalid view type: " + viewType);
}
}
@Override
public void onBindViewHolder(@NonNull SettingViewHolder holder, int position)
{
holder.bind(getItem(position));
}
private SettingsItem getItem(int position)
{
return mSettings.get(position);
}
@Override
public int getItemCount()
{
if (mSettings != null)
{
return mSettings.size();
}
else
{
return 0;
}
}
@Override
public int getItemViewType(int position)
{
return getItem(position).getType();
}
public Settings getSettings()
{
return mView.getSettings();
}
public void setSettings(ArrayList<SettingsItem> settings)
{
mSettings = settings;
notifyDataSetChanged();
}
public void clearSetting(SettingsItem item)
{
item.clear(getSettings());
mView.onSettingChanged();
}
public void notifyAllSettingsChanged()
{
notifyItemRangeChanged(0, getItemCount());
mView.onSettingChanged();
}
public void onBooleanClick(SwitchSetting item, boolean checked)
{
item.setChecked(getSettings(), checked);
mView.onSettingChanged();
}
public void onInputStringClick(InputStringSetting item, int position)
{
LayoutInflater inflater = LayoutInflater.from(mContext);
DialogInputStringBinding binding = DialogInputStringBinding.inflate(inflater);
TextInputEditText input = binding.input;
input.setText(item.getSelectedValue());
mDialog = new MaterialAlertDialogBuilder(mView.getActivity())
.setView(binding.getRoot())
.setMessage(item.getDescription())
.setPositiveButton(R.string.ok, (dialogInterface, i) ->
{
String editTextInput = input.getText().toString();
if (!item.getSelectedValue().equals(editTextInput))
{
notifyItemChanged(position);
mView.onSettingChanged();
}
item.setSelectedValue(mView.getSettings(), editTextInput);
})
.setNegativeButton(R.string.cancel, null)
.show();
}
public void onSingleChoiceClick(SingleChoiceSetting item, int position)
{
mClickedItem = item;
mClickedPosition = position;
int value = getSelectionForSingleChoiceValue(item);
mDialog = new MaterialAlertDialogBuilder(mView.getActivity())
.setTitle(item.getName())
.setSingleChoiceItems(item.getChoicesId(), value, this)
.show();
}
public void onStringSingleChoiceClick(StringSingleChoiceSetting item, int position)
{
mClickedItem = item;
mClickedPosition = position;
item.refreshChoicesAndValues();
String[] choices = item.getChoices();
int noChoicesAvailableString = item.getNoChoicesAvailableString();
if (noChoicesAvailableString != 0 && choices.length == 0)
{
mDialog = new MaterialAlertDialogBuilder(mView.getActivity())
.setTitle(item.getName())
.setMessage(noChoicesAvailableString)
.setPositiveButton(R.string.ok, null)
.show();
}
else
{
mDialog = new MaterialAlertDialogBuilder(mView.getActivity())
.setTitle(item.getName())
.setSingleChoiceItems(item.getChoices(), item.getSelectedValueIndex(),
this)
.show();
}
}
public void onSingleChoiceDynamicDescriptionsClick(SingleChoiceSettingDynamicDescriptions item,
int position)
{
mClickedItem = item;
mClickedPosition = position;
int value = getSelectionForSingleChoiceDynamicDescriptionsValue(item);
mDialog = new MaterialAlertDialogBuilder(mView.getActivity())
.setTitle(item.getName())
.setSingleChoiceItems(item.getChoicesId(), value, this)
.show();
}
public void onSliderClick(SliderSetting item, int position)
{
mClickedItem = item;
mClickedPosition = position;
mSeekbarProgress = item.getSelectedValue();
LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
DialogSliderBinding binding = DialogSliderBinding.inflate(inflater);
mTextSliderValue = binding.textValue;
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
binding.textUnits.setText(item.getUnits());
Slider slider = binding.slider;
slider.setValueFrom(item.getMin());
slider.setValueTo(item.getMax());
slider.setValue(mSeekbarProgress);
slider.setStepSize(item.getStepSize());
slider.addOnChangeListener(this);
mDialog = new MaterialAlertDialogBuilder(mView.getActivity())
.setTitle(item.getName())
.setView(binding.getRoot())
.setPositiveButton(R.string.ok, this)
.show();
}
public void onSubmenuClick(SubmenuSetting item)
{
mView.loadSubMenu(item.getMenuKey());
}
public void onInputMappingClick(final InputMappingControlSetting item, final int position)
{
if (item.getController().getDefaultDevice().isEmpty() && !mView.isMappingAllDevices())
{
new MaterialAlertDialogBuilder(mView.getActivity())
.setMessage(R.string.input_binding_no_device)
.setPositiveButton(R.string.ok, this)
.show();
return;
}
final MotionAlertDialog dialog = new MotionAlertDialog(mView.getActivity(), item,
mView.isMappingAllDevices());
Drawable background = ContextCompat.getDrawable(mContext, R.drawable.dialog_round);
@ColorInt int color = new ElevationOverlayProvider(dialog.getContext()).compositeOverlay(
MaterialColors.getColor(dialog.getWindow().getDecorView(), R.attr.colorSurface),
dialog.getWindow().getDecorView().getElevation());
background.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
dialog.getWindow().setBackgroundDrawable(background);
dialog.setTitle(R.string.input_binding);
dialog.setMessage(String.format(mContext.getString(R.string.input_binding_description),
item.getName()));
dialog.setButton(AlertDialog.BUTTON_NEGATIVE, mContext.getString(R.string.cancel), this);
dialog.setButton(AlertDialog.BUTTON_NEUTRAL, mContext.getString(R.string.clear),
(dialogInterface, i) -> item.clearValue());
dialog.setOnDismissListener(dialog1 ->
{
notifyItemChanged(position);
mView.onSettingChanged();
});
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
public void onAdvancedInputMappingClick(final InputMappingControlSetting item, final int position)
{
LayoutInflater inflater = LayoutInflater.from(mContext);
DialogAdvancedMappingBinding binding = DialogAdvancedMappingBinding.inflate(inflater);
final AdvancedMappingDialog dialog = new AdvancedMappingDialog(mContext, binding,
item.getControlReference(), item.getController());
Drawable background = ContextCompat.getDrawable(mContext, R.drawable.dialog_round);
@ColorInt int color = new ElevationOverlayProvider(dialog.getContext()).compositeOverlay(
MaterialColors.getColor(dialog.getWindow().getDecorView(), R.attr.colorSurface),
dialog.getWindow().getDecorView().getElevation());
background.setColorFilter(color, PorterDuff.Mode.SRC_ATOP);
dialog.getWindow().setBackgroundDrawable(background);
dialog.setTitle(item.isInput() ?
R.string.input_configure_input : R.string.input_configure_output);
dialog.setView(binding.getRoot());
dialog.setButton(AlertDialog.BUTTON_POSITIVE, mContext.getString(R.string.ok),
(dialogInterface, i) ->
{
item.setValue(dialog.getExpression());
notifyItemChanged(position);
mView.onSettingChanged();
});
dialog.setButton(AlertDialog.BUTTON_NEGATIVE, mContext.getString(R.string.cancel), this);
dialog.setButton(AlertDialog.BUTTON_NEUTRAL, mContext.getString(R.string.clear),
(dialogInterface, i) ->
{
item.clearValue();
notifyItemChanged(position);
mView.onSettingChanged();
});
dialog.setCanceledOnTouchOutside(false);
dialog.show();
}
public void onFilePickerDirectoryClick(SettingsItem item, int position)
{
mClickedItem = item;
mClickedPosition = position;
if (!PermissionsHandler.isExternalStorageLegacy())
{
new MaterialAlertDialogBuilder(mContext)
.setMessage(R.string.path_not_changeable_scoped_storage)
.setPositiveButton(R.string.ok, (dialog, i) -> dialog.dismiss())
.show();
}
else
{
FileBrowserHelper.openDirectoryPicker(mView.getActivity(), FileBrowserHelper.GAME_EXTENSIONS);
}
}
public void onFilePickerFileClick(SettingsItem item, int position)
{
mClickedItem = item;
mClickedPosition = position;
FilePicker filePicker = (FilePicker) item;
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
intent.addCategory(Intent.CATEGORY_OPENABLE);
intent.setType("*/*");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, filePicker.getSelectedValue());
}
mView.getActivity().startActivityForResult(intent, filePicker.getRequestType());
}
public void onDateTimeClick(DateTimeChoiceSetting item, int position)
{
mClickedItem = item;
mClickedPosition = position;
long storedTime = Long.decode(item.getSelectedValue()) * 1000;
// Helper to extract hour and minute from epoch time
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(storedTime);
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
// Start and end epoch times available for the Wii's date picker
CalendarConstraints calendarConstraints = new CalendarConstraints.Builder()
.setStart(946684800000L)
.setEnd(2082672000000L)
.build();
int timeFormat = TimeFormat.CLOCK_12H;
if (DateFormat.is24HourFormat(mView.getActivity()))
{
timeFormat = TimeFormat.CLOCK_24H;
}
MaterialDatePicker<Long> datePicker = MaterialDatePicker.Builder.datePicker()
.setSelection(storedTime)
.setTitleText(R.string.select_rtc_date)
.setCalendarConstraints(calendarConstraints)
.build();
MaterialTimePicker timePicker = new MaterialTimePicker.Builder()
.setTimeFormat(timeFormat)
.setHour(calendar.get(Calendar.HOUR_OF_DAY))
.setMinute(calendar.get(Calendar.MINUTE))
.setTitleText(R.string.select_rtc_time)
.build();
datePicker.addOnPositiveButtonClickListener(
selection -> timePicker.show(mView.getActivity().getSupportFragmentManager(),
"TimePicker"));
timePicker.addOnPositiveButtonClickListener(selection ->
{
long epochTime = datePicker.getSelection() / 1000;
epochTime += (long) timePicker.getHour() * 60 * 60;
epochTime += (long) timePicker.getMinute() * 60;
String rtcString = "0x" + Long.toHexString(epochTime);
if (!item.getSelectedValue().equals(rtcString))
{
notifyItemChanged(mClickedPosition);
mView.onSettingChanged();
}
item.setSelectedValue(mView.getSettings(), rtcString);
mClickedItem = null;
});
datePicker.show(mView.getActivity().getSupportFragmentManager(), "DatePicker");
}
public void onFilePickerConfirmation(String selectedFile)
{
FilePicker filePicker = (FilePicker) mClickedItem;
if (!filePicker.getSelectedValue().equals(selectedFile))
{
notifyItemChanged(mClickedPosition);
mView.onSettingChanged();
}
filePicker.setSelectedValue(mView.getSettings(), selectedFile);
mClickedItem = null;
}
public static void clearLog()
{
// Don't delete the log in case it is being monitored by another app.
File log = new File(DirectoryInitialization.getUserDirectory() + "/Logs/dolphin.log");
try
{
RandomAccessFile raf = new RandomAccessFile(log, "rw");
raf.setLength(0);
}
catch (IOException e)
{
Log.error("[SettingsAdapter] Failed to clear log file: " + e.getMessage());
}
}
public void onMenuTagAction(@NonNull MenuTag menuTag, int value)
{
mView.onMenuTagAction(menuTag, value);
}
public boolean hasMenuTagActionForValue(@NonNull MenuTag menuTag, int value)
{
return mView.hasMenuTagActionForValue(menuTag, value);
}
@Override
public void onClick(DialogInterface dialog, int which)
{
if (mClickedItem instanceof SingleChoiceSetting)
{
SingleChoiceSetting scSetting = (SingleChoiceSetting) mClickedItem;
int value = getValueForSingleChoiceSelection(scSetting, which);
if (scSetting.getSelectedValue() != value)
mView.onSettingChanged();
scSetting.setSelectedValue(getSettings(), value);
closeDialog();
}
else if (mClickedItem instanceof SingleChoiceSettingDynamicDescriptions)
{
SingleChoiceSettingDynamicDescriptions scSetting =
(SingleChoiceSettingDynamicDescriptions) mClickedItem;
int value = getValueForSingleChoiceDynamicDescriptionsSelection(scSetting, which);
if (scSetting.getSelectedValue() != value)
mView.onSettingChanged();
scSetting.setSelectedValue(getSettings(), value);
closeDialog();
}
else if (mClickedItem instanceof StringSingleChoiceSetting)
{
StringSingleChoiceSetting scSetting = (StringSingleChoiceSetting) mClickedItem;
String value = scSetting.getValueAt(which);
if (!scSetting.getSelectedValue().equals(value))
mView.onSettingChanged();
scSetting.setSelectedValue(getSettings(), value);
closeDialog();
}
else if (mClickedItem instanceof IntSliderSetting)
{
IntSliderSetting sliderSetting = (IntSliderSetting) mClickedItem;
if (sliderSetting.getSelectedValue() != mSeekbarProgress)
mView.onSettingChanged();
sliderSetting.setSelectedValue(getSettings(), mSeekbarProgress);
closeDialog();
}
else if (mClickedItem instanceof FloatSliderSetting)
{
FloatSliderSetting sliderSetting = (FloatSliderSetting) mClickedItem;
if (sliderSetting.getSelectedValue() != mSeekbarProgress)
mView.onSettingChanged();
sliderSetting.setSelectedValue(getSettings(), mSeekbarProgress);
closeDialog();
}
mClickedItem = null;
mSeekbarProgress = -1;
}
public void closeDialog()
{
if (mDialog != null)
{
if (mClickedPosition != -1)
{
notifyItemChanged(mClickedPosition);
mClickedPosition = -1;
}
mDialog.dismiss();
mDialog = null;
}
}
@Override
public void onValueChange(@NonNull Slider slider, float progress, boolean fromUser)
{
mSeekbarProgress = (int) progress;
mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
}
private int getValueForSingleChoiceSelection(SingleChoiceSetting item, int which)
{
int valuesId = item.getValuesId();
if (valuesId > 0)
{
int[] valuesArray = mContext.getResources().getIntArray(valuesId);
return valuesArray[which];
}
else
{
return which;
}
}
private int getSelectionForSingleChoiceValue(SingleChoiceSetting item)
{
int value = item.getSelectedValue();
int valuesId = item.getValuesId();
if (valuesId > 0)
{
int[] valuesArray = mContext.getResources().getIntArray(valuesId);
for (int index = 0; index < valuesArray.length; index++)
{
int current = valuesArray[index];
if (current == value)
{
return index;
}
}
}
else
{
return value;
}
return -1;
}
private int getValueForSingleChoiceDynamicDescriptionsSelection(
SingleChoiceSettingDynamicDescriptions item, int which)
{
int valuesId = item.getValuesId();
if (valuesId > 0)
{
int[] valuesArray = mContext.getResources().getIntArray(valuesId);
return valuesArray[which];
}
else
{
return which;
}
}
private int getSelectionForSingleChoiceDynamicDescriptionsValue(
SingleChoiceSettingDynamicDescriptions item)
{
int value = item.getSelectedValue();
int valuesId = item.getValuesId();
if (valuesId > 0)
{
int[] valuesArray = mContext.getResources().getIntArray(valuesId);
for (int index = 0; index < valuesArray.length; index++)
{
int current = valuesArray[index];
if (current == value)
{
return index;
}
}
}
else
{
return value;
}
return -1;
}
}

View File

@ -0,0 +1,590 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.graphics.PorterDuff
import android.os.Build
import android.provider.DocumentsContract
import android.text.format.DateFormat
import android.view.LayoutInflater
import android.view.ViewGroup
import android.widget.TextView
import androidx.annotation.ColorInt
import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.color.MaterialColors
import com.google.android.material.datepicker.CalendarConstraints
import com.google.android.material.datepicker.MaterialDatePicker
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.elevation.ElevationOverlayProvider
import com.google.android.material.slider.Slider
import com.google.android.material.timepicker.MaterialTimePicker
import com.google.android.material.timepicker.TimeFormat
import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.databinding.*
import org.dolphinemu.dolphinemu.features.input.model.view.InputMappingControlSetting
import org.dolphinemu.dolphinemu.features.input.ui.AdvancedMappingDialog
import org.dolphinemu.dolphinemu.features.input.ui.MotionAlertDialog
import org.dolphinemu.dolphinemu.features.input.ui.viewholder.InputMappingControlSettingViewHolder
import org.dolphinemu.dolphinemu.features.settings.model.Settings
import org.dolphinemu.dolphinemu.features.settings.model.view.*
import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.*
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper
import org.dolphinemu.dolphinemu.utils.Log
import org.dolphinemu.dolphinemu.utils.PermissionsHandler
import java.io.File
import java.io.IOException
import java.io.RandomAccessFile
import java.util.*
class SettingsAdapter(
private val fragmentView: SettingsFragmentView,
private val context: Context
) :
RecyclerView.Adapter<SettingViewHolder>(), DialogInterface.OnClickListener,
Slider.OnChangeListener {
private var settingsList: ArrayList<SettingsItem>? = null
private var clickedItem: SettingsItem? = null
private var clickedPosition: Int = -1
private var seekbarProgress = 0
private var dialog: AlertDialog? = null
private var textSliderValue: TextView? = null
val settings: Settings?
get() = fragmentView.settings
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
SettingsItem.TYPE_HEADER -> HeaderViewHolder(
ListItemHeaderBinding.inflate(inflater),
this
)
SettingsItem.TYPE_SWITCH -> SwitchSettingViewHolder(
ListItemSettingSwitchBinding.inflate(inflater),
this
)
SettingsItem.TYPE_STRING_SINGLE_CHOICE,
SettingsItem.TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS,
SettingsItem.TYPE_SINGLE_CHOICE -> SingleChoiceViewHolder(
ListItemSettingBinding.inflate(inflater),
this
)
SettingsItem.TYPE_SLIDER -> SliderViewHolder(
ListItemSettingBinding.inflate(
inflater
), this, context
)
SettingsItem.TYPE_SUBMENU -> SubmenuViewHolder(
ListItemSubmenuBinding.inflate(
inflater
), this
)
SettingsItem.TYPE_INPUT_MAPPING_CONTROL -> InputMappingControlSettingViewHolder(
ListItemMappingBinding.inflate(inflater),
this
)
SettingsItem.TYPE_FILE_PICKER -> FilePickerViewHolder(
ListItemSettingBinding.inflate(
inflater
), this
)
SettingsItem.TYPE_RUN_RUNNABLE -> RunRunnableViewHolder(
ListItemSettingBinding.inflate(
inflater
), this, context
)
SettingsItem.TYPE_STRING -> InputStringSettingViewHolder(
ListItemSettingBinding.inflate(
inflater
), this
)
SettingsItem.TYPE_HYPERLINK_HEADER -> HeaderHyperLinkViewHolder(
ListItemHeaderBinding.inflate(
inflater
), this
)
SettingsItem.TYPE_DATETIME_CHOICE -> DateTimeSettingViewHolder(
ListItemSettingBinding.inflate(
inflater
), this
)
else -> throw IllegalArgumentException("Invalid view type: $viewType")
}
}
override fun onBindViewHolder(holder: SettingViewHolder, position: Int) {
holder.bind(getItem(position))
}
private fun getItem(position: Int): SettingsItem {
return settingsList!![position]
}
override fun getItemCount(): Int {
return if (settingsList != null) {
settingsList!!.size
} else {
0
}
}
override fun getItemViewType(position: Int): Int {
return getItem(position).type
}
fun setSettings(settings: ArrayList<SettingsItem>?) {
settingsList = settings
notifyDataSetChanged()
}
fun clearSetting(item: SettingsItem) {
item.clear(settings!!)
fragmentView.onSettingChanged()
}
fun notifyAllSettingsChanged() {
notifyItemRangeChanged(0, itemCount)
fragmentView.onSettingChanged()
}
fun onBooleanClick(item: SwitchSetting, checked: Boolean) {
item.setChecked(settings, checked)
fragmentView.onSettingChanged()
}
fun onInputStringClick(item: InputStringSetting, position: Int) {
val inflater = LayoutInflater.from(context)
val binding = DialogInputStringBinding.inflate(inflater)
val input = binding.input
input.setText(item.selectedValue)
dialog = MaterialAlertDialogBuilder(fragmentView.fragmentActivity)
.setView(binding.root)
.setMessage(item.description)
.setPositiveButton(R.string.ok) { _: DialogInterface?, _: Int ->
val editTextInput = input.text.toString()
if (item.selectedValue != editTextInput) {
notifyItemChanged(position)
fragmentView.onSettingChanged()
}
item.setSelectedValue(fragmentView.settings!!, editTextInput)
}
.setNegativeButton(R.string.cancel, null)
.show()
}
fun onSingleChoiceClick(item: SingleChoiceSetting, position: Int) {
clickedItem = item
clickedPosition = position
val value = getSelectionForSingleChoiceValue(item)
dialog = MaterialAlertDialogBuilder(fragmentView.fragmentActivity)
.setTitle(item.name)
.setSingleChoiceItems(item.choicesId, value, this)
.show()
}
fun onStringSingleChoiceClick(item: StringSingleChoiceSetting, position: Int) {
clickedItem = item
clickedPosition = position
item.refreshChoicesAndValues()
val choices = item.choices
val noChoicesAvailableString = item.noChoicesAvailableString
dialog = if (noChoicesAvailableString != 0 && choices!!.isEmpty()) {
MaterialAlertDialogBuilder(fragmentView.fragmentActivity)
.setTitle(item.name)
.setMessage(noChoicesAvailableString)
.setPositiveButton(R.string.ok, null)
.show()
} else {
MaterialAlertDialogBuilder(fragmentView.fragmentActivity)
.setTitle(item.name)
.setSingleChoiceItems(
item.choices, item.selectedValueIndex,
this
)
.show()
}
}
fun onSingleChoiceDynamicDescriptionsClick(
item: SingleChoiceSettingDynamicDescriptions,
position: Int
) {
clickedItem = item
clickedPosition = position
val value = getSelectionForSingleChoiceDynamicDescriptionsValue(item)
dialog = MaterialAlertDialogBuilder(fragmentView.fragmentActivity)
.setTitle(item.name)
.setSingleChoiceItems(item.choicesId, value, this)
.show()
}
fun onSliderClick(item: SliderSetting, position: Int) {
clickedItem = item
clickedPosition = position
seekbarProgress = item.selectedValue
val inflater = LayoutInflater.from(fragmentView.fragmentActivity)
val binding = DialogSliderBinding.inflate(inflater)
textSliderValue = binding.textValue
textSliderValue!!.text = seekbarProgress.toString()
binding.textUnits.text = item.units
val slider = binding.slider
slider.valueFrom = item.min.toFloat()
slider.valueTo = item.max.toFloat()
slider.value = seekbarProgress.toFloat()
slider.stepSize = item.stepSize.toFloat()
slider.addOnChangeListener(this)
dialog = MaterialAlertDialogBuilder(fragmentView.fragmentActivity)
.setTitle(item.name)
.setView(binding.root)
.setPositiveButton(R.string.ok, this)
.show()
}
fun onSubmenuClick(item: SubmenuSetting) {
fragmentView.loadSubMenu(item.menuKey)
}
fun onInputMappingClick(item: InputMappingControlSetting, position: Int) {
if (item.controller.defaultDevice.isEmpty() && !fragmentView.isMappingAllDevices) {
MaterialAlertDialogBuilder(fragmentView.fragmentActivity)
.setMessage(R.string.input_binding_no_device)
.setPositiveButton(R.string.ok, this)
.show()
return
}
val dialog = MotionAlertDialog(
fragmentView.fragmentActivity, item,
fragmentView.isMappingAllDevices
)
val background = ContextCompat.getDrawable(context, R.drawable.dialog_round)
@ColorInt val color = ElevationOverlayProvider(dialog.context).compositeOverlay(
MaterialColors.getColor(dialog.window!!.decorView, R.attr.colorSurface),
dialog.window!!.decorView.elevation
)
background!!.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
dialog.window!!.setBackgroundDrawable(background)
dialog.setTitle(R.string.input_binding)
dialog.setMessage(
String.format(
context.getString(R.string.input_binding_description),
item.name
)
)
dialog.setButton(AlertDialog.BUTTON_NEGATIVE, context.getString(R.string.cancel), this)
dialog.setButton(
AlertDialog.BUTTON_NEUTRAL,
context.getString(R.string.clear)
) { _: DialogInterface?, _: Int -> item.clearValue() }
dialog.setOnDismissListener {
notifyItemChanged(position)
fragmentView.onSettingChanged()
}
dialog.setCanceledOnTouchOutside(false)
dialog.show()
}
fun onAdvancedInputMappingClick(item: InputMappingControlSetting, position: Int) {
val inflater = LayoutInflater.from(context)
val binding = DialogAdvancedMappingBinding.inflate(inflater)
val dialog = AdvancedMappingDialog(
context,
binding,
item.controlReference,
item.controller
)
val background = ContextCompat.getDrawable(context, R.drawable.dialog_round)
@ColorInt val color = ElevationOverlayProvider(dialog.context).compositeOverlay(
MaterialColors.getColor(dialog.window!!.decorView, R.attr.colorSurface),
dialog.window!!.decorView.elevation
)
background!!.setColorFilter(color, PorterDuff.Mode.SRC_ATOP)
dialog.window!!.setBackgroundDrawable(background)
dialog.setTitle(if (item.isInput) R.string.input_configure_input else R.string.input_configure_output)
dialog.setView(binding.root)
dialog.setButton(
AlertDialog.BUTTON_POSITIVE, context.getString(R.string.ok)
) { _: DialogInterface?, _: Int ->
item.value = dialog.expression
notifyItemChanged(position)
fragmentView.onSettingChanged()
}
dialog.setButton(AlertDialog.BUTTON_NEGATIVE, context.getString(R.string.cancel), this)
dialog.setButton(
AlertDialog.BUTTON_NEUTRAL,
context.getString(R.string.clear)
) { _: DialogInterface?, _: Int ->
item.clearValue()
notifyItemChanged(position)
fragmentView.onSettingChanged()
}
dialog.setCanceledOnTouchOutside(false)
dialog.show()
}
fun onFilePickerDirectoryClick(item: SettingsItem?, position: Int) {
clickedItem = item
clickedPosition = position
if (!PermissionsHandler.isExternalStorageLegacy()) {
MaterialAlertDialogBuilder(context)
.setMessage(R.string.path_not_changeable_scoped_storage)
.setPositiveButton(R.string.ok) { dialog: DialogInterface, _: Int -> dialog.dismiss() }
.show()
} else {
FileBrowserHelper.openDirectoryPicker(
fragmentView.fragmentActivity,
FileBrowserHelper.GAME_EXTENSIONS
)
}
}
fun onFilePickerFileClick(item: SettingsItem, position: Int) {
clickedItem = item
clickedPosition = position
val filePicker = item as FilePicker
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "*/*"
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
intent.putExtra(DocumentsContract.EXTRA_INITIAL_URI, filePicker.getSelectedValue())
}
fragmentView.fragmentActivity.startActivityForResult(intent, filePicker.requestType)
}
fun onDateTimeClick(item: DateTimeChoiceSetting, position: Int) {
clickedItem = item
clickedPosition = position
val storedTime = java.lang.Long.decode(item.getSelectedValue()) * 1000
// Helper to extract hour and minute from epoch time
val calendar = Calendar.getInstance()
calendar.timeInMillis = storedTime
calendar.timeZone = TimeZone.getTimeZone("UTC")
// Start and end epoch times available for the Wii's date picker
val calendarConstraints = CalendarConstraints.Builder()
.setStart(946684800000L)
.setEnd(2082672000000L)
.build()
var timeFormat = TimeFormat.CLOCK_12H
if (DateFormat.is24HourFormat(fragmentView.fragmentActivity)) {
timeFormat = TimeFormat.CLOCK_24H
}
val datePicker = MaterialDatePicker.Builder.datePicker()
.setSelection(storedTime)
.setTitleText(R.string.select_rtc_date)
.setCalendarConstraints(calendarConstraints)
.build()
val timePicker = MaterialTimePicker.Builder()
.setTimeFormat(timeFormat)
.setHour(calendar[Calendar.HOUR_OF_DAY])
.setMinute(calendar[Calendar.MINUTE])
.setTitleText(R.string.select_rtc_time)
.build()
datePicker.addOnPositiveButtonClickListener {
timePicker.show(
fragmentView.fragmentActivity.supportFragmentManager,
"TimePicker"
)
}
timePicker.addOnPositiveButtonClickListener {
var epochTime = datePicker.selection!! / 1000
epochTime += timePicker.hour.toLong() * 60 * 60
epochTime += timePicker.minute.toLong() * 60
val rtcString = "0x" + java.lang.Long.toHexString(epochTime)
if (item.getSelectedValue() != rtcString) {
notifyItemChanged(clickedPosition)
fragmentView.onSettingChanged()
}
item.setSelectedValue(fragmentView.settings!!, rtcString)
clickedItem = null
}
datePicker.show(fragmentView.fragmentActivity.supportFragmentManager, "DatePicker")
}
fun onFilePickerConfirmation(selectedFile: String) {
val filePicker = clickedItem as FilePicker?
if (filePicker!!.getSelectedValue() != selectedFile) {
notifyItemChanged(clickedPosition)
fragmentView.onSettingChanged()
}
filePicker.setSelectedValue(fragmentView.settings!!, selectedFile)
clickedItem = null
}
fun onMenuTagAction(menuTag: MenuTag, value: Int) {
fragmentView.onMenuTagAction(menuTag, value)
}
fun hasMenuTagActionForValue(menuTag: MenuTag, value: Int): Boolean {
return fragmentView.hasMenuTagActionForValue(menuTag, value)
}
override fun onClick(dialog: DialogInterface, which: Int) {
when (clickedItem) {
is SingleChoiceSetting -> {
val scSetting = clickedItem as SingleChoiceSetting
val value = getValueForSingleChoiceSelection(scSetting, which)
if (scSetting.selectedValue != value) fragmentView.onSettingChanged()
scSetting.setSelectedValue(settings, value)
closeDialog()
}
is SingleChoiceSettingDynamicDescriptions -> {
val scSetting = clickedItem as SingleChoiceSettingDynamicDescriptions
val value = getValueForSingleChoiceDynamicDescriptionsSelection(scSetting, which)
if (scSetting.selectedValue != value) fragmentView.onSettingChanged()
scSetting.setSelectedValue(settings!!, value)
closeDialog()
}
is StringSingleChoiceSetting -> {
val scSetting = clickedItem as StringSingleChoiceSetting
val value = scSetting.getValueAt(which)
if (scSetting.selectedValue != value) fragmentView.onSettingChanged()
scSetting.setSelectedValue(settings, value)
closeDialog()
}
is IntSliderSetting -> {
val sliderSetting = clickedItem as IntSliderSetting
if (sliderSetting.selectedValue != seekbarProgress) fragmentView.onSettingChanged()
sliderSetting.setSelectedValue(settings, seekbarProgress)
closeDialog()
}
is FloatSliderSetting -> {
val sliderSetting = clickedItem as FloatSliderSetting
if (sliderSetting.selectedValue != seekbarProgress) fragmentView.onSettingChanged()
sliderSetting.setSelectedValue(settings, seekbarProgress.toFloat())
closeDialog()
}
}
clickedItem = null
seekbarProgress = -1
}
fun closeDialog() {
if (dialog != null) {
if (clickedPosition != -1) {
notifyItemChanged(clickedPosition)
clickedPosition = -1
}
dialog!!.dismiss()
dialog = null
}
}
override fun onValueChange(slider: Slider, progress: Float, fromUser: Boolean) {
seekbarProgress = progress.toInt()
textSliderValue!!.text = seekbarProgress.toString()
}
private fun getValueForSingleChoiceSelection(item: SingleChoiceSetting, which: Int): Int {
val valuesId = item.valuesId
return if (valuesId > 0) {
val valuesArray = context.resources.getIntArray(valuesId)
valuesArray[which]
} else {
which
}
}
private fun getSelectionForSingleChoiceValue(item: SingleChoiceSetting): Int {
val value = item.selectedValue
val valuesId = item.valuesId
if (valuesId > 0) {
val valuesArray = context.resources.getIntArray(valuesId)
for (index in valuesArray.indices) {
val current = valuesArray[index]
if (current == value) {
return index
}
}
} else {
return value
}
return -1
}
private fun getValueForSingleChoiceDynamicDescriptionsSelection(
item: SingleChoiceSettingDynamicDescriptions,
which: Int
): Int {
val valuesId = item.valuesId
return if (valuesId > 0) {
val valuesArray = context.resources.getIntArray(valuesId)
valuesArray[which]
} else {
which
}
}
private fun getSelectionForSingleChoiceDynamicDescriptionsValue(
item: SingleChoiceSettingDynamicDescriptions
): Int {
val value = item.selectedValue
val valuesId = item.valuesId
if (valuesId > 0) {
val valuesArray = context.resources.getIntArray(valuesId)
for (index in valuesArray.indices) {
val current = valuesArray[index]
if (current == value) {
return index
}
}
} else {
return value
}
return -1
}
companion object {
fun clearLog() {
// Don't delete the log in case it is being monitored by another app.
val log = File(DirectoryInitialization.getUserDirectory() + "/Logs/dolphin.log")
try {
val raf = RandomAccessFile(log, "rw")
raf.setLength(0)
} catch (e: IOException) {
Log.error("[SettingsAdapter] Failed to clear log file: " + e.message)
}
}
}
}

View File

@ -1,295 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui;
import android.content.Context;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.FragmentSettingsBinding;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public final class SettingsFragment extends Fragment implements SettingsFragmentView
{
private static final String ARGUMENT_MENU_TAG = "menu_tag";
private static final String ARGUMENT_GAME_ID = "game_id";
private SettingsFragmentPresenter mPresenter;
private SettingsActivityView mActivity;
private SettingsAdapter mAdapter;
private int mOldControllerSettingsWarningHeight = 0;
private static final Map<MenuTag, Integer> titles = new HashMap<>();
static
{
titles.put(MenuTag.SETTINGS, R.string.settings);
titles.put(MenuTag.CONFIG, R.string.config);
titles.put(MenuTag.CONFIG_GENERAL, R.string.general_submenu);
titles.put(MenuTag.CONFIG_INTERFACE, R.string.interface_submenu);
titles.put(MenuTag.CONFIG_AUDIO, R.string.audio_submenu);
titles.put(MenuTag.CONFIG_PATHS, R.string.paths_submenu);
titles.put(MenuTag.CONFIG_GAME_CUBE, R.string.gamecube_submenu);
titles.put(MenuTag.CONFIG_SERIALPORT1, R.string.serialport1_submenu);
titles.put(MenuTag.CONFIG_WII, R.string.wii_submenu);
titles.put(MenuTag.CONFIG_ADVANCED, R.string.advanced_submenu);
titles.put(MenuTag.DEBUG, R.string.debug_submenu);
titles.put(MenuTag.GRAPHICS, R.string.graphics_settings);
titles.put(MenuTag.ENHANCEMENTS, R.string.enhancements_submenu);
titles.put(MenuTag.STEREOSCOPY, R.string.stereoscopy_submenu);
titles.put(MenuTag.HACKS, R.string.hacks_submenu);
titles.put(MenuTag.STATISTICS, R.string.statistics_submenu);
titles.put(MenuTag.ADVANCED_GRAPHICS, R.string.advanced_graphics_submenu);
titles.put(MenuTag.CONFIG_LOG, R.string.log_submenu);
titles.put(MenuTag.GCPAD_TYPE, R.string.gcpad_settings);
titles.put(MenuTag.WIIMOTE, R.string.wiimote_settings);
titles.put(MenuTag.WIIMOTE_EXTENSION, R.string.wiimote_extensions);
titles.put(MenuTag.GCPAD_1, R.string.controller_0);
titles.put(MenuTag.GCPAD_2, R.string.controller_1);
titles.put(MenuTag.GCPAD_3, R.string.controller_2);
titles.put(MenuTag.GCPAD_4, R.string.controller_3);
titles.put(MenuTag.WIIMOTE_1, R.string.wiimote_0);
titles.put(MenuTag.WIIMOTE_2, R.string.wiimote_1);
titles.put(MenuTag.WIIMOTE_3, R.string.wiimote_2);
titles.put(MenuTag.WIIMOTE_4, R.string.wiimote_3);
titles.put(MenuTag.WIIMOTE_EXTENSION_1, R.string.wiimote_extension_0);
titles.put(MenuTag.WIIMOTE_EXTENSION_2, R.string.wiimote_extension_1);
titles.put(MenuTag.WIIMOTE_EXTENSION_3, R.string.wiimote_extension_2);
titles.put(MenuTag.WIIMOTE_EXTENSION_4, R.string.wiimote_extension_3);
titles.put(MenuTag.WIIMOTE_GENERAL_1, R.string.wiimote_general);
titles.put(MenuTag.WIIMOTE_GENERAL_2, R.string.wiimote_general);
titles.put(MenuTag.WIIMOTE_GENERAL_3, R.string.wiimote_general);
titles.put(MenuTag.WIIMOTE_GENERAL_4, R.string.wiimote_general);
titles.put(MenuTag.WIIMOTE_MOTION_SIMULATION_1, R.string.wiimote_motion_simulation);
titles.put(MenuTag.WIIMOTE_MOTION_SIMULATION_2, R.string.wiimote_motion_simulation);
titles.put(MenuTag.WIIMOTE_MOTION_SIMULATION_3, R.string.wiimote_motion_simulation);
titles.put(MenuTag.WIIMOTE_MOTION_SIMULATION_4, R.string.wiimote_motion_simulation);
titles.put(MenuTag.WIIMOTE_MOTION_INPUT_1, R.string.wiimote_motion_input);
titles.put(MenuTag.WIIMOTE_MOTION_INPUT_2, R.string.wiimote_motion_input);
titles.put(MenuTag.WIIMOTE_MOTION_INPUT_3, R.string.wiimote_motion_input);
titles.put(MenuTag.WIIMOTE_MOTION_INPUT_4, R.string.wiimote_motion_input);
}
private FragmentSettingsBinding mBinding;
public static Fragment newInstance(MenuTag menuTag, String gameId, Bundle extras)
{
SettingsFragment fragment = new SettingsFragment();
Bundle arguments = new Bundle();
if (extras != null)
{
arguments.putAll(extras);
}
arguments.putSerializable(ARGUMENT_MENU_TAG, menuTag);
arguments.putString(ARGUMENT_GAME_ID, gameId);
fragment.setArguments(arguments);
return fragment;
}
@Override
public void onAttach(@NonNull Context context)
{
super.onAttach(context);
mActivity = (SettingsActivityView) context;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Bundle args = getArguments();
MenuTag menuTag = (MenuTag) args.getSerializable(ARGUMENT_MENU_TAG);
String gameId = getArguments().getString(ARGUMENT_GAME_ID);
mPresenter = new SettingsFragmentPresenter(this, getContext());
mAdapter = new SettingsAdapter(this, getContext());
mPresenter.onCreate(menuTag, gameId, args);
}
@NonNull
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState)
{
mBinding = FragmentSettingsBinding.inflate(inflater, container, false);
return mBinding.getRoot();
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState)
{
Bundle args = getArguments();
MenuTag menuTag = (MenuTag) args.getSerializable(ARGUMENT_MENU_TAG);
if (titles.containsKey(menuTag))
{
mActivity.setToolbarTitle(getString(titles.get(menuTag)));
}
LinearLayoutManager manager = new LinearLayoutManager(getActivity());
RecyclerView recyclerView = mBinding.listSettings;
recyclerView.setAdapter(mAdapter);
recyclerView.setLayoutManager(manager);
SettingsDividerItemDecoration divider = new SettingsDividerItemDecoration(requireActivity());
recyclerView.addItemDecoration(divider);
setInsets();
SettingsActivityView activity = (SettingsActivityView) getActivity();
mPresenter.onViewCreated(menuTag, activity.getSettings());
}
@Override
public void onDestroyView()
{
super.onDestroyView();
mBinding = null;
}
@Override
public void onDetach()
{
super.onDetach();
mActivity = null;
if (mAdapter != null)
{
mAdapter.closeDialog();
}
}
@Override
public void onSettingsFileLoaded(
org.dolphinemu.dolphinemu.features.settings.model.Settings settings)
{
mPresenter.setSettings(settings);
}
@Override
public void showSettingsList(ArrayList<SettingsItem> settingsList)
{
mAdapter.setSettings(settingsList);
}
@Override
public void loadDefaultSettings()
{
mPresenter.loadDefaultSettings();
}
@Override
public SettingsAdapter getAdapter()
{
return mAdapter;
}
@Override
public void loadSubMenu(MenuTag menuKey)
{
mActivity.showSettingsFragment(menuKey, null, true, getArguments().getString(ARGUMENT_GAME_ID));
}
@Override
public void showDialogFragment(DialogFragment fragment)
{
mActivity.showDialogFragment(fragment);
}
@Override
public void showToastMessage(String message)
{
mActivity.showToastMessage(message);
}
@Override
public Settings getSettings()
{
return mPresenter.getSettings();
}
@Override
public void onSettingChanged()
{
mActivity.onSettingChanged();
}
@Override
public void onControllerSettingsChanged()
{
mAdapter.notifyAllSettingsChanged();
mPresenter.updateOldControllerSettingsWarningVisibility();
}
@Override
public void onMenuTagAction(@NonNull MenuTag menuTag, int value)
{
mActivity.onMenuTagAction(menuTag, value);
}
public boolean hasMenuTagActionForValue(@NonNull MenuTag menuTag, int value)
{
return mActivity.hasMenuTagActionForValue(menuTag, value);
}
@Override
public void setMappingAllDevices(boolean allDevices)
{
mActivity.setMappingAllDevices(allDevices);
}
@Override
public boolean isMappingAllDevices()
{
return mActivity.isMappingAllDevices();
}
@Override
public void setOldControllerSettingsWarningVisibility(boolean visible)
{
mOldControllerSettingsWarningHeight =
mActivity.setOldControllerSettingsWarningVisibility(visible);
// Trigger the insets listener we've registered
mBinding.listSettings.requestApplyInsets();
}
private void setInsets()
{
ViewCompat.setOnApplyWindowInsetsListener(mBinding.listSettings, (v, windowInsets) ->
{
Insets insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars());
int listSpacing = getResources().getDimensionPixelSize(R.dimen.spacing_list);
v.setPadding(0, 0, 0, insets.bottom + listSpacing + mOldControllerSettingsWarningHeight);
return windowInsets;
});
}
}

View File

@ -0,0 +1,242 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updatePadding
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.LinearLayoutManager
import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.databinding.FragmentSettingsBinding
import org.dolphinemu.dolphinemu.features.settings.model.Settings
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem
import org.dolphinemu.dolphinemu.utils.SerializableHelper.serializable
import java.util.*
import kotlin.collections.ArrayList
class SettingsFragment : Fragment(), SettingsFragmentView {
private lateinit var presenter: SettingsFragmentPresenter
private var activityView: SettingsActivityView? = null
private lateinit var menuTag: MenuTag
override val fragmentActivity: FragmentActivity
get() = requireActivity()
override var adapter: SettingsAdapter? = null
private var oldControllerSettingsWarningHeight = 0
private var binding: FragmentSettingsBinding? = null
override fun onAttach(context: Context) {
super.onAttach(context)
activityView = context as SettingsActivityView
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
menuTag = requireArguments().serializable(ARGUMENT_MENU_TAG)!!
val gameId = requireArguments().getString(ARGUMENT_GAME_ID)
presenter = SettingsFragmentPresenter(this, requireContext())
adapter = SettingsAdapter(this, requireContext())
presenter.onCreate(menuTag, gameId, requireArguments())
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
binding = FragmentSettingsBinding.inflate(inflater, container, false)
return binding!!.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
if (titles.containsKey(menuTag)) {
activityView!!.setToolbarTitle(getString(titles[menuTag]!!))
}
val manager = LinearLayoutManager(activity)
val recyclerView = binding!!.listSettings
recyclerView.adapter = adapter
recyclerView.layoutManager = manager
val divider = SettingsDividerItemDecoration(requireActivity())
recyclerView.addItemDecoration(divider)
setInsets()
val activity = activity as SettingsActivityView?
presenter.onViewCreated(menuTag, activity!!.settings)
}
override fun onDestroyView() {
super.onDestroyView()
binding = null
}
override fun onDetach() {
super.onDetach()
activityView = null
if (adapter != null) {
adapter!!.closeDialog()
}
}
override fun onSettingsFileLoaded(settings: Settings) {
presenter.settings = settings
}
override fun showSettingsList(settingsList: ArrayList<SettingsItem>) {
adapter!!.setSettings(settingsList)
}
override fun loadDefaultSettings() {
presenter.loadDefaultSettings()
}
override fun loadSubMenu(menuKey: MenuTag) {
activityView!!.showSettingsFragment(
menuKey,
null,
true,
requireArguments().getString(ARGUMENT_GAME_ID)!!
)
}
override fun showDialogFragment(fragment: DialogFragment) {
activityView!!.showDialogFragment(fragment)
}
override fun showToastMessage(message: String) {
activityView!!.showToastMessage(message)
}
override val settings: Settings?
get() = presenter.settings
override fun onSettingChanged() {
activityView!!.onSettingChanged()
}
override fun onControllerSettingsChanged() {
adapter!!.notifyAllSettingsChanged()
presenter.updateOldControllerSettingsWarningVisibility()
}
override fun onMenuTagAction(menuTag: MenuTag, value: Int) {
activityView!!.onMenuTagAction(menuTag, value)
}
override fun hasMenuTagActionForValue(menuTag: MenuTag, value: Int): Boolean {
return activityView!!.hasMenuTagActionForValue(menuTag, value)
}
override var isMappingAllDevices: Boolean
get() = activityView!!.isMappingAllDevices
set(allDevices) {
activityView!!.isMappingAllDevices = allDevices
}
override fun setOldControllerSettingsWarningVisibility(visible: Boolean) {
oldControllerSettingsWarningHeight =
activityView!!.setOldControllerSettingsWarningVisibility(visible)
// Trigger the insets listener we've registered
binding!!.listSettings.requestApplyInsets()
}
private fun setInsets() {
ViewCompat.setOnApplyWindowInsetsListener(binding!!.listSettings) { v: View, windowInsets: WindowInsetsCompat ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
val listSpacing = resources.getDimensionPixelSize(R.dimen.spacing_list)
v.updatePadding(bottom = insets.bottom + listSpacing + oldControllerSettingsWarningHeight)
windowInsets
}
}
companion object {
private const val ARGUMENT_MENU_TAG = "menu_tag"
private const val ARGUMENT_GAME_ID = "game_id"
private val titles: MutableMap<MenuTag, Int> = EnumMap(MenuTag::class.java)
init {
titles[MenuTag.SETTINGS] = R.string.settings
titles[MenuTag.CONFIG] = R.string.config
titles[MenuTag.CONFIG_GENERAL] = R.string.general_submenu
titles[MenuTag.CONFIG_INTERFACE] = R.string.interface_submenu
titles[MenuTag.CONFIG_AUDIO] = R.string.audio_submenu
titles[MenuTag.CONFIG_PATHS] = R.string.paths_submenu
titles[MenuTag.CONFIG_GAME_CUBE] = R.string.gamecube_submenu
titles[MenuTag.CONFIG_SERIALPORT1] = R.string.serialport1_submenu
titles[MenuTag.CONFIG_WII] = R.string.wii_submenu
titles[MenuTag.CONFIG_ADVANCED] = R.string.advanced_submenu
titles[MenuTag.DEBUG] = R.string.debug_submenu
titles[MenuTag.GRAPHICS] = R.string.graphics_settings
titles[MenuTag.ENHANCEMENTS] = R.string.enhancements_submenu
titles[MenuTag.STEREOSCOPY] = R.string.stereoscopy_submenu
titles[MenuTag.HACKS] = R.string.hacks_submenu
titles[MenuTag.STATISTICS] = R.string.statistics_submenu
titles[MenuTag.ADVANCED_GRAPHICS] = R.string.advanced_graphics_submenu
titles[MenuTag.CONFIG_LOG] = R.string.log_submenu
titles[MenuTag.GCPAD_TYPE] = R.string.gcpad_settings
titles[MenuTag.WIIMOTE] = R.string.wiimote_settings
titles[MenuTag.WIIMOTE_EXTENSION] = R.string.wiimote_extensions
titles[MenuTag.GCPAD_1] = R.string.controller_0
titles[MenuTag.GCPAD_2] = R.string.controller_1
titles[MenuTag.GCPAD_3] = R.string.controller_2
titles[MenuTag.GCPAD_4] = R.string.controller_3
titles[MenuTag.WIIMOTE_1] = R.string.wiimote_0
titles[MenuTag.WIIMOTE_2] = R.string.wiimote_1
titles[MenuTag.WIIMOTE_3] = R.string.wiimote_2
titles[MenuTag.WIIMOTE_4] = R.string.wiimote_3
titles[MenuTag.WIIMOTE_EXTENSION_1] = R.string.wiimote_extension_0
titles[MenuTag.WIIMOTE_EXTENSION_2] = R.string.wiimote_extension_1
titles[MenuTag.WIIMOTE_EXTENSION_3] = R.string.wiimote_extension_2
titles[MenuTag.WIIMOTE_EXTENSION_4] = R.string.wiimote_extension_3
titles[MenuTag.WIIMOTE_GENERAL_1] = R.string.wiimote_general
titles[MenuTag.WIIMOTE_GENERAL_2] = R.string.wiimote_general
titles[MenuTag.WIIMOTE_GENERAL_3] = R.string.wiimote_general
titles[MenuTag.WIIMOTE_GENERAL_4] = R.string.wiimote_general
titles[MenuTag.WIIMOTE_MOTION_SIMULATION_1] = R.string.wiimote_motion_simulation
titles[MenuTag.WIIMOTE_MOTION_SIMULATION_2] = R.string.wiimote_motion_simulation
titles[MenuTag.WIIMOTE_MOTION_SIMULATION_3] = R.string.wiimote_motion_simulation
titles[MenuTag.WIIMOTE_MOTION_SIMULATION_4] = R.string.wiimote_motion_simulation
titles[MenuTag.WIIMOTE_MOTION_INPUT_1] = R.string.wiimote_motion_input
titles[MenuTag.WIIMOTE_MOTION_INPUT_2] = R.string.wiimote_motion_input
titles[MenuTag.WIIMOTE_MOTION_INPUT_3] = R.string.wiimote_motion_input
titles[MenuTag.WIIMOTE_MOTION_INPUT_4] = R.string.wiimote_motion_input
}
@JvmStatic
fun newInstance(menuTag: MenuTag?, gameId: String?, extras: Bundle?): Fragment {
val fragment = SettingsFragment()
val arguments = Bundle()
if (extras != null) {
arguments.putAll(extras)
}
arguments.putSerializable(ARGUMENT_MENU_TAG, menuTag)
arguments.putString(ARGUMENT_GAME_ID, gameId)
fragment.arguments = arguments
return fragment
}
}
}

View File

@ -1,123 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui;
import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import java.util.ArrayList;
/**
* Abstraction for a screen showing a list of settings. Instances of
* this type of view will each display a layer of the setting hierarchy.
*/
public interface SettingsFragmentView
{
/**
* Called by the containing Activity to notify the Fragment that an
* asynchronous load operation completed.
*
* @param settings The (possibly null) result of the ini load operation.
*/
void onSettingsFileLoaded(Settings settings);
/**
* Pass an ArrayList of settings to the View so that it can be displayed on screen.
*
* @param settingsList The settings to display
*/
void showSettingsList(ArrayList<SettingsItem> settingsList);
/**
* Called by the containing Activity when an asynchronous load operation fails.
* Instructs the Fragment to load the settings screen with defaults selected.
*/
void loadDefaultSettings();
/**
* @return The Fragment's containing activity.
*/
FragmentActivity getActivity();
/**
* @return The Fragment's SettingsAdapter.
*/
SettingsAdapter getAdapter();
/**
* Tell the Fragment to tell the containing Activity to show a new
* Fragment containing a submenu of settings.
*
* @param menuKey Identifier for the settings group that should be shown.
*/
void loadSubMenu(MenuTag menuKey);
void showDialogFragment(DialogFragment fragment);
/**
* Tell the Fragment to tell the containing activity to display a toast message.
*
* @param message Text to be shown in the Toast
*/
void showToastMessage(String message);
/**
* @return The backing settings store.
*/
Settings getSettings();
/**
* Have the fragment tell the containing Activity that a setting was modified.
*/
void onSettingChanged();
/**
* Refetches the values of all controller settings.
*
* To be used when loading an input profile or performing some other action that changes all
* controller settings at once.
*/
void onControllerSettingsChanged();
/**
* Have the fragment tell the containing Activity that the user wants to open the MenuTag
* associated with a setting.
*
* @param menuTag The MenuTag of the setting.
* @param value The current value of the setting.
*/
void onMenuTagAction(@NonNull MenuTag menuTag, int value);
/**
* Returns whether anything will happen when the user wants to open the MenuTag associated with a
* setting, given the current value of the setting.
*
* @param menuTag The MenuTag of the setting.
* @param value The current value of the setting.
*/
boolean hasMenuTagActionForValue(@NonNull MenuTag menuTag, int value);
/**
* Sets whether the input mapping dialog should detect inputs from all devices,
* not just the device configured for the controller.
*/
void setMappingAllDevices(boolean allDevices);
/**
* Returns whether the input mapping dialog should detect inputs from all devices,
* not just the device configured for the controller.
*/
boolean isMappingAllDevices();
/**
* Shows or hides a warning telling the user that they're using incompatible controller settings.
* The warning is hidden by default.
*
* @param visible Whether the warning should be visible.
*/
void setOldControllerSettingsWarningVisibility(boolean visible);
}

View File

@ -0,0 +1,114 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.FragmentActivity
import org.dolphinemu.dolphinemu.features.settings.model.Settings
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem
/**
* Abstraction for a screen showing a list of settings. Instances of
* this type of view will each display a layer of the Setting hierarchy.
*/
interface SettingsFragmentView {
/**
* Called by the containing Activity to notify the Fragment that an
* asynchronous load operation completed.
*
* @param settings The (possibly null) result of the ini load operation.
*/
fun onSettingsFileLoaded(settings: Settings)
/**
* Pass an ArrayList of settings to the View so that it can be displayed on screen.
*
* @param settingsList The settings to display
*/
fun showSettingsList(settingsList: ArrayList<SettingsItem>)
/**
* Called by the containing Activity when an asynchronous load operation fails.
* Instructs the Fragment to load the settings screen with defaults selected.
*/
fun loadDefaultSettings()
/**
* @return The Fragment's containing activity.
*/
val fragmentActivity: FragmentActivity
/**
* @return The Fragment's SettingsAdapter.
*/
val adapter: SettingsAdapter?
/**
* Tell the Fragment to tell the containing Activity to show a new
* Fragment containing a submenu of settings.
*
* @param menuKey Identifier for the settings group that should be shown.
*/
fun loadSubMenu(menuKey: MenuTag)
fun showDialogFragment(fragment: DialogFragment)
/**
* Tell the Fragment to tell the containing activity to display a toast message.
*
* @param message Text to be shown in the Toast
*/
fun showToastMessage(message: String)
/**
* @return The backing settings store.
*/
val settings: Settings?
/**
* Have the fragment tell the containing Activity that a Setting was modified.
*/
fun onSettingChanged()
/**
* Refetches the values of all controller settings.
*
* To be used when loading an input profile or performing some other action that changes all
* controller settings at once.
*/
fun onControllerSettingsChanged()
/**
* Have the fragment tell the containing Activity that the user wants to open the MenuTag
* associated with a Setting.
*
* @param menuTag The MenuTag of the Setting.
* @param value The current value of the Setting.
*/
fun onMenuTagAction(menuTag: MenuTag, value: Int)
/**
* Returns whether anything will happen when the user wants to open the MenuTag associated with a
* stringSetting, given the current value of the Setting.
*
* @param menuTag The MenuTag of the Setting.
* @param value The current value of the Setting.
*/
fun hasMenuTagActionForValue(menuTag: MenuTag, value: Int): Boolean
/**
* Returns whether the input mapping dialog should detect inputs from all devices,
* not just the device configured for the controller.
*/
/**
* Sets whether the input mapping dialog should detect inputs from all devices,
* not just the device configured for the controller.
*/
var isMappingAllDevices: Boolean
/**
* Shows or hides a warning telling the user that they're using incompatible controller settings.
* The warning is hidden by default.
*
* @param visible Whether the warning should be visible.
*/
fun setOldControllerSettingsWarningVisibility(visible: Boolean)
}

View File

@ -1,17 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui;
import androidx.lifecycle.ViewModel;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
public class SettingsViewModel extends ViewModel
{
private final Settings mSettings = new Settings();
public Settings getSettings()
{
return mSettings;
}
}

View File

@ -0,0 +1,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui
import androidx.lifecycle.ViewModel
import org.dolphinemu.dolphinemu.features.settings.model.Settings
class SettingsViewModel : ViewModel() {
val settings = Settings()
}

View File

@ -18,12 +18,15 @@ class DateTimeSettingViewHolder(
private val binding: ListItemSettingBinding, private val binding: ListItemSettingBinding,
adapter: SettingsAdapter adapter: SettingsAdapter
) : SettingViewHolder(binding.root, adapter) { ) : SettingViewHolder(binding.root, adapter) {
private var mItem: DateTimeChoiceSetting? = null lateinit var setting: DateTimeChoiceSetting
override val item: SettingsItem
get() = setting
override fun bind(item: SettingsItem) { override fun bind(item: SettingsItem) {
mItem = item as DateTimeChoiceSetting setting = item as DateTimeChoiceSetting
val inputTime = mItem!!.getSelectedValue() val inputTime = setting.getSelectedValue()
binding.textSettingName.text = item.getName() binding.textSettingName.text = item.name
if (!TextUtils.isEmpty(inputTime)) { if (!TextUtils.isEmpty(inputTime)) {
val epochTime = inputTime.substring(2).toLong(16) val epochTime = inputTime.substring(2).toLong(16)
@ -32,21 +35,17 @@ class DateTimeSettingViewHolder(
val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM) val dateFormatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM)
binding.textSettingDescription.text = dateFormatter.format(zonedTime) binding.textSettingDescription.text = dateFormatter.format(zonedTime)
} else { } else {
binding.textSettingDescription.text = item.getDescription() binding.textSettingDescription.text = item.description
} }
setStyle(binding.textSettingName, mItem) setStyle(binding.textSettingName, setting)
} }
override fun onClick(clicked: View) { override fun onClick(clicked: View) {
if (!mItem!!.isEditable) { if (!setting.isEditable) {
showNotRuntimeEditableError() showNotRuntimeEditableError()
return return
} }
adapter.onDateTimeClick(mItem, bindingAdapterPosition) adapter.onDateTimeClick(setting, bindingAdapterPosition)
setStyle(binding.textSettingName, mItem) setStyle(binding.textSettingName, setting)
}
override fun getItem(): SettingsItem? {
return mItem
} }
} }

View File

@ -1,99 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
import org.dolphinemu.dolphinemu.ui.main.MainPresenter;
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper;
public final class FilePickerViewHolder extends SettingViewHolder
{
private FilePicker mFilePicker;
private SettingsItem mItem;
private final ListItemSettingBinding mBinding;
public FilePickerViewHolder(ListItemSettingBinding binding, SettingsAdapter adapter)
{
super(binding.getRoot(), adapter);
mBinding = binding;
}
@Override
public void bind(SettingsItem item)
{
mFilePicker = (FilePicker) item;
mItem = item;
String path = mFilePicker.getSelectedValue();
if (FileBrowserHelper.isPathEmptyOrValid(path))
{
itemView.setBackground(mBinding.getRoot().getBackground());
}
else
{
itemView.setBackgroundResource(R.drawable.invalid_setting_background);
}
mBinding.textSettingName.setText(item.getName());
if (!TextUtils.isEmpty(item.getDescription()))
{
mBinding.textSettingDescription.setText(item.getDescription());
}
else
{
if (TextUtils.isEmpty(path))
{
String defaultPathRelative = mFilePicker.getDefaultPathRelativeToUserDirectory();
if (defaultPathRelative != null)
{
path = DirectoryInitialization.getUserDirectory() + defaultPathRelative;
}
}
mBinding.textSettingDescription.setText(path);
}
setStyle(mBinding.textSettingName, mItem);
}
@Override
public void onClick(View clicked)
{
if (!mItem.isEditable())
{
showNotRuntimeEditableError();
return;
}
int position = getBindingAdapterPosition();
if (mFilePicker.getRequestType() == MainPresenter.REQUEST_DIRECTORY)
{
getAdapter().onFilePickerDirectoryClick(mItem, position);
}
else
{
getAdapter().onFilePickerFileClick(mItem, position);
}
setStyle(mBinding.textSettingName, mItem);
}
@Nullable @Override
protected SettingsItem getItem()
{
return mItem;
}
}

View File

@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder
import android.text.TextUtils
import android.view.View
import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding
import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter
import org.dolphinemu.dolphinemu.ui.main.MainPresenter
import org.dolphinemu.dolphinemu.utils.DirectoryInitialization
import org.dolphinemu.dolphinemu.utils.FileBrowserHelper
class FilePickerViewHolder(
private val binding: ListItemSettingBinding,
adapter: SettingsAdapter?
) : SettingViewHolder(binding.getRoot(), adapter!!) {
lateinit var setting: FilePicker
override val item: SettingsItem
get() = setting
override fun bind(item: SettingsItem) {
setting = item as FilePicker
var path = setting.getSelectedValue()
if (FileBrowserHelper.isPathEmptyOrValid(path)) {
itemView.background = binding.getRoot().background
} else {
itemView.setBackgroundResource(R.drawable.invalid_setting_background)
}
binding.textSettingName.text = setting.name
if (!TextUtils.isEmpty(setting.description)) {
binding.textSettingDescription.text = setting.description
} else {
if (TextUtils.isEmpty(path)) {
val defaultPathRelative = setting.defaultPathRelativeToUserDirectory
if (defaultPathRelative != null) {
path = DirectoryInitialization.getUserDirectory() + defaultPathRelative
}
}
binding.textSettingDescription.text = path
}
setStyle(binding.textSettingName, setting)
}
override fun onClick(clicked: View) {
if (!setting.isEditable) {
showNotRuntimeEditableError()
return
}
val position = bindingAdapterPosition
if (setting.requestType == MainPresenter.REQUEST_DIRECTORY) {
adapter.onFilePickerDirectoryClick(setting, position)
} else {
adapter.onFilePickerFileClick(setting, position)
}
setStyle(binding.textSettingName, setting)
}
}

View File

@ -1,36 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.text.method.LinkMovementMethod;
import androidx.annotation.NonNull;
import com.google.android.material.color.MaterialColors;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public final class HeaderHyperLinkViewHolder extends HeaderViewHolder
{
private final ListItemHeaderBinding mBinding;
public HeaderHyperLinkViewHolder(@NonNull ListItemHeaderBinding binding, SettingsAdapter adapter)
{
super(binding, adapter);
mBinding = binding;
itemView.setOnClickListener(null);
}
@Override
public void bind(@NonNull SettingsItem item)
{
super.bind(item);
mBinding.textHeaderName.setMovementMethod(LinkMovementMethod.getInstance());
mBinding.textHeaderName.setLinkTextColor(
MaterialColors.getColor(itemView, R.attr.colorTertiary));
}
}

View File

@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder
import android.text.method.LinkMovementMethod
import com.google.android.material.color.MaterialColors
import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter
class HeaderHyperLinkViewHolder(
private val binding: ListItemHeaderBinding,
adapter: SettingsAdapter?
) : HeaderViewHolder(binding, adapter) {
init {
itemView.setOnClickListener(null)
}
override fun bind(item: SettingsItem) {
super.bind(item)
binding.textHeaderName.movementMethod = LinkMovementMethod.getInstance()
binding.textHeaderName.setLinkTextColor(
MaterialColors.getColor(itemView, R.attr.colorTertiary)
)
}
}

View File

@ -1,42 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding;
public class HeaderViewHolder extends SettingViewHolder
{
private final ListItemHeaderBinding mBinding;
public HeaderViewHolder(@NonNull ListItemHeaderBinding binding, SettingsAdapter adapter)
{
super(binding.getRoot(), adapter);
itemView.setOnClickListener(null);
mBinding = binding;
}
@Override
public void bind(@NonNull SettingsItem item)
{
mBinding.textHeaderName.setText(item.getName());
}
@Override
public void onClick(View clicked)
{
// no-op
}
@Nullable @Override
protected SettingsItem getItem()
{
return null;
}
}

View File

@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder
import android.view.View
import org.dolphinemu.dolphinemu.databinding.ListItemHeaderBinding
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter
open class HeaderViewHolder(
private val binding: ListItemHeaderBinding,
adapter: SettingsAdapter?
) : SettingViewHolder(binding.root, adapter!!) {
override val item: SettingsItem? = null
init {
itemView.setOnClickListener(null)
}
override fun bind(item: SettingsItem) {
binding.textHeaderName.text = item.name
}
override fun onClick(clicked: View) {
// no-op
}
}

View File

@ -1,71 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.InputStringSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public final class InputStringSettingViewHolder extends SettingViewHolder
{
private InputStringSetting mInputString;
private final ListItemSettingBinding mBinding;
public InputStringSettingViewHolder(@NonNull ListItemSettingBinding binding,
SettingsAdapter adapter)
{
super(binding.getRoot(), adapter);
mBinding = binding;
}
@Override
public void bind(SettingsItem item)
{
mInputString = (InputStringSetting) item;
String inputString = mInputString.getSelectedValue();
mBinding.textSettingName.setText(item.getName());
if (!TextUtils.isEmpty(inputString))
{
mBinding.textSettingDescription.setText(inputString);
}
else
{
mBinding.textSettingDescription.setText(item.getDescription());
}
setStyle(mBinding.textSettingName, mInputString);
}
@Override
public void onClick(View clicked)
{
if (!mInputString.isEditable())
{
showNotRuntimeEditableError();
return;
}
int position = getBindingAdapterPosition();
getAdapter().onInputStringClick(mInputString, position);
setStyle(mBinding.textSettingName, mInputString);
}
@Nullable @Override
protected SettingsItem getItem()
{
return mInputString;
}
}

View File

@ -0,0 +1,49 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder
import android.text.TextUtils
import android.view.View
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding
import org.dolphinemu.dolphinemu.features.settings.model.view.InputStringSetting
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter
class InputStringSettingViewHolder(
private val binding: ListItemSettingBinding,
adapter: SettingsAdapter
) : SettingViewHolder(binding.getRoot(), adapter) {
private lateinit var setting: InputStringSetting
override val item: SettingsItem
get() = setting
override fun bind(item: SettingsItem) {
setting = item as InputStringSetting
val inputString = setting.selectedValue
binding.textSettingName.text = setting.name
if (!TextUtils.isEmpty(inputString)) {
binding.textSettingDescription.text = inputString
} else {
binding.textSettingDescription.text = setting.description
}
setStyle(binding.textSettingName, setting)
}
override fun onClick(clicked: View) {
if (!setting.isEditable) {
showNotRuntimeEditableError()
return
}
val position = bindingAdapterPosition
adapter.onInputStringClick(setting, position)
setStyle(binding.textSettingName, setting)
}
}

View File

@ -1,93 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.content.Context;
import android.view.View;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.features.settings.model.view.RunRunnable;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public final class RunRunnableViewHolder extends SettingViewHolder
{
private RunRunnable mItem;
private final Context mContext;
private final ListItemSettingBinding mBinding;
public RunRunnableViewHolder(@NonNull ListItemSettingBinding binding, SettingsAdapter adapter,
Context context)
{
super(binding.getRoot(), adapter);
mBinding = binding;
mContext = context;
}
@Override
public void bind(SettingsItem item)
{
mItem = (RunRunnable) item;
mBinding.textSettingName.setText(item.getName());
mBinding.textSettingDescription.setText(item.getDescription());
setStyle(mBinding.textSettingName, mItem);
}
@Override
public void onClick(View clicked)
{
if (!mItem.isEditable())
{
showNotRuntimeEditableError();
return;
}
int alertTextID = mItem.getAlertText();
if (alertTextID > 0)
{
new MaterialAlertDialogBuilder(mContext)
.setTitle(mItem.getName())
.setMessage(alertTextID)
.setPositiveButton(R.string.ok, (dialog, whichButton) ->
{
runRunnable();
dialog.dismiss();
})
.setNegativeButton(R.string.cancel, (dialog, whichButton) -> dialog.dismiss())
.show();
}
else
{
runRunnable();
}
}
@Nullable @Override
protected SettingsItem getItem()
{
return mItem;
}
private void runRunnable()
{
mItem.getRunnable().run();
if (mItem.getToastTextAfterRun() > 0)
{
Toast.makeText(mContext, mContext.getString(mItem.getToastTextAfterRun()), Toast.LENGTH_SHORT)
.show();
}
}
}

View File

@ -0,0 +1,68 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder
import android.content.Context
import android.content.DialogInterface
import android.view.View
import android.widget.Toast
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding
import org.dolphinemu.dolphinemu.features.settings.model.view.RunRunnable
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter
class RunRunnableViewHolder(
private val mBinding: ListItemSettingBinding, adapter: SettingsAdapter?,
private val mContext: Context
) : SettingViewHolder(mBinding.getRoot(), adapter!!) {
private lateinit var setting: RunRunnable
override val item: SettingsItem
get() = setting
override fun bind(item: SettingsItem) {
setting = item as RunRunnable
mBinding.textSettingName.text = setting.name
mBinding.textSettingDescription.text = setting.description
setStyle(mBinding.textSettingName, setting)
}
override fun onClick(clicked: View) {
if (!setting.isEditable) {
showNotRuntimeEditableError()
return
}
val alertTextID = setting.alertText
if (alertTextID > 0) {
MaterialAlertDialogBuilder(mContext)
.setTitle(setting.name)
.setMessage(alertTextID)
.setPositiveButton(R.string.ok) { dialog: DialogInterface, _: Int ->
runRunnable()
dialog.dismiss()
}
.setNegativeButton(R.string.cancel) { dialog: DialogInterface, _: Int -> dialog.dismiss() }
.show()
} else {
runRunnable()
}
}
private fun runRunnable() {
setting.runnable.run()
if (setting.toastTextAfterRun > 0) {
Toast.makeText(
mContext,
mContext.getString(setting.toastTextAfterRun),
Toast.LENGTH_SHORT
).show()
}
}
}

View File

@ -1,111 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.content.Context;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.dolphinemu.dolphinemu.DolphinApplication;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
public abstract class SettingViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener, View.OnLongClickListener
{
private SettingsAdapter mAdapter;
public SettingViewHolder(View itemView, SettingsAdapter adapter)
{
super(itemView);
mAdapter = adapter;
itemView.setOnClickListener(this);
itemView.setOnLongClickListener(this);
}
protected SettingsAdapter getAdapter()
{
return mAdapter;
}
protected void setStyle(TextView textView, SettingsItem settingsItem)
{
boolean overridden = settingsItem.isOverridden();
textView.setTypeface(null, overridden ? Typeface.BOLD : Typeface.NORMAL);
if (!settingsItem.isEditable())
textView.setPaintFlags(textView.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
protected static void showNotRuntimeEditableError()
{
Toast.makeText(DolphinApplication.getAppContext(), R.string.setting_not_runtime_editable,
Toast.LENGTH_SHORT).show();
}
protected static void showIplNotAvailableError()
{
Toast.makeText(DolphinApplication.getAppContext(), R.string.ipl_not_found, Toast.LENGTH_SHORT)
.show();
}
/**
* Called by the adapter to set this ViewHolder's child views to display the list item
* it must now represent.
*
* @param item The list item that should be represented by this ViewHolder.
*/
public abstract void bind(SettingsItem item);
/**
* Called when this ViewHolder's view is clicked on. Implementations should usually pass
* this event up to the adapter.
*
* @param clicked The view that was clicked on.
*/
public abstract void onClick(View clicked);
@Nullable
protected abstract SettingsItem getItem();
public boolean onLongClick(View clicked)
{
SettingsItem item = getItem();
if (item == null || !item.canClear())
return false;
if (!item.isEditable())
{
showNotRuntimeEditableError();
return true;
}
Context context = clicked.getContext();
new MaterialAlertDialogBuilder(context)
.setMessage(R.string.setting_clear_confirm)
.setPositiveButton(R.string.ok, (dialog, whichButton) ->
{
getAdapter().clearSetting(item);
bind(item);
Toast.makeText(context, R.string.setting_cleared, Toast.LENGTH_SHORT).show();
dialog.dismiss();
})
.setNegativeButton(R.string.cancel, (dialog, whichButton) -> dialog.dismiss())
.show();
return true;
}
}

View File

@ -0,0 +1,98 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder
import android.content.DialogInterface
import android.graphics.Paint
import android.graphics.Typeface
import android.view.View
import android.view.View.OnLongClickListener
import android.widget.TextView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.dolphinemu.dolphinemu.DolphinApplication
import org.dolphinemu.dolphinemu.R
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter
abstract class SettingViewHolder(itemView: View, protected val adapter: SettingsAdapter) :
RecyclerView.ViewHolder(itemView), View.OnClickListener, OnLongClickListener {
init {
itemView.setOnClickListener(this)
itemView.setOnLongClickListener(this)
}
protected fun setStyle(textView: TextView, settingsItem: SettingsItem) {
val overridden = settingsItem.isOverridden
textView.setTypeface(null, if (overridden) Typeface.BOLD else Typeface.NORMAL)
if (!settingsItem.isEditable) textView.paintFlags =
textView.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG
}
/**
* Called by the adapter to set this ViewHolder's child views to display the list item
* it must now represent.
*
* @param item The list item that should be represented by this ViewHolder.
*/
abstract fun bind(item: SettingsItem)
/**
* Called when this ViewHolder's view is clicked on. Implementations should usually pass
* this event up to the adapter.
*
* @param clicked The view that was clicked on.
*/
abstract override fun onClick(clicked: View)
protected abstract val item: SettingsItem?
override fun onLongClick(clicked: View): Boolean {
val item = item
if (item == null || !item.canClear()) return false
if (!item.isEditable) {
showNotRuntimeEditableError()
return true
}
val context = clicked.context
MaterialAlertDialogBuilder(context)
.setMessage(R.string.setting_clear_confirm)
.setPositiveButton(R.string.ok) { dialog: DialogInterface, _: Int ->
adapter.clearSetting(item)
bind(item)
Toast.makeText(
context,
R.string.setting_cleared,
Toast.LENGTH_SHORT
).show()
dialog.dismiss()
}
.setNegativeButton(R.string.cancel) { dialog: DialogInterface, _: Int -> dialog.dismiss() }
.show()
return true
}
protected fun showIplNotAvailableError() {
Toast.makeText(
DolphinApplication.getAppContext(),
R.string.ipl_not_found,
Toast.LENGTH_SHORT
).show()
}
protected fun showNotRuntimeEditableError() {
Toast.makeText(
DolphinApplication.getAppContext(),
R.string.setting_not_runtime_editable,
Toast.LENGTH_SHORT
).show()
}
}

View File

@ -1,148 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-or-later
package org.dolphinemu.dolphinemu.features.settings.ui.viewholder;
import android.content.res.Resources;
import android.text.TextUtils;
import android.view.View;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.dolphinemu.dolphinemu.databinding.ListItemSettingBinding;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem;
import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSetting;
import org.dolphinemu.dolphinemu.features.settings.model.view.SingleChoiceSettingDynamicDescriptions;
import org.dolphinemu.dolphinemu.features.settings.model.view.StringSingleChoiceSetting;
import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter;
import java.util.function.Supplier;
public final class SingleChoiceViewHolder extends SettingViewHolder
{
private SettingsItem mItem;
private final ListItemSettingBinding mBinding;
public SingleChoiceViewHolder(@NonNull ListItemSettingBinding binding, SettingsAdapter adapter)
{
super(binding.getRoot(), adapter);
mBinding = binding;
}
@Override
public void bind(SettingsItem item)
{
mItem = item;
mBinding.textSettingName.setText(item.getName());
if (!TextUtils.isEmpty(item.getDescription()))
{
mBinding.textSettingDescription.setText(item.getDescription());
}
else if (item instanceof SingleChoiceSetting)
{
SingleChoiceSetting setting = (SingleChoiceSetting) item;
int selected = setting.getSelectedValue();
Resources resMgr = mBinding.textSettingDescription.getContext().getResources();
String[] choices = resMgr.getStringArray(setting.getChoicesId());
int[] values = resMgr.getIntArray(setting.getValuesId());
for (int i = 0; i < values.length; ++i)
{
if (values[i] == selected)
{
mBinding.textSettingDescription.setText(choices[i]);
}
}
}
else if (item instanceof StringSingleChoiceSetting)
{
StringSingleChoiceSetting setting = (StringSingleChoiceSetting) item;
String choice = setting.getSelectedChoice();
mBinding.textSettingDescription.setText(choice);
}
else if (item instanceof SingleChoiceSettingDynamicDescriptions)
{
SingleChoiceSettingDynamicDescriptions setting =
(SingleChoiceSettingDynamicDescriptions) item;
int selected = setting.getSelectedValue();
Resources resMgr = mBinding.textSettingDescription.getContext().getResources();
String[] choices = resMgr.getStringArray(setting.getDescriptionChoicesId());
int[] values = resMgr.getIntArray(setting.getDescriptionValuesId());
for (int i = 0; i < values.length; ++i)
{
if (values[i] == selected)
{
mBinding.textSettingDescription.setText(choices[i]);
}
}
}
MenuTag menuTag = null;
Supplier<Integer> getSelectedValue = null;
if (item instanceof SingleChoiceSetting)
{
SingleChoiceSetting setting = (SingleChoiceSetting) item;
menuTag = setting.getMenuTag();
getSelectedValue = setting::getSelectedValue;
}
else if (item instanceof StringSingleChoiceSetting)
{
StringSingleChoiceSetting setting = (StringSingleChoiceSetting) item;
menuTag = setting.getMenuTag();
getSelectedValue = setting::getSelectedValueIndex;
}
if (menuTag != null && getAdapter().hasMenuTagActionForValue(menuTag, getSelectedValue.get()))
{
mBinding.buttonMoreSettings.setVisibility(View.VISIBLE);
final MenuTag finalMenuTag = menuTag;
final Supplier<Integer> finalGetSelectedValue = getSelectedValue;
mBinding.buttonMoreSettings.setOnClickListener((view) ->
getAdapter().onMenuTagAction(finalMenuTag, finalGetSelectedValue.get()));
}
else
{
mBinding.buttonMoreSettings.setVisibility(View.GONE);
}
setStyle(mBinding.textSettingName, mItem);
}
@Override
public void onClick(View clicked)
{
if (!mItem.isEditable())
{
showNotRuntimeEditableError();
return;
}
int position = getBindingAdapterPosition();
if (mItem instanceof SingleChoiceSetting)
{
getAdapter().onSingleChoiceClick((SingleChoiceSetting) mItem, position);
}
else if (mItem instanceof StringSingleChoiceSetting)
{
getAdapter().onStringSingleChoiceClick((StringSingleChoiceSetting) mItem, position);
}
else if (mItem instanceof SingleChoiceSettingDynamicDescriptions)
{
getAdapter().onSingleChoiceDynamicDescriptionsClick(
(SingleChoiceSettingDynamicDescriptions) mItem, position);
}
setStyle(mBinding.textSettingName, mItem);
}
@Nullable @Override
protected SettingsItem getItem()
{
return mItem;
}
}

Some files were not shown because too many files have changed in this diff Show More