android: Convert SettingsAdapter to Kotlin

Update SettingsAdapter.kt
This commit is contained in:
Charles Lombardo 2023-03-07 13:40:24 -05:00 committed by bunnei
parent 39a65f8446
commit 87f4c3f105
3 changed files with 315 additions and 366 deletions

View file

@ -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;
}
}

View file

@ -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
}
}

View file

@ -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>