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