From 87f4c3f105424ef084be1801bca97ff1620b5869 Mon Sep 17 00:00:00 2001
From: Charles Lombardo <clombardo169@gmail.com>
Date: Tue, 7 Mar 2023 13:40:24 -0500
Subject: [PATCH] android: Convert SettingsAdapter to Kotlin

Update SettingsAdapter.kt
---
 .../features/settings/ui/SettingsAdapter.java | 366 ------------------
 .../features/settings/ui/SettingsAdapter.kt   | 313 +++++++++++++++
 .../app/src/main/res/values/strings.xml       |   2 +
 3 files changed, 315 insertions(+), 366 deletions(-)
 delete mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.java
 create mode 100644 src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt

diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.java b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.java
deleted file mode 100644
index 47e73bfe22..0000000000
--- a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.java
+++ /dev/null
@@ -1,366 +0,0 @@
-package org.yuzu.yuzu_emu.features.settings.ui;
-
-import android.content.Context;
-import android.content.DialogInterface;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.DatePicker;
-import android.widget.SeekBar;
-import android.widget.TextView;
-import android.widget.TimePicker;
-
-import androidx.appcompat.app.AlertDialog;
-import androidx.recyclerview.widget.RecyclerView;
-
-import org.yuzu.yuzu_emu.R;
-import org.yuzu.yuzu_emu.features.settings.model.FloatSetting;
-import org.yuzu.yuzu_emu.features.settings.model.IntSetting;
-import org.yuzu.yuzu_emu.features.settings.model.StringSetting;
-import org.yuzu.yuzu_emu.features.settings.model.view.CheckBoxSetting;
-import org.yuzu.yuzu_emu.features.settings.model.view.DateTimeSetting;
-import org.yuzu.yuzu_emu.features.settings.model.view.SettingsItem;
-import org.yuzu.yuzu_emu.features.settings.model.view.SingleChoiceSetting;
-import org.yuzu.yuzu_emu.features.settings.model.view.SliderSetting;
-import org.yuzu.yuzu_emu.features.settings.model.view.StringSingleChoiceSetting;
-import org.yuzu.yuzu_emu.features.settings.model.view.SubmenuSetting;
-import org.yuzu.yuzu_emu.features.settings.ui.viewholder.CheckBoxSettingViewHolder;
-import org.yuzu.yuzu_emu.features.settings.ui.viewholder.DateTimeViewHolder;
-import org.yuzu.yuzu_emu.features.settings.ui.viewholder.HeaderViewHolder;
-import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SettingViewHolder;
-import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SingleChoiceViewHolder;
-import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SliderViewHolder;
-import org.yuzu.yuzu_emu.features.settings.ui.viewholder.SubmenuViewHolder;
-import org.yuzu.yuzu_emu.utils.Log;
-
-import java.util.ArrayList;
-
-public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolder>
-        implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener {
-    private SettingsFragmentView mView;
-    private 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;
-    }
-
-    @Override
-    public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-        View view;
-        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
-
-        switch (viewType) {
-            case SettingsItem.TYPE_HEADER:
-                view = inflater.inflate(R.layout.list_item_settings_header, parent, false);
-                return new HeaderViewHolder(view, this);
-
-            case SettingsItem.TYPE_CHECKBOX:
-                view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false);
-                return new CheckBoxSettingViewHolder(view, this);
-
-            case SettingsItem.TYPE_SINGLE_CHOICE:
-            case SettingsItem.TYPE_STRING_SINGLE_CHOICE:
-                view = inflater.inflate(R.layout.list_item_setting, parent, false);
-                return new SingleChoiceViewHolder(view, this);
-
-            case SettingsItem.TYPE_SLIDER:
-                view = inflater.inflate(R.layout.list_item_setting, parent, false);
-                return new SliderViewHolder(view, this);
-
-            case SettingsItem.TYPE_SUBMENU:
-                view = inflater.inflate(R.layout.list_item_setting, parent, false);
-                return new SubmenuViewHolder(view, this);
-
-            case SettingsItem.TYPE_DATETIME_SETTING:
-                view = inflater.inflate(R.layout.list_item_setting, parent, false);
-                return new DateTimeViewHolder(view, this);
-
-            default:
-                Log.error("[SettingsAdapter] Invalid view type: " + viewType);
-                return null;
-        }
-    }
-
-    @Override
-    public void onBindViewHolder(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 void setSettings(ArrayList<SettingsItem> settings) {
-        mSettings = settings;
-        notifyDataSetChanged();
-    }
-
-    public void onBooleanClick(CheckBoxSetting item, int position, boolean checked) {
-        IntSetting setting = item.setChecked(checked);
-        notifyItemChanged(position);
-
-        if (setting != null) {
-            mView.putSetting(setting);
-        }
-
-        mView.onSettingChanged();
-    }
-
-    public void onSingleChoiceClick(SingleChoiceSetting item) {
-        mClickedItem = item;
-
-        int value = getSelectionForSingleChoiceValue(item);
-
-        AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
-
-        builder.setTitle(item.getNameId());
-        builder.setSingleChoiceItems(item.getChoicesId(), value, this);
-
-        mDialog = builder.show();
-    }
-
-    public void onSingleChoiceClick(SingleChoiceSetting item, int position) {
-        mClickedPosition = position;
-        onSingleChoiceClick(item);
-    }
-
-    public void onStringSingleChoiceClick(StringSingleChoiceSetting item) {
-        mClickedItem = item;
-
-        AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
-
-        builder.setTitle(item.getNameId());
-        builder.setSingleChoiceItems(item.getChoicesId(), item.getSelectValueIndex(), this);
-
-        mDialog = builder.show();
-    }
-
-    public void onStringSingleChoiceClick(StringSingleChoiceSetting item, int position) {
-        mClickedPosition = position;
-        onStringSingleChoiceClick(item);
-    }
-
-    DialogInterface.OnClickListener defaultCancelListener = (dialog, which) -> closeDialog();
-
-    public void onDateTimeClick(DateTimeSetting item, int position) {
-        mClickedItem = item;
-        mClickedPosition = position;
-
-        AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
-
-        LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
-        View view = inflater.inflate(R.layout.sysclock_datetime_picker, null);
-
-        DatePicker dp = view.findViewById(R.id.date_picker);
-        TimePicker tp = view.findViewById(R.id.time_picker);
-
-        //set date and time to substrings of settingValue; format = 2018-12-24 04:20:69 (alright maybe not that 69)
-        String settingValue = item.getValue();
-        dp.updateDate(Integer.parseInt(settingValue.substring(0, 4)), Integer.parseInt(settingValue.substring(5, 7)) - 1, Integer.parseInt(settingValue.substring(8, 10)));
-
-        tp.setIs24HourView(true);
-        tp.setHour(Integer.parseInt(settingValue.substring(11, 13)));
-        tp.setMinute(Integer.parseInt(settingValue.substring(14, 16)));
-
-        DialogInterface.OnClickListener ok = (dialog, which) -> {
-            //set it
-            int year = dp.getYear();
-            if (year < 2000) {
-                year = 2000;
-            }
-            String month = ("00" + (dp.getMonth() + 1)).substring(String.valueOf(dp.getMonth() + 1).length());
-            String day = ("00" + dp.getDayOfMonth()).substring(String.valueOf(dp.getDayOfMonth()).length());
-            String hr = ("00" + tp.getHour()).substring(String.valueOf(tp.getHour()).length());
-            String min = ("00" + tp.getMinute()).substring(String.valueOf(tp.getMinute()).length());
-            String datetime = year + "-" + month + "-" + day + " " + hr + ":" + min + ":01";
-
-            StringSetting setting = item.setSelectedValue(datetime);
-            if (setting != null) {
-                mView.putSetting(setting);
-            }
-
-            mView.onSettingChanged();
-
-            mClickedItem = null;
-            closeDialog();
-        };
-
-        builder.setView(view);
-        builder.setPositiveButton(android.R.string.ok, ok);
-        builder.setNegativeButton(android.R.string.cancel, defaultCancelListener);
-        mDialog = builder.show();
-    }
-
-    public void onSliderClick(SliderSetting item, int position) {
-        mClickedItem = item;
-        mClickedPosition = position;
-        mSeekbarProgress = item.getSelectedValue();
-        AlertDialog.Builder builder = new AlertDialog.Builder(mView.getActivity());
-
-        LayoutInflater inflater = LayoutInflater.from(mView.getActivity());
-        View view = inflater.inflate(R.layout.dialog_seekbar, null);
-
-        SeekBar seekbar = view.findViewById(R.id.seekbar);
-
-        builder.setTitle(item.getNameId());
-        builder.setView(view);
-        builder.setPositiveButton(android.R.string.ok, this);
-        builder.setNegativeButton(android.R.string.cancel, defaultCancelListener);
-        builder.setNeutralButton(R.string.slider_default, (DialogInterface dialog, int which) -> {
-            seekbar.setProgress(item.getDefaultValue());
-            onClick(dialog, which);
-        });
-        mDialog = builder.show();
-
-        mTextSliderValue = view.findViewById(R.id.text_value);
-        mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
-
-        TextView units = view.findViewById(R.id.text_units);
-        units.setText(item.getUnits());
-
-        seekbar.setMin(item.getMin());
-        seekbar.setMax(item.getMax());
-        seekbar.setProgress(mSeekbarProgress);
-
-        seekbar.setOnSeekBarChangeListener(this);
-    }
-
-    public void onSubmenuClick(SubmenuSetting item) {
-        mView.loadSubMenu(item.getMenuKey());
-    }
-
-    @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();
-            }
-
-            // Get the backing Setting, which may be null (if for example it was missing from the file)
-            IntSetting setting = scSetting.setSelectedValue(value);
-            if (setting != null) {
-                mView.putSetting(setting);
-            }
-
-            closeDialog();
-        } else if (mClickedItem instanceof StringSingleChoiceSetting) {
-            StringSingleChoiceSetting scSetting = (StringSingleChoiceSetting) mClickedItem;
-            String value = scSetting.getValueAt(which);
-            if (!scSetting.getSelectedValue().equals(value))
-                mView.onSettingChanged();
-
-            StringSetting setting = scSetting.setSelectedValue(value);
-            if (setting != null) {
-                mView.putSetting(setting);
-            }
-
-            closeDialog();
-        } else if (mClickedItem instanceof SliderSetting) {
-            SliderSetting sliderSetting = (SliderSetting) mClickedItem;
-            if (sliderSetting.getSelectedValue() != mSeekbarProgress) {
-                mView.onSettingChanged();
-            }
-
-            if (sliderSetting.getSetting() instanceof FloatSetting) {
-                float value = (float) mSeekbarProgress;
-
-                FloatSetting setting = sliderSetting.setSelectedValue(value);
-                if (setting != null) {
-                    mView.putSetting(setting);
-                }
-            } else {
-                IntSetting setting = sliderSetting.setSelectedValue(mSeekbarProgress);
-                if (setting != null) {
-                    mView.putSetting(setting);
-                }
-            }
-
-            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 onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-        mSeekbarProgress = progress;
-        mTextSliderValue.setText(String.valueOf(mSeekbarProgress));
-    }
-
-    @Override
-    public void onStartTrackingTouch(SeekBar seekBar) {
-    }
-
-    @Override
-    public void onStopTrackingTouch(SeekBar seekBar) {
-    }
-
-    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;
-    }
-}
diff --git a/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
new file mode 100644
index 0000000000..f35023b012
--- /dev/null
+++ b/src/android/app/src/main/java/org/yuzu/yuzu_emu/features/settings/ui/SettingsAdapter.kt
@@ -0,0 +1,313 @@
+package org.yuzu.yuzu_emu.features.settings.ui
+
+import android.content.Context
+import android.content.DialogInterface
+import android.icu.util.Calendar
+import android.icu.util.TimeZone
+import android.text.format.DateFormat
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.TextView
+import androidx.appcompat.app.AlertDialog
+import androidx.recyclerview.widget.RecyclerView
+import com.google.android.material.datepicker.MaterialDatePicker
+import com.google.android.material.dialog.MaterialAlertDialogBuilder
+import com.google.android.material.slider.Slider
+import com.google.android.material.timepicker.MaterialTimePicker
+import com.google.android.material.timepicker.TimeFormat
+import org.yuzu.yuzu_emu.R
+import org.yuzu.yuzu_emu.features.settings.model.FloatSetting
+import org.yuzu.yuzu_emu.features.settings.model.view.*
+import org.yuzu.yuzu_emu.features.settings.ui.viewholder.*
+
+class SettingsAdapter(
+    private val fragmentView: SettingsFragmentView,
+    private val context: Context
+) : RecyclerView.Adapter<SettingViewHolder?>(), DialogInterface.OnClickListener {
+    private var settings: ArrayList<SettingsItem>? = null
+    private var clickedItem: SettingsItem? = null
+    private var clickedPosition: Int
+    private var dialog: AlertDialog? = null
+    private var sliderProgress = 0
+    private var textSliderValue: TextView? = null
+
+    private var defaultCancelListener =
+        DialogInterface.OnClickListener { _: DialogInterface?, _: Int -> closeDialog() }
+
+    init {
+        clickedPosition = -1
+    }
+
+    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SettingViewHolder {
+        val view: View
+        val inflater = LayoutInflater.from(parent.context)
+        return when (viewType) {
+            SettingsItem.TYPE_HEADER -> {
+                view = inflater.inflate(R.layout.list_item_settings_header, parent, false)
+                HeaderViewHolder(view, this)
+            }
+            SettingsItem.TYPE_CHECKBOX -> {
+                view = inflater.inflate(R.layout.list_item_setting_checkbox, parent, false)
+                CheckBoxSettingViewHolder(view, this)
+            }
+            SettingsItem.TYPE_SINGLE_CHOICE, SettingsItem.TYPE_STRING_SINGLE_CHOICE -> {
+                view = inflater.inflate(R.layout.list_item_setting, parent, false)
+                SingleChoiceViewHolder(view, this)
+            }
+            SettingsItem.TYPE_SLIDER -> {
+                view = inflater.inflate(R.layout.list_item_setting, parent, false)
+                SliderViewHolder(view, this)
+            }
+            SettingsItem.TYPE_SUBMENU -> {
+                view = inflater.inflate(R.layout.list_item_setting, parent, false)
+                SubmenuViewHolder(view, this)
+            }
+            SettingsItem.TYPE_DATETIME_SETTING -> {
+                view = inflater.inflate(R.layout.list_item_setting, parent, false)
+                DateTimeViewHolder(view, this)
+            }
+            else -> {
+                // TODO: Create an error view since we can't return null now
+                view = inflater.inflate(R.layout.list_item_settings_header, parent, false)
+                HeaderViewHolder(view, this)
+            }
+        }
+    }
+
+    override fun onBindViewHolder(holder: SettingViewHolder, position: Int) {
+        holder.bind(getItem(position))
+    }
+
+    private fun getItem(position: Int): SettingsItem {
+        return settings!![position]
+    }
+
+    override fun getItemCount(): Int {
+        return if (settings != null) {
+            settings!!.size
+        } else {
+            0
+        }
+    }
+
+    override fun getItemViewType(position: Int): Int {
+        return getItem(position).type
+    }
+
+    fun setSettings(settings: ArrayList<SettingsItem>?) {
+        this.settings = settings
+        notifyDataSetChanged()
+    }
+
+    fun onBooleanClick(item: CheckBoxSetting, position: Int, checked: Boolean) {
+        val setting = item.setChecked(checked)
+        notifyItemChanged(position)
+        if (setting != null) {
+            fragmentView.putSetting(setting)
+        }
+        fragmentView.onSettingChanged()
+    }
+
+    private fun onSingleChoiceClick(item: SingleChoiceSetting) {
+        clickedItem = item
+        val value = getSelectionForSingleChoiceValue(item)
+        dialog = MaterialAlertDialogBuilder(context)
+            .setTitle(item.nameId)
+            .setSingleChoiceItems(item.choicesId, value, this)
+            .show()
+    }
+
+    fun onSingleChoiceClick(item: SingleChoiceSetting, position: Int) {
+        clickedPosition = position
+        onSingleChoiceClick(item)
+    }
+
+    private fun onStringSingleChoiceClick(item: StringSingleChoiceSetting) {
+        clickedItem = item
+        dialog = MaterialAlertDialogBuilder(context)
+            .setTitle(item.nameId)
+            .setSingleChoiceItems(item.choicesId, item.selectValueIndex, this)
+            .show()
+    }
+
+    fun onStringSingleChoiceClick(item: StringSingleChoiceSetting, position: Int) {
+        clickedPosition = position
+        onStringSingleChoiceClick(item)
+    }
+
+    fun onDateTimeClick(item: DateTimeSetting, position: Int) {
+        clickedItem = item
+        clickedPosition = position
+        val storedTime = java.lang.Long.decode(item.value) * 1000
+
+        // Helper to extract hour and minute from epoch time
+        val calendar: Calendar = Calendar.getInstance()
+        calendar.timeInMillis = storedTime
+        calendar.timeZone = TimeZone.getTimeZone("UTC")
+
+        var timeFormat: Int = TimeFormat.CLOCK_12H
+        if (DateFormat.is24HourFormat(fragmentView.fragmentActivity)) {
+            timeFormat = TimeFormat.CLOCK_24H
+        }
+
+        val datePicker: MaterialDatePicker<Long> = MaterialDatePicker.Builder.datePicker()
+            .setSelection(storedTime)
+            .setTitleText(R.string.select_rtc_date)
+            .build()
+        val timePicker: MaterialTimePicker = 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 {
+            timePicker.show(
+                fragmentView.fragmentActivity.supportFragmentManager,
+                "TimePicker"
+            )
+        }
+        timePicker.addOnPositiveButtonClickListener {
+            var epochTime: Long = datePicker.selection!! / 1000
+            epochTime += timePicker.hour.toLong() * 60 * 60
+            epochTime += timePicker.minute.toLong() * 60
+            val rtcString = epochTime.toString()
+            if (item.value != rtcString) {
+                notifyItemChanged(clickedPosition)
+                fragmentView.onSettingChanged()
+            }
+            item.setSelectedValue(rtcString)
+            clickedItem = null
+        }
+        datePicker.show(fragmentView.fragmentActivity.supportFragmentManager, "DatePicker")
+    }
+
+    fun onSliderClick(item: SliderSetting, position: Int) {
+        clickedItem = item
+        clickedPosition = position
+        sliderProgress = item.selectedValue
+
+        val inflater = LayoutInflater.from(context)
+        val sliderLayout = inflater.inflate(R.layout.dialog_slider, null)
+        val sliderView = sliderLayout.findViewById<Slider>(R.id.slider)
+
+        textSliderValue = sliderLayout.findViewById(R.id.text_value)
+        textSliderValue!!.text = sliderProgress.toString()
+        val units = sliderLayout.findViewById<TextView>(R.id.text_units)
+        units.text = item.units
+
+        sliderView.apply {
+            valueFrom = item.min.toFloat()
+            valueTo = item.max.toFloat()
+            value = sliderProgress.toFloat()
+            addOnChangeListener { _: Slider, value: Float, _: Boolean ->
+                sliderProgress = value.toInt()
+                textSliderValue!!.text = sliderProgress.toString()
+            }
+        }
+
+        dialog = MaterialAlertDialogBuilder(context)
+            .setTitle(item.nameId)
+            .setView(sliderLayout)
+            .setPositiveButton(android.R.string.ok, this)
+            .setNegativeButton(android.R.string.cancel, defaultCancelListener)
+            .setNeutralButton(R.string.slider_default) { dialog: DialogInterface, which: Int ->
+                sliderView.value = item.defaultValue.toFloat()
+                onClick(dialog, which)
+            }
+            .show()
+    }
+
+    fun onSubmenuClick(item: SubmenuSetting) {
+        fragmentView.loadSubMenu(item.menuKey)
+    }
+
+    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()
+                }
+
+                // Get the backing Setting, which may be null (if for example it was missing from the file)
+                val setting = scSetting.setSelectedValue(value)
+                if (setting != null) {
+                    fragmentView.putSetting(setting)
+                }
+                closeDialog()
+            }
+            is StringSingleChoiceSetting -> {
+                val scSetting = clickedItem as StringSingleChoiceSetting
+                val value = scSetting.getValueAt(which)
+                if (scSetting.selectedValue != value) fragmentView.onSettingChanged()
+                val setting = scSetting.setSelectedValue(value)
+                if (setting != null) {
+                    fragmentView.putSetting(setting)
+                }
+                closeDialog()
+            }
+            is SliderSetting -> {
+                val sliderSetting = clickedItem as SliderSetting
+                if (sliderSetting.selectedValue != sliderProgress) {
+                    fragmentView.onSettingChanged()
+                }
+                if (sliderSetting.setting is FloatSetting) {
+                    val value = sliderProgress.toFloat()
+                    val setting = sliderSetting.setSelectedValue(value)
+                    if (setting != null) {
+                        fragmentView.putSetting(setting)
+                    }
+                } else {
+                    val setting = sliderSetting.setSelectedValue(sliderProgress)
+                    if (setting != null) {
+                        fragmentView.putSetting(setting)
+                    }
+                }
+                closeDialog()
+            }
+        }
+        clickedItem = null
+        sliderProgress = -1
+    }
+
+    fun closeDialog() {
+        if (dialog != null) {
+            if (clickedPosition != -1) {
+                notifyItemChanged(clickedPosition)
+                clickedPosition = -1
+            }
+            dialog!!.dismiss()
+            dialog = null
+        }
+    }
+
+    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
+    }
+}
diff --git a/src/android/app/src/main/res/values/strings.xml b/src/android/app/src/main/res/values/strings.xml
index aa0cef5215..7ef6b803e2 100644
--- a/src/android/app/src/main/res/values/strings.xml
+++ b/src/android/app/src/main/res/values/strings.xml
@@ -23,6 +23,8 @@
     <string name="init_time_description">If the \"System clock type\" setting is set to \"Simulated clock\", this changes the fixed date and time to start at.</string>
     <string name="emulated_region">Emulated region</string>
     <string name="emulated_language">Emulated language</string>
+    <string name="select_rtc_date">Select RTC Date</string>
+    <string name="select_rtc_time">Select RTC Time</string>
 
     <!-- Graphics settings strings -->
     <string name="renderer_api">API</string>