summaryrefslogtreecommitdiffstats
path: root/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model
diff options
context:
space:
mode:
Diffstat (limited to 'src/android/app/src/main/java/org/citra/citra_emu/features/settings/model')
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.java23
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/FloatSetting.java23
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.java23
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Setting.java42
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/SettingSection.java55
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.java132
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/StringSetting.java23
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/CheckBoxSetting.java80
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/DateTimeSetting.java40
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/HeaderSetting.java14
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.java382
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/PremiumHeader.java12
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/PremiumSingleChoiceSetting.java59
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SettingsItem.java107
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SingleChoiceSetting.java60
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.java101
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/StringSingleChoiceSetting.java82
-rw-r--r--src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SubmenuSetting.java21
18 files changed, 1279 insertions, 0 deletions
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.java
new file mode 100644
index 000000000..932dcf1d3
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/BooleanSetting.java
@@ -0,0 +1,23 @@
+package org.citra.citra_emu.features.settings.model;
+
+public final class BooleanSetting extends Setting {
+ private boolean mValue;
+
+ public BooleanSetting(String key, String section, boolean value) {
+ super(key, section);
+ mValue = value;
+ }
+
+ public boolean getValue() {
+ return mValue;
+ }
+
+ public void setValue(boolean value) {
+ mValue = value;
+ }
+
+ @Override
+ public String getValueAsString() {
+ return mValue ? "True" : "False";
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/FloatSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/FloatSetting.java
new file mode 100644
index 000000000..275f0ecea
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/FloatSetting.java
@@ -0,0 +1,23 @@
+package org.citra.citra_emu.features.settings.model;
+
+public final class FloatSetting extends Setting {
+ private float mValue;
+
+ public FloatSetting(String key, String section, float value) {
+ super(key, section);
+ mValue = value;
+ }
+
+ public float getValue() {
+ return mValue;
+ }
+
+ public void setValue(float value) {
+ mValue = value;
+ }
+
+ @Override
+ public String getValueAsString() {
+ return Float.toString(mValue);
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.java
new file mode 100644
index 000000000..f712e5bfa
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/IntSetting.java
@@ -0,0 +1,23 @@
+package org.citra.citra_emu.features.settings.model;
+
+public final class IntSetting extends Setting {
+ private int mValue;
+
+ public IntSetting(String key, String section, int value) {
+ super(key, section);
+ mValue = value;
+ }
+
+ public int getValue() {
+ return mValue;
+ }
+
+ public void setValue(int value) {
+ mValue = value;
+ }
+
+ @Override
+ public String getValueAsString() {
+ return Integer.toString(mValue);
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Setting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Setting.java
new file mode 100644
index 000000000..b762847c9
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Setting.java
@@ -0,0 +1,42 @@
+package org.citra.citra_emu.features.settings.model;
+
+/**
+ * Abstraction for a setting item as read from / written to Citra's configuration ini files.
+ * These files generally consist of a key/value pair, though the type of value is ambiguous and
+ * must be inferred at read-time. The type of value determines which child of this class is used
+ * to represent the Setting.
+ */
+public abstract class Setting {
+ private String mKey;
+ private String mSection;
+
+ /**
+ * Base constructor.
+ *
+ * @param key Everything to the left of the = in a line from the ini file.
+ * @param section The corresponding recent section header; e.g. [Core] or [Enhancements] without the brackets.
+ */
+ public Setting(String key, String section) {
+ mKey = key;
+ mSection = section;
+ }
+
+ /**
+ * @return The identifier used to write this setting to the ini file.
+ */
+ public String getKey() {
+ return mKey;
+ }
+
+ /**
+ * @return The name of the header under which this Setting should be written in the ini file.
+ */
+ public String getSection() {
+ return mSection;
+ }
+
+ /**
+ * @return A representation of this Setting's backing value converted to a String (e.g. for serialization).
+ */
+ public abstract String getValueAsString();
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/SettingSection.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/SettingSection.java
new file mode 100644
index 000000000..0a291aa6b
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/SettingSection.java
@@ -0,0 +1,55 @@
+package org.citra.citra_emu.features.settings.model;
+
+import java.util.HashMap;
+
+/**
+ * A semantically-related group of Settings objects. These Settings are
+ * internally stored as a HashMap.
+ */
+public final class SettingSection {
+ private String mName;
+
+ private HashMap<String, Setting> mSettings = new HashMap<>();
+
+ /**
+ * Create a new SettingSection with no Settings in it.
+ *
+ * @param name The header of this section; e.g. [Core] or [Enhancements] without the brackets.
+ */
+ public SettingSection(String name) {
+ mName = name;
+ }
+
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Convenience method; inserts a value directly into the backing HashMap.
+ *
+ * @param setting The Setting to be inserted.
+ */
+ public void putSetting(Setting setting) {
+ mSettings.put(setting.getKey(), setting);
+ }
+
+ /**
+ * Convenience method; gets a value directly from the backing HashMap.
+ *
+ * @param key Used to retrieve the Setting.
+ * @return A Setting object (you should probably cast this before using)
+ */
+ public Setting getSetting(String key) {
+ return mSettings.get(key);
+ }
+
+ public HashMap<String, Setting> getSettings() {
+ return mSettings;
+ }
+
+ public void mergeSection(SettingSection settingSection) {
+ for (Setting setting : settingSection.mSettings.values()) {
+ putSetting(setting);
+ }
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.java
new file mode 100644
index 000000000..9684966f2
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/Settings.java
@@ -0,0 +1,132 @@
+package org.citra.citra_emu.features.settings.model;
+
+import android.text.TextUtils;
+
+import org.citra.citra_emu.CitraApplication;
+import org.citra.citra_emu.R;
+import org.citra.citra_emu.features.settings.ui.SettingsActivityView;
+import org.citra.citra_emu.features.settings.utils.SettingsFile;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeMap;
+
+public class Settings {
+ public static final String SECTION_PREMIUM = "Premium";
+ public static final String SECTION_CORE = "Core";
+ public static final String SECTION_SYSTEM = "System";
+ public static final String SECTION_CAMERA = "Camera";
+ public static final String SECTION_CONTROLS = "Controls";
+ public static final String SECTION_RENDERER = "Renderer";
+ public static final String SECTION_LAYOUT = "Layout";
+ public static final String SECTION_UTILITY = "Utility";
+ public static final String SECTION_AUDIO = "Audio";
+ public static final String SECTION_DEBUG = "Debug";
+
+ private String gameId;
+
+ private static final Map<String, List<String>> configFileSectionsMap = new HashMap<>();
+
+ static {
+ configFileSectionsMap.put(SettingsFile.FILE_NAME_CONFIG, Arrays.asList(SECTION_PREMIUM, SECTION_CORE, SECTION_SYSTEM, SECTION_CAMERA, SECTION_CONTROLS, SECTION_RENDERER, SECTION_LAYOUT, SECTION_UTILITY, SECTION_AUDIO, SECTION_DEBUG));
+ }
+
+ /**
+ * A HashMap<String, SettingSection> that constructs a new SettingSection instead of returning null
+ * when getting a key not already in the map
+ */
+ public static final class SettingsSectionMap extends HashMap<String, SettingSection> {
+ @Override
+ public SettingSection get(Object key) {
+ if (!(key instanceof String)) {
+ return null;
+ }
+
+ String stringKey = (String) key;
+
+ if (!super.containsKey(stringKey)) {
+ SettingSection section = new SettingSection(stringKey);
+ super.put(stringKey, section);
+ return section;
+ }
+ return super.get(key);
+ }
+ }
+
+ private HashMap<String, SettingSection> sections = new Settings.SettingsSectionMap();
+
+ public SettingSection getSection(String sectionName) {
+ return sections.get(sectionName);
+ }
+
+ public boolean isEmpty() {
+ return sections.isEmpty();
+ }
+
+ public HashMap<String, SettingSection> getSections() {
+ return sections;
+ }
+
+ public void loadSettings(SettingsActivityView view) {
+ sections = new Settings.SettingsSectionMap();
+ loadCitraSettings(view);
+
+ if (!TextUtils.isEmpty(gameId)) {
+ loadCustomGameSettings(gameId, view);
+ }
+ }
+
+ private void loadCitraSettings(SettingsActivityView view) {
+ for (Map.Entry<String, List<String>> entry : configFileSectionsMap.entrySet()) {
+ String fileName = entry.getKey();
+ sections.putAll(SettingsFile.readFile(fileName, view));
+ }
+ }
+
+ private void loadCustomGameSettings(String gameId, SettingsActivityView view) {
+ // custom game settings
+ mergeSections(SettingsFile.readCustomGameSettings(gameId, view));
+ }
+
+ private void mergeSections(HashMap<String, SettingSection> updatedSections) {
+ for (Map.Entry<String, SettingSection> entry : updatedSections.entrySet()) {
+ if (sections.containsKey(entry.getKey())) {
+ SettingSection originalSection = sections.get(entry.getKey());
+ SettingSection updatedSection = entry.getValue();
+ originalSection.mergeSection(updatedSection);
+ } else {
+ sections.put(entry.getKey(), entry.getValue());
+ }
+ }
+ }
+
+ public void loadSettings(String gameId, SettingsActivityView view) {
+ this.gameId = gameId;
+ loadSettings(view);
+ }
+
+ public void saveSettings(SettingsActivityView view) {
+ if (TextUtils.isEmpty(gameId)) {
+ view.showToastMessage(CitraApplication.getAppContext().getString(R.string.ini_saved), false);
+
+ for (Map.Entry<String, List<String>> entry : configFileSectionsMap.entrySet()) {
+ String fileName = entry.getKey();
+ List<String> sectionNames = entry.getValue();
+ TreeMap<String, SettingSection> iniSections = new TreeMap<>();
+ for (String section : sectionNames) {
+ iniSections.put(section, sections.get(section));
+ }
+
+ SettingsFile.saveFile(fileName, iniSections, view);
+ }
+ } else {
+ // custom game settings
+ view.showToastMessage(CitraApplication.getAppContext().getString(R.string.gameid_saved, gameId), false);
+
+ SettingsFile.saveCustomGameSettings(gameId, sections);
+ }
+
+ }
+} \ No newline at end of file
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/StringSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/StringSetting.java
new file mode 100644
index 000000000..b906b7010
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/StringSetting.java
@@ -0,0 +1,23 @@
+package org.citra.citra_emu.features.settings.model;
+
+public final class StringSetting extends Setting {
+ private String mValue;
+
+ public StringSetting(String key, String section, String value) {
+ super(key, section);
+ mValue = value;
+ }
+
+ public String getValue() {
+ return mValue;
+ }
+
+ public void setValue(String value) {
+ mValue = value;
+ }
+
+ @Override
+ public String getValueAsString() {
+ return mValue;
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/CheckBoxSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/CheckBoxSetting.java
new file mode 100644
index 000000000..baf40709f
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/CheckBoxSetting.java
@@ -0,0 +1,80 @@
+package org.citra.citra_emu.features.settings.model.view;
+
+import org.citra.citra_emu.CitraApplication;
+import org.citra.citra_emu.R;
+import org.citra.citra_emu.features.settings.model.BooleanSetting;
+import org.citra.citra_emu.features.settings.model.IntSetting;
+import org.citra.citra_emu.features.settings.model.Setting;
+import org.citra.citra_emu.features.settings.ui.SettingsFragmentView;
+
+public final class CheckBoxSetting extends SettingsItem {
+ private boolean mDefaultValue;
+ private boolean mShowPerformanceWarning;
+ private SettingsFragmentView mView;
+
+ public CheckBoxSetting(String key, String section, int titleId, int descriptionId,
+ boolean defaultValue, Setting setting) {
+ super(key, section, setting, titleId, descriptionId);
+ mDefaultValue = defaultValue;
+ mShowPerformanceWarning = false;
+ }
+
+ public CheckBoxSetting(String key, String section, int titleId, int descriptionId,
+ boolean defaultValue, Setting setting, boolean show_performance_warning, SettingsFragmentView view) {
+ super(key, section, setting, titleId, descriptionId);
+ mDefaultValue = defaultValue;
+ mView = view;
+ mShowPerformanceWarning = show_performance_warning;
+ }
+
+ public boolean isChecked() {
+ if (getSetting() == null) {
+ return mDefaultValue;
+ }
+
+ // Try integer setting
+ try {
+ IntSetting setting = (IntSetting) getSetting();
+ return setting.getValue() == 1;
+ } catch (ClassCastException exception) {
+ }
+
+ // Try boolean setting
+ try {
+ BooleanSetting setting = (BooleanSetting) getSetting();
+ return setting.getValue() == true;
+ } catch (ClassCastException exception) {
+ }
+
+ return mDefaultValue;
+ }
+
+ /**
+ * Write a value to the backing boolean. If that boolean was previously null,
+ * initializes a new one and returns it, so it can be added to the Hashmap.
+ *
+ * @param checked Pretty self explanatory.
+ * @return null if overwritten successfully; otherwise, a newly created BooleanSetting.
+ */
+ public IntSetting setChecked(boolean checked) {
+ // Show a performance warning if the setting has been disabled
+ if (mShowPerformanceWarning && !checked) {
+ mView.showToastMessage(CitraApplication.getAppContext().getString(R.string.performance_warning), true);
+ }
+
+ if (getSetting() == null) {
+ IntSetting setting = new IntSetting(getKey(), getSection(), checked ? 1 : 0);
+ setSetting(setting);
+ return setting;
+ } else {
+ IntSetting setting = (IntSetting) getSetting();
+ setting.setValue(checked ? 1 : 0);
+ return null;
+ }
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_CHECKBOX;
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/DateTimeSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/DateTimeSetting.java
new file mode 100644
index 000000000..afc3352cc
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/DateTimeSetting.java
@@ -0,0 +1,40 @@
+package org.citra.citra_emu.features.settings.model.view;
+
+import org.citra.citra_emu.features.settings.model.Setting;
+import org.citra.citra_emu.features.settings.model.StringSetting;
+
+public final class DateTimeSetting extends SettingsItem {
+ private String mDefaultValue;
+
+ public DateTimeSetting(String key, String section, int titleId, int descriptionId,
+ String defaultValue, Setting setting) {
+ super(key, section, setting, titleId, descriptionId);
+ mDefaultValue = defaultValue;
+ }
+
+ public String getValue() {
+ if (getSetting() != null) {
+ StringSetting setting = (StringSetting) getSetting();
+ return setting.getValue();
+ } else {
+ return mDefaultValue;
+ }
+ }
+
+ public StringSetting setSelectedValue(String datetime) {
+ if (getSetting() == null) {
+ StringSetting setting = new StringSetting(getKey(), getSection(), datetime);
+ setSetting(setting);
+ return setting;
+ } else {
+ StringSetting setting = (StringSetting) getSetting();
+ setting.setValue(datetime);
+ return null;
+ }
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_DATETIME_SETTING;
+ }
+} \ No newline at end of file
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/HeaderSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/HeaderSetting.java
new file mode 100644
index 000000000..bac8876cd
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/HeaderSetting.java
@@ -0,0 +1,14 @@
+package org.citra.citra_emu.features.settings.model.view;
+
+import org.citra.citra_emu.features.settings.model.Setting;
+
+public final class HeaderSetting extends SettingsItem {
+ public HeaderSetting(String key, Setting setting, int titleId, int descriptionId) {
+ super(key, null, setting, titleId, descriptionId);
+ }
+
+ @Override
+ public int getType() {
+ return SettingsItem.TYPE_HEADER;
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.java
new file mode 100644
index 000000000..e9141a208
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/InputBindingSetting.java
@@ -0,0 +1,382 @@
+package org.citra.citra_emu.features.settings.model.view;
+
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.widget.Toast;
+
+import org.citra.citra_emu.CitraApplication;
+import org.citra.citra_emu.NativeLibrary;
+import org.citra.citra_emu.R;
+import org.citra.citra_emu.features.settings.model.Setting;
+import org.citra.citra_emu.features.settings.model.StringSetting;
+import org.citra.citra_emu.features.settings.utils.SettingsFile;
+
+public final class InputBindingSetting extends SettingsItem {
+ private static final String INPUT_MAPPING_PREFIX = "InputMapping";
+
+ public InputBindingSetting(String key, String section, int titleId, Setting setting) {
+ super(key, section, setting, titleId, 0);
+ }
+
+ public String getValue() {
+ if (getSetting() == null) {
+ return "";
+ }
+
+ StringSetting setting = (StringSetting) getSetting();
+ return setting.getValue();
+ }
+
+ /**
+ * Returns true if this key is for the 3DS Circle Pad
+ */
+ private boolean IsCirclePad() {
+ switch (getKey()) {
+ case SettingsFile.KEY_CIRCLEPAD_AXIS_HORIZONTAL:
+ case SettingsFile.KEY_CIRCLEPAD_AXIS_VERTICAL:
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this key is for a horizontal axis for a 3DS analog stick or D-pad
+ */
+ public boolean IsHorizontalOrientation() {
+ switch (getKey()) {
+ case SettingsFile.KEY_CIRCLEPAD_AXIS_HORIZONTAL:
+ case SettingsFile.KEY_CSTICK_AXIS_HORIZONTAL:
+ case SettingsFile.KEY_DPAD_AXIS_HORIZONTAL:
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this key is for the 3DS C-Stick
+ */
+ private boolean IsCStick() {
+ switch (getKey()) {
+ case SettingsFile.KEY_CSTICK_AXIS_HORIZONTAL:
+ case SettingsFile.KEY_CSTICK_AXIS_VERTICAL:
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this key is for the 3DS D-Pad
+ */
+ private boolean IsDPad() {
+ switch (getKey()) {
+ case SettingsFile.KEY_DPAD_AXIS_HORIZONTAL:
+ case SettingsFile.KEY_DPAD_AXIS_VERTICAL:
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this key is for the 3DS L/R or ZL/ZR buttons. Note, these are not real
+ * triggers on the 3DS, but we support them as such on a physical gamepad.
+ */
+ public boolean IsTrigger() {
+ switch (getKey()) {
+ case SettingsFile.KEY_BUTTON_L:
+ case SettingsFile.KEY_BUTTON_R:
+ case SettingsFile.KEY_BUTTON_ZL:
+ case SettingsFile.KEY_BUTTON_ZR:
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if a gamepad axis can be used to map this key.
+ */
+ public boolean IsAxisMappingSupported() {
+ return IsCirclePad() || IsCStick() || IsDPad() || IsTrigger();
+ }
+
+ /**
+ * Returns true if a gamepad button can be used to map this key.
+ */
+ private boolean IsButtonMappingSupported() {
+ return !IsAxisMappingSupported() || IsTrigger();
+ }
+
+ /**
+ * Returns the Citra button code for the settings key.
+ */
+ private int getButtonCode() {
+ switch (getKey()) {
+ case SettingsFile.KEY_BUTTON_A:
+ return NativeLibrary.ButtonType.BUTTON_A;
+ case SettingsFile.KEY_BUTTON_B:
+ return NativeLibrary.ButtonType.BUTTON_B;
+ case SettingsFile.KEY_BUTTON_X:
+ return NativeLibrary.ButtonType.BUTTON_X;
+ case SettingsFile.KEY_BUTTON_Y:
+ return NativeLibrary.ButtonType.BUTTON_Y;
+ case SettingsFile.KEY_BUTTON_L:
+ return NativeLibrary.ButtonType.TRIGGER_L;
+ case SettingsFile.KEY_BUTTON_R:
+ return NativeLibrary.ButtonType.TRIGGER_R;
+ case SettingsFile.KEY_BUTTON_ZL:
+ return NativeLibrary.ButtonType.BUTTON_ZL;
+ case SettingsFile.KEY_BUTTON_ZR:
+ return NativeLibrary.ButtonType.BUTTON_ZR;
+ case SettingsFile.KEY_BUTTON_SELECT:
+ return NativeLibrary.ButtonType.BUTTON_SELECT;
+ case SettingsFile.KEY_BUTTON_START:
+ return NativeLibrary.ButtonType.BUTTON_START;
+ case SettingsFile.KEY_BUTTON_UP:
+ return NativeLibrary.ButtonType.DPAD_UP;
+ case SettingsFile.KEY_BUTTON_DOWN:
+ return NativeLibrary.ButtonType.DPAD_DOWN;
+ case SettingsFile.KEY_BUTTON_LEFT:
+ return NativeLibrary.ButtonType.DPAD_LEFT;
+ case SettingsFile.KEY_BUTTON_RIGHT:
+ return NativeLibrary.ButtonType.DPAD_RIGHT;
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the settings key for the specified Citra button code.
+ */
+ private static String getButtonKey(int buttonCode) {
+ switch (buttonCode) {
+ case NativeLibrary.ButtonType.BUTTON_A:
+ return SettingsFile.KEY_BUTTON_A;
+ case NativeLibrary.ButtonType.BUTTON_B:
+ return SettingsFile.KEY_BUTTON_B;
+ case NativeLibrary.ButtonType.BUTTON_X:
+ return SettingsFile.KEY_BUTTON_X;
+ case NativeLibrary.ButtonType.BUTTON_Y:
+ return SettingsFile.KEY_BUTTON_Y;
+ case NativeLibrary.ButtonType.TRIGGER_L:
+ return SettingsFile.KEY_BUTTON_L;
+ case NativeLibrary.ButtonType.TRIGGER_R:
+ return SettingsFile.KEY_BUTTON_R;
+ case NativeLibrary.ButtonType.BUTTON_ZL:
+ return SettingsFile.KEY_BUTTON_ZL;
+ case NativeLibrary.ButtonType.BUTTON_ZR:
+ return SettingsFile.KEY_BUTTON_ZR;
+ case NativeLibrary.ButtonType.BUTTON_SELECT:
+ return SettingsFile.KEY_BUTTON_SELECT;
+ case NativeLibrary.ButtonType.BUTTON_START:
+ return SettingsFile.KEY_BUTTON_START;
+ case NativeLibrary.ButtonType.DPAD_UP:
+ return SettingsFile.KEY_BUTTON_UP;
+ case NativeLibrary.ButtonType.DPAD_DOWN:
+ return SettingsFile.KEY_BUTTON_DOWN;
+ case NativeLibrary.ButtonType.DPAD_LEFT:
+ return SettingsFile.KEY_BUTTON_LEFT;
+ case NativeLibrary.ButtonType.DPAD_RIGHT:
+ return SettingsFile.KEY_BUTTON_RIGHT;
+ }
+ return "";
+ }
+
+ /**
+ * Returns the key used to lookup the reverse mapping for this key, which is used to cleanup old
+ * settings on re-mapping or clearing of a setting.
+ */
+ private String getReverseKey() {
+ String reverseKey = INPUT_MAPPING_PREFIX + "_ReverseMapping_" + getKey();
+
+ if (IsAxisMappingSupported() && !IsTrigger()) {
+ // Triggers are the only axis-supported mappings without orientation
+ reverseKey += "_" + (IsHorizontalOrientation() ? 0 : 1);
+ }
+
+ return reverseKey;
+ }
+
+ /**
+ * Removes the old mapping for this key from the settings, e.g. on user clearing the setting.
+ */
+ public void removeOldMapping() {
+ // Get preferences editor
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(CitraApplication.getAppContext());
+ SharedPreferences.Editor editor = preferences.edit();
+
+ // Try remove all possible keys we wrote for this setting
+ String oldKey = preferences.getString(getReverseKey(), "");
+ if (!oldKey.equals("")) {
+ editor.remove(getKey()); // Used for ui text
+ editor.remove(oldKey); // Used for button mapping
+ editor.remove(oldKey + "_GuestOrientation"); // Used for axis orientation
+ editor.remove(oldKey + "_GuestButton"); // Used for axis button
+ }
+
+ // Apply changes
+ editor.apply();
+ }
+
+ /**
+ * Helper function to get the settings key for an gamepad button.
+ */
+ public static String getInputButtonKey(int keyCode) {
+ return INPUT_MAPPING_PREFIX + "_Button_" + keyCode;
+ }
+
+ /**
+ * Helper function to get the settings key for an gamepad axis.
+ */
+ public static String getInputAxisKey(int axis) {
+ return INPUT_MAPPING_PREFIX + "_HostAxis_" + axis;
+ }
+
+ /**
+ * Helper function to get the settings key for an gamepad axis button (stick or trigger).
+ */
+ public static String getInputAxisButtonKey(int axis) {
+ return getInputAxisKey(axis) + "_GuestButton";
+ }
+
+ /**
+ * Helper function to get the settings key for an gamepad axis orientation.
+ */
+ public static String getInputAxisOrientationKey(int axis) {
+ return getInputAxisKey(axis) + "_GuestOrientation";
+ }
+
+ /**
+ * Helper function to write a gamepad button mapping for the setting.
+ */
+ private void WriteButtonMapping(String key) {
+ // Get preferences editor
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(CitraApplication.getAppContext());
+ SharedPreferences.Editor editor = preferences.edit();
+
+ // Remove mapping for another setting using this input
+ int oldButtonCode = preferences.getInt(key, -1);
+ if (oldButtonCode != -1) {
+ String oldKey = getButtonKey(oldButtonCode);
+ editor.remove(oldKey); // Only need to remove UI text setting, others will be overwritten
+ }
+
+ // Cleanup old mapping for this setting
+ removeOldMapping();
+
+ // Write new mapping
+ editor.putInt(key, getButtonCode());
+
+ // Write next reverse mapping for future cleanup
+ editor.putString(getReverseKey(), key);
+
+ // Apply changes
+ editor.apply();
+ }
+
+ /**
+ * Helper function to write a gamepad axis mapping for the setting.
+ */
+ private void WriteAxisMapping(int axis, int value) {
+ // Get preferences editor
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(CitraApplication.getAppContext());
+ SharedPreferences.Editor editor = preferences.edit();
+
+ // Cleanup old mapping
+ removeOldMapping();
+
+ // Write new mapping
+ editor.putInt(getInputAxisOrientationKey(axis), IsHorizontalOrientation() ? 0 : 1);
+ editor.putInt(getInputAxisButtonKey(axis), value);
+
+ // Write next reverse mapping for future cleanup
+ editor.putString(getReverseKey(), getInputAxisKey(axis));
+
+ // Apply changes
+ editor.apply();
+ }
+
+ /**
+ * Saves the provided key input setting as an Android preference.
+ *
+ * @param keyEvent KeyEvent of this key press.
+ */
+ public void onKeyInput(KeyEvent keyEvent) {
+ if (!IsButtonMappingSupported()) {
+ Toast.makeText(CitraApplication.getAppContext(), R.string.input_message_analog_only, Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ InputDevice device = keyEvent.getDevice();
+
+ WriteButtonMapping(getInputButtonKey(keyEvent.getKeyCode()));
+
+ String uiString = device.getName() + ": Button " + keyEvent.getKeyCode();
+ setUiString(uiString);
+ }
+
+ /**
+ * Saves the provided motion input setting as an Android preference.
+ *
+ * @param device InputDevice from which the input event originated.
+ * @param motionRange MotionRange of the movement
+ * @param axisDir Either '-' or '+' (currently unused)
+ */
+ public void onMotionInput(InputDevice device, InputDevice.MotionRange motionRange,
+ char axisDir) {
+ if (!IsAxisMappingSupported()) {
+ Toast.makeText(CitraApplication.getAppContext(), R.string.input_message_button_only, Toast.LENGTH_LONG).show();
+ return;
+ }
+
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(CitraApplication.getAppContext());
+ SharedPreferences.Editor editor = preferences.edit();
+
+ int button;
+ if (IsCirclePad()) {
+ button = NativeLibrary.ButtonType.STICK_LEFT;
+ } else if (IsCStick()) {
+ button = NativeLibrary.ButtonType.STICK_C;
+ } else if (IsDPad()) {
+ button = NativeLibrary.ButtonType.DPAD;
+ } else {
+ button = getButtonCode();
+ }
+
+ WriteAxisMapping(motionRange.getAxis(), button);
+
+ String uiString = device.getName() + ": Axis " + motionRange.getAxis();
+ setUiString(uiString);
+
+ editor.apply();
+ }
+
+ /**
+ * Sets the string to use in the configuration UI for the gamepad input.
+ */
+ private StringSetting setUiString(String ui) {
+ SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(CitraApplication.getAppContext());
+ SharedPreferences.Editor editor = preferences.edit();
+
+ if (getSetting() == null) {
+ StringSetting setting = new StringSetting(getKey(), getSection(), "");
+ setSetting(setting);
+
+ editor.putString(setting.getKey(), ui);
+ editor.apply();
+
+ return setting;
+ } else {
+ StringSetting setting = (StringSetting) getSetting();
+
+ editor.putString(setting.getKey(), ui);
+ editor.apply();
+
+ return null;
+ }
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_INPUT_BINDING;
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/PremiumHeader.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/PremiumHeader.java
new file mode 100644
index 000000000..2b1793d3e
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/PremiumHeader.java
@@ -0,0 +1,12 @@
+package org.citra.citra_emu.features.settings.model.view;
+
+public final class PremiumHeader extends SettingsItem {
+ public PremiumHeader() {
+ super(null, null, null, 0, 0);
+ }
+
+ @Override
+ public int getType() {
+ return SettingsItem.TYPE_PREMIUM;
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/PremiumSingleChoiceSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/PremiumSingleChoiceSetting.java
new file mode 100644
index 000000000..c0560d2dc
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/PremiumSingleChoiceSetting.java
@@ -0,0 +1,59 @@
+package org.citra.citra_emu.features.settings.model.view;
+
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+
+import org.citra.citra_emu.CitraApplication;
+import org.citra.citra_emu.R;
+import org.citra.citra_emu.features.settings.model.Setting;
+import org.citra.citra_emu.features.settings.ui.SettingsFragmentView;
+
+public final class PremiumSingleChoiceSetting extends SettingsItem {
+ private int mDefaultValue;
+
+ private int mChoicesId;
+ private int mValuesId;
+ private SettingsFragmentView mView;
+
+ private static SharedPreferences mPreferences = PreferenceManager.getDefaultSharedPreferences(CitraApplication.getAppContext());
+
+ public PremiumSingleChoiceSetting(String key, String section, int titleId, int descriptionId,
+ int choicesId, int valuesId, int defaultValue, Setting setting, SettingsFragmentView view) {
+ super(key, section, setting, titleId, descriptionId);
+ mValuesId = valuesId;
+ mChoicesId = choicesId;
+ mDefaultValue = defaultValue;
+ mView = view;
+ }
+
+ public int getChoicesId() {
+ return mChoicesId;
+ }
+
+ public int getValuesId() {
+ return mValuesId;
+ }
+
+ public int getSelectedValue() {
+ return mPreferences.getInt(getKey(), mDefaultValue);
+ }
+
+ /**
+ * Write a value to the backing int. If that int was previously null,
+ * initializes a new one and returns it, so it can be added to the Hashmap.
+ *
+ * @param selection New value of the int.
+ * @return null if overwritten successfully otherwise; a newly created IntSetting.
+ */
+ public void setSelectedValue(int selection) {
+ final SharedPreferences.Editor editor = mPreferences.edit();
+ editor.putInt(getKey(), selection);
+ editor.apply();
+ mView.showToastMessage(CitraApplication.getAppContext().getString(R.string.design_updated), false);
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_SINGLE_CHOICE;
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SettingsItem.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SettingsItem.java
new file mode 100644
index 000000000..305352022
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SettingsItem.java
@@ -0,0 +1,107 @@
+package org.citra.citra_emu.features.settings.model.view;
+
+import org.citra.citra_emu.features.settings.model.Setting;
+import org.citra.citra_emu.features.settings.model.Settings;
+import org.citra.citra_emu.features.settings.ui.SettingsAdapter;
+
+/**
+ * ViewModel abstraction for an Item in the RecyclerView powering SettingsFragments.
+ * Each one corresponds to a {@link Setting} object, so this class's subclasses
+ * should vaguely correspond to those subclasses. There are a few with multiple analogues
+ * and a few with none (Headers, for example, do not correspond to anything in the ini
+ * file.)
+ */
+public abstract class SettingsItem {
+ public static final int TYPE_HEADER = 0;
+ public static final int TYPE_CHECKBOX = 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_BINDING = 5;
+ public static final int TYPE_STRING_SINGLE_CHOICE = 6;
+ public static final int TYPE_DATETIME_SETTING = 7;
+ public static final int TYPE_PREMIUM = 8;
+
+ private String mKey;
+ private String mSection;
+
+ private Setting mSetting;
+
+ private int mNameId;
+ private int mDescriptionId;
+ private boolean mIsPremium;
+
+ /**
+ * Base constructor. Takes a key / section name in case the third parameter, the Setting,
+ * is null; in which case, one can be constructed and saved using the key / section.
+ *
+ * @param key Identifier for the Setting represented by this Item.
+ * @param section Section to which the Setting belongs.
+ * @param setting A possibly-null backing Setting, to be modified on UI events.
+ * @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(String key, String section, Setting setting, int nameId,
+ int descriptionId) {
+ mKey = key;
+ mSection = section;
+ mSetting = setting;
+ mNameId = nameId;
+ mDescriptionId = descriptionId;
+ mIsPremium = (section == Settings.SECTION_PREMIUM);
+ }
+
+ /**
+ * @return The identifier for the backing Setting.
+ */
+ public String getKey() {
+ return mKey;
+ }
+
+ /**
+ * @return The header under which the backing Setting belongs.
+ */
+ public String getSection() {
+ return mSection;
+ }
+
+ /**
+ * @return The backing Setting, possibly null.
+ */
+ public Setting getSetting() {
+ return mSetting;
+ }
+
+ /**
+ * Replace the backing setting with a new one. Generally used in cases where
+ * the backing setting is null.
+ *
+ * @param setting A non-null Setting.
+ */
+ public void setSetting(Setting setting) {
+ mSetting = setting;
+ }
+
+ /**
+ * @return A resource ID for a text string representing this Setting's name.
+ */
+ public int getNameId() {
+ return mNameId;
+ }
+
+ public int getDescriptionId() {
+ return mDescriptionId;
+ }
+
+ public boolean isPremium() {
+ return mIsPremium;
+ }
+
+ /**
+ * 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();
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SingleChoiceSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SingleChoiceSetting.java
new file mode 100644
index 000000000..ee9d225d6
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SingleChoiceSetting.java
@@ -0,0 +1,60 @@
+package org.citra.citra_emu.features.settings.model.view;
+
+import org.citra.citra_emu.features.settings.model.IntSetting;
+import org.citra.citra_emu.features.settings.model.Setting;
+
+public final class SingleChoiceSetting extends SettingsItem {
+ private int mDefaultValue;
+
+ private int mChoicesId;
+ private int mValuesId;
+
+ public SingleChoiceSetting(String key, String section, int titleId, int descriptionId,
+ int choicesId, int valuesId, int defaultValue, Setting setting) {
+ super(key, section, setting, titleId, descriptionId);
+ mValuesId = valuesId;
+ mChoicesId = choicesId;
+ mDefaultValue = defaultValue;
+ }
+
+ public int getChoicesId() {
+ return mChoicesId;
+ }
+
+ public int getValuesId() {
+ return mValuesId;
+ }
+
+ public int getSelectedValue() {
+ if (getSetting() != null) {
+ IntSetting setting = (IntSetting) getSetting();
+ return setting.getValue();
+ } else {
+ return mDefaultValue;
+ }
+ }
+
+ /**
+ * Write a value to the backing int. If that int was previously null,
+ * initializes a new one and returns it, so it can be added to the Hashmap.
+ *
+ * @param selection New value of the int.
+ * @return null if overwritten successfully otherwise; a newly created IntSetting.
+ */
+ public IntSetting setSelectedValue(int selection) {
+ if (getSetting() == null) {
+ IntSetting setting = new IntSetting(getKey(), getSection(), selection);
+ setSetting(setting);
+ return setting;
+ } else {
+ IntSetting setting = (IntSetting) getSetting();
+ setting.setValue(selection);
+ return null;
+ }
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_SINGLE_CHOICE;
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.java
new file mode 100644
index 000000000..551b13f99
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SliderSetting.java
@@ -0,0 +1,101 @@
+package org.citra.citra_emu.features.settings.model.view;
+
+import org.citra.citra_emu.features.settings.model.FloatSetting;
+import org.citra.citra_emu.features.settings.model.IntSetting;
+import org.citra.citra_emu.features.settings.model.Setting;
+import org.citra.citra_emu.utils.Log;
+
+public final class SliderSetting extends SettingsItem {
+ private int mMin;
+ private int mMax;
+ private int mDefaultValue;
+
+ private String mUnits;
+
+ public SliderSetting(String key, String section, int titleId, int descriptionId,
+ int min, int max, String units, int defaultValue, Setting setting) {
+ super(key, section, setting, titleId, descriptionId);
+ mMin = min;
+ mMax = max;
+ mUnits = units;
+ mDefaultValue = defaultValue;
+ }
+
+ public int getMin() {
+ return mMin;
+ }
+
+ public int getMax() {
+ return mMax;
+ }
+
+ public int getDefaultValue() {
+ return mDefaultValue;
+ }
+
+ public int getSelectedValue() {
+ Setting setting = getSetting();
+
+ if (setting == null) {
+ return mDefaultValue;
+ }
+
+ if (setting instanceof IntSetting) {
+ IntSetting intSetting = (IntSetting) setting;
+ return intSetting.getValue();
+ } else if (setting instanceof FloatSetting) {
+ FloatSetting floatSetting = (FloatSetting) setting;
+ return Math.round(floatSetting.getValue());
+ } else {
+ Log.error("[SliderSetting] Error casting setting type.");
+ return -1;
+ }
+ }
+
+ /**
+ * Write a value to the backing int. If that int was previously null,
+ * initializes a new one and returns it, so it can be added to the Hashmap.
+ *
+ * @param selection New value of the int.
+ * @return null if overwritten successfully otherwise; a newly created IntSetting.
+ */
+ public IntSetting setSelectedValue(int selection) {
+ if (getSetting() == null) {
+ IntSetting setting = new IntSetting(getKey(), getSection(), selection);
+ setSetting(setting);
+ return setting;
+ } else {
+ IntSetting setting = (IntSetting) getSetting();
+ setting.setValue(selection);
+ return null;
+ }
+ }
+
+ /**
+ * Write a value to the backing float. If that float was previously null,
+ * initializes a new one and returns it, so it can be added to the Hashmap.
+ *
+ * @param selection New value of the float.
+ * @return null if overwritten successfully otherwise; a newly created FloatSetting.
+ */
+ public FloatSetting setSelectedValue(float selection) {
+ if (getSetting() == null) {
+ FloatSetting setting = new FloatSetting(getKey(), getSection(), selection);
+ setSetting(setting);
+ return setting;
+ } else {
+ FloatSetting setting = (FloatSetting) getSetting();
+ setting.setValue(selection);
+ return null;
+ }
+ }
+
+ public String getUnits() {
+ return mUnits;
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_SLIDER;
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/StringSingleChoiceSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/StringSingleChoiceSetting.java
new file mode 100644
index 000000000..057145d9d
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/StringSingleChoiceSetting.java
@@ -0,0 +1,82 @@
+package org.citra.citra_emu.features.settings.model.view;
+
+import org.citra.citra_emu.features.settings.model.Setting;
+import org.citra.citra_emu.features.settings.model.StringSetting;
+
+public class StringSingleChoiceSetting extends SettingsItem {
+ private String mDefaultValue;
+
+ private String[] mChoicesId;
+ private String[] mValuesId;
+
+ public StringSingleChoiceSetting(String key, String section, int titleId, int descriptionId,
+ String[] choicesId, String[] valuesId, String defaultValue, Setting setting) {
+ super(key, section, setting, titleId, descriptionId);
+ mValuesId = valuesId;
+ mChoicesId = choicesId;
+ mDefaultValue = defaultValue;
+ }
+
+ public String[] getChoicesId() {
+ return mChoicesId;
+ }
+
+ public String[] getValuesId() {
+ return mValuesId;
+ }
+
+ public String getValueAt(int index) {
+ if (mValuesId == null)
+ return null;
+
+ if (index >= 0 && index < mValuesId.length) {
+ return mValuesId[index];
+ }
+
+ return "";
+ }
+
+ public String getSelectedValue() {
+ if (getSetting() != null) {
+ StringSetting setting = (StringSetting) getSetting();
+ return setting.getValue();
+ } else {
+ return mDefaultValue;
+ }
+ }
+
+ public int getSelectValueIndex() {
+ String selectedValue = getSelectedValue();
+ for (int i = 0; i < mValuesId.length; i++) {
+ if (mValuesId[i].equals(selectedValue)) {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ /**
+ * Write a value to the backing int. If that int was previously null,
+ * initializes a new one and returns it, so it can be added to the Hashmap.
+ *
+ * @param selection New value of the int.
+ * @return null if overwritten successfully otherwise; a newly created IntSetting.
+ */
+ public StringSetting setSelectedValue(String selection) {
+ if (getSetting() == null) {
+ StringSetting setting = new StringSetting(getKey(), getSection(), selection);
+ setSetting(setting);
+ return setting;
+ } else {
+ StringSetting setting = (StringSetting) getSetting();
+ setting.setValue(selection);
+ return null;
+ }
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_STRING_SINGLE_CHOICE;
+ }
+}
diff --git a/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SubmenuSetting.java b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SubmenuSetting.java
new file mode 100644
index 000000000..9d44a923f
--- /dev/null
+++ b/src/android/app/src/main/java/org/citra/citra_emu/features/settings/model/view/SubmenuSetting.java
@@ -0,0 +1,21 @@
+package org.citra.citra_emu.features.settings.model.view;
+
+import org.citra.citra_emu.features.settings.model.Setting;
+
+public final class SubmenuSetting extends SettingsItem {
+ private String mMenuKey;
+
+ public SubmenuSetting(String key, Setting setting, int titleId, int descriptionId, String menuKey) {
+ super(key, null, setting, titleId, descriptionId);
+ mMenuKey = menuKey;
+ }
+
+ public String getMenuKey() {
+ return mMenuKey;
+ }
+
+ @Override
+ public int getType() {
+ return TYPE_SUBMENU;
+ }
+}