mirror of
https://github.com/izzy2lost/WeeU.git
synced 2026-07-06 00:19:59 -07:00
Refactor adapters & add audio, graphics and game folder settings
This commit is contained in:
@@ -26,6 +26,21 @@ JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved) {
|
||||
return JNI_VERSION_1_6;
|
||||
}
|
||||
|
||||
void initializeAudioDevices() {
|
||||
auto &config = g_config.data();
|
||||
if (!config.tv_device.empty())
|
||||
AndroidAudio::createAudioDevice(IAudioAPI::AudioAPI::Cubeb,
|
||||
config.tv_channels,
|
||||
config.tv_volume,
|
||||
true);
|
||||
|
||||
if (!config.pad_device.empty())
|
||||
AndroidAudio::createAudioDevice(IAudioAPI::AudioAPI::Cubeb,
|
||||
config.pad_channels,
|
||||
config.pad_volume,
|
||||
false);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_setSurface(JNIEnv *env, jclass clazz, jobject surface,
|
||||
@@ -60,6 +75,7 @@ Java_info_cemu_Cemu_NativeLibrary_setSurfaceSize(JNIEnv *env, jclass clazz, jint
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_startGame(JNIEnv *env, jclass clazz, jlong title_id) {
|
||||
initializeAudioDevices();
|
||||
gui_startGame(*reinterpret_cast<TitleId *>(&title_id));
|
||||
}
|
||||
|
||||
@@ -301,10 +317,6 @@ Java_info_cemu_Cemu_NativeLibrary_initializeEmulation(JNIEnv *env, jclass clazz)
|
||||
InitializeGlobalVulkan();
|
||||
createCemuDirectories();
|
||||
g_config.Load();
|
||||
auto &config = g_config.data();
|
||||
AndroidAudio::createAudioDevice(IAudioAPI::AudioAPI::Cubeb,
|
||||
config.tv_channels,
|
||||
config.tv_volume);
|
||||
}
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
@@ -512,3 +524,98 @@ Java_info_cemu_Cemu_NativeLibrary_onAxisEvent(JNIEnv *env, jclass clazz, jstring
|
||||
auto deviceName = JNIUtils::JStringToString(env, device_name);
|
||||
androidControllerProvider->on_axis_event(deviceDescriptor, deviceName, axis_code, value);
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_getAsyncShaderCompile(JNIEnv *env, jclass clazz) {
|
||||
return g_config.data().async_compile;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_setAsyncShaderCompile(JNIEnv *env, jclass clazz,
|
||||
jboolean enabled) {
|
||||
g_config.data().async_compile = enabled;
|
||||
g_config.Save();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_getVSyncMode(JNIEnv *env, jclass clazz) {
|
||||
return g_config.data().vsync;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_setVSyncMode(JNIEnv *env, jclass clazz,
|
||||
jint vsync_mode) {
|
||||
g_config.data().vsync = vsync_mode;
|
||||
g_config.Save();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_getAccurateBarriers(JNIEnv *env, jclass clazz) {
|
||||
return g_config.data().vk_accurate_barriers;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_setAccurateBarriers(JNIEnv *env, jclass clazz,
|
||||
jboolean enabled) {
|
||||
g_config.data().vk_accurate_barriers = enabled;
|
||||
g_config.Save();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_getAudioDeviceEnabled(JNIEnv *env, jclass clazz, jboolean tv) {
|
||||
const auto &device = tv ? g_config.data().tv_device : g_config.data().pad_device;
|
||||
return !device.empty();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_setAudioDeviceEnabled(JNIEnv *env, jclass clazz,
|
||||
jboolean enabled, jboolean tv) {
|
||||
auto &device = tv ? g_config.data().tv_device : g_config.data().pad_device;
|
||||
if (enabled)
|
||||
device = L"Default";
|
||||
else
|
||||
device.clear();
|
||||
g_config.Save();
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_getAudioDeviceChannels(JNIEnv *env, jclass clazz, jboolean tv) {
|
||||
const auto &deviceChannels = tv ? g_config.data().tv_channels : g_config.data().pad_channels;
|
||||
return deviceChannels;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_setAudioDeviceChannels(JNIEnv *env, jclass clazz,
|
||||
jint channels, jboolean tv) {
|
||||
auto &deviceChannels = tv ? g_config.data().tv_channels : g_config.data().pad_channels;
|
||||
deviceChannels = static_cast<AudioChannels>(channels);
|
||||
g_config.Save();
|
||||
}
|
||||
|
||||
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT jint JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_getAudioDeviceVolume(JNIEnv *env, jclass clazz, jboolean tv) {
|
||||
const auto &deviceVolume = tv ? g_config.data().tv_volume : g_config.data().pad_volume;
|
||||
return deviceVolume;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
JNIEXPORT void JNICALL
|
||||
Java_info_cemu_Cemu_NativeLibrary_setAudioDeviceVolume(JNIEnv *env, jclass clazz,
|
||||
jint volume, jboolean tv) {
|
||||
auto &deviceVolume = tv ? g_config.data().tv_volume : g_config.data().pad_volume;
|
||||
deviceVolume = volume;
|
||||
g_config.Save();
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import info.cemu.Cemu.databinding.FragmentAudioSettingsBinding;
|
||||
|
||||
public class AudioSettingsFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
FragmentAudioSettingsBinding binding = FragmentAudioSettingsBinding.inflate(inflater, container, false);
|
||||
|
||||
GenericRecyclerViewAdapter genericRecyclerViewAdapter = new GenericRecyclerViewAdapter();
|
||||
|
||||
CheckboxRecyclerViewItem tvDeviceCheckbox = new CheckboxRecyclerViewItem(getString(R.string.tv),
|
||||
getString(R.string.tv_audio_description), NativeLibrary.getAudioDeviceEnabled(true),
|
||||
checked -> NativeLibrary.setAudioDeviceEnabled(checked, true));
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(tvDeviceCheckbox);
|
||||
|
||||
var tvChannelsChoices = Stream.of(NativeLibrary.AUDIO_CHANNELS_MONO, NativeLibrary.AUDIO_CHANNELS_STEREO, NativeLibrary.AUDIO_CHANNELS_SURROUND)
|
||||
.map(channels -> new SelectionAdapter.ChoiceItem<>(NativeLibrary.channelsToResourceNameId(channels), channels))
|
||||
.collect(Collectors.toList());
|
||||
int tvChannels = NativeLibrary.getAudioDeviceChannels(true);
|
||||
SelectionAdapter<Integer> tvChannelsSelectionAdapter = new SelectionAdapter<>(tvChannelsChoices, tvChannels);
|
||||
SingleSelectionRecyclerViewItem<Integer> tvChannelsModeSelection = new SingleSelectionRecyclerViewItem<>(getString(R.string.tv_channels),
|
||||
getString(NativeLibrary.channelsToResourceNameId(tvChannels)), tvChannelsSelectionAdapter,
|
||||
(channels, selectionRecyclerViewItem) -> {
|
||||
NativeLibrary.setAudioDeviceChannels(channels, true);
|
||||
selectionRecyclerViewItem.setDescription(getString(NativeLibrary.channelsToResourceNameId(channels)));
|
||||
});
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(tvChannelsModeSelection);
|
||||
|
||||
SliderRecyclerViewItem tvVolumeSlider = new SliderRecyclerViewItem(getString(R.string.tv_volume),
|
||||
NativeLibrary.AUDIO_MIN_VOLUME,
|
||||
NativeLibrary.AUDIO_MAX_VOLUME,
|
||||
NativeLibrary.getAudioDeviceVolume(true),
|
||||
value -> NativeLibrary.setAudioDeviceVolume((int) value, true),
|
||||
value -> (int) value + "%");
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(tvVolumeSlider);
|
||||
|
||||
CheckboxRecyclerViewItem padDeviceCheckbox = new CheckboxRecyclerViewItem(getString(R.string.gamepad),
|
||||
getString(R.string.gamepad_audio_description), NativeLibrary.getAudioDeviceEnabled(true),
|
||||
checked -> NativeLibrary.setAudioDeviceEnabled(checked, true));
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(padDeviceCheckbox);
|
||||
|
||||
var gamepadChannelsChoices = List.of(new SelectionAdapter.ChoiceItem<>(NativeLibrary.channelsToResourceNameId(NativeLibrary.AUDIO_CHANNELS_STEREO), NativeLibrary.AUDIO_CHANNELS_STEREO));
|
||||
int gamepadChannels = NativeLibrary.getAudioDeviceChannels(false);
|
||||
SelectionAdapter<Integer> gamepadChannelsSelectionAdapter = new SelectionAdapter<>(gamepadChannelsChoices, gamepadChannels);
|
||||
SingleSelectionRecyclerViewItem<Integer> gamepadChannelsModeSelection = new SingleSelectionRecyclerViewItem<>(getString(R.string.gamepad_channels),
|
||||
getString(NativeLibrary.channelsToResourceNameId(gamepadChannels)), gamepadChannelsSelectionAdapter,
|
||||
(channels, selectionRecyclerViewItem) -> {
|
||||
NativeLibrary.setAudioDeviceChannels(channels, false);
|
||||
selectionRecyclerViewItem.setDescription(getString(NativeLibrary.channelsToResourceNameId(channels)));
|
||||
});
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(gamepadChannelsModeSelection);
|
||||
|
||||
SliderRecyclerViewItem padVolumeSlider = new SliderRecyclerViewItem(getString(R.string.pad_volume),
|
||||
NativeLibrary.AUDIO_MIN_VOLUME,
|
||||
NativeLibrary.AUDIO_MAX_VOLUME,
|
||||
NativeLibrary.getAudioDeviceVolume(false),
|
||||
value -> NativeLibrary.setAudioDeviceVolume((int) value, false),
|
||||
value -> (int) value + "%");
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(padVolumeSlider);
|
||||
|
||||
binding.audioSettingsRecyclerView.setAdapter(genericRecyclerViewAdapter);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
}
|
||||
@@ -24,8 +24,8 @@ public class ButtonRecyclerViewItem implements RecyclerViewItem {
|
||||
}
|
||||
|
||||
private final OnButtonClickListener onButtonClickListener;
|
||||
private String text;
|
||||
private String description;
|
||||
private final String text;
|
||||
private final String description;
|
||||
|
||||
public ButtonRecyclerViewItem(String text, String description, OnButtonClickListener onButtonClickListener) {
|
||||
this.text = text;
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
import android.app.Application;
|
||||
import android.os.FileUtils;
|
||||
import android.util.DisplayMetrics;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class CemuApplication extends Application {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
public class CemuPreferences {
|
||||
public static final String PREFERENCES_NAME = "CEMU_PREFERENCES";
|
||||
public static final String GAMES_PATH_KEY = "GAME_PATHS_KEY";
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.checkbox.MaterialCheckBox;
|
||||
|
||||
public class CheckboxRecyclerViewItem implements RecyclerViewItem {
|
||||
public interface OnCheckedChangeListener {
|
||||
void onCheckChanged(boolean checked);
|
||||
}
|
||||
|
||||
private static class CheckBoxViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView label;
|
||||
TextView description;
|
||||
MaterialCheckBox checkBox;
|
||||
|
||||
public CheckBoxViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
label = itemView.findViewById(R.id.checkbox_label);
|
||||
description = itemView.findViewById(R.id.checkbox_description);
|
||||
checkBox = itemView.findViewById(R.id.checkbox);
|
||||
}
|
||||
}
|
||||
|
||||
private final String label;
|
||||
private final String description;
|
||||
private boolean checked;
|
||||
private final OnCheckedChangeListener onCheckedChangeListener;
|
||||
|
||||
public CheckboxRecyclerViewItem(String label, String description, boolean checked, OnCheckedChangeListener onCheckedChangeListener) {
|
||||
this.label = label;
|
||||
this.description = description;
|
||||
this.checked = checked;
|
||||
this.onCheckedChangeListener = onCheckedChangeListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
return new CheckBoxViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_checkbox, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, RecyclerView.Adapter<RecyclerView.ViewHolder> adapter) {
|
||||
CheckBoxViewHolder checkBoxViewHolder = (CheckBoxViewHolder) viewHolder;
|
||||
checkBoxViewHolder.label.setText(label);
|
||||
checkBoxViewHolder.description.setText(description);
|
||||
checkBoxViewHolder.checkBox.setChecked(checked);
|
||||
checkBoxViewHolder.itemView.setOnClickListener(view -> {
|
||||
checked = !checkBoxViewHolder.checkBox.isChecked();
|
||||
checkBoxViewHolder.checkBox.setChecked(checked);
|
||||
if (onCheckedChangeListener != null) onCheckedChangeListener.onCheckChanged(checked);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -35,10 +35,15 @@ public class ControllerInputsFragment extends Fragment {
|
||||
}
|
||||
|
||||
private void setControllerInputs(Map<Integer, String> inputs) {
|
||||
emulatedControllerTypeAdapter.setCurrentControllerType(controllerType);
|
||||
emulatedControllerTypeAdapter.setSelectedValue(controllerType);
|
||||
emulatedControllerTypeAdapter.setControllerTypeCounts(NativeLibrary.getVPADControllersCount(), NativeLibrary.getWPADControllersCount());
|
||||
SpinnerRecyclerViewItem emulatedControllerSpinner = new SpinnerRecyclerViewItem(R.string.emulated_controller_label, emulatedControllerTypeAdapter, emulatedControllerTypeAdapter.getPosition(controllerType), position -> onTypeChanged(emulatedControllerTypeAdapter.getItem(position)));
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(emulatedControllerSpinner);
|
||||
String controllerTypeName = getString(NativeLibrary.controllerTypeToResourceNameId(controllerType));
|
||||
|
||||
SingleSelectionRecyclerViewItem<Integer> emulatedControllerSelection = new SingleSelectionRecyclerViewItem<>(getString(R.string.emulated_controller_label),
|
||||
getString(R.string.emulated_controller_selection_description, controllerTypeName),
|
||||
emulatedControllerTypeAdapter,
|
||||
(controllerType, selectionRecyclerViewItem) -> onTypeChanged(controllerType));
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(emulatedControllerSelection);
|
||||
for (var controllerInputsGroups : controllerInputsDataProvider.getControllerInputs(controllerType, inputs)) {
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(new HeaderRecyclerViewItem(controllerInputsGroups.groupResourceIdName));
|
||||
for (var controllerInput : controllerInputsGroups.inputs) {
|
||||
|
||||
@@ -1,23 +1,22 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.TextView;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class EmulatedControllerTypeAdapter extends BaseAdapter {
|
||||
private final List<Integer> controllerTypes = List.of(NativeLibrary.EMULATED_CONTROLLER_TYPE_DISABLED, NativeLibrary.EMULATED_CONTROLLER_TYPE_VPAD, NativeLibrary.EMULATED_CONTROLLER_TYPE_PRO, NativeLibrary.EMULATED_CONTROLLER_TYPE_CLASSIC, NativeLibrary.EMULATED_CONTROLLER_TYPE_WIIMOTE);
|
||||
public class EmulatedControllerTypeAdapter extends SelectionAdapter<Integer> {
|
||||
private int vpadCount = 0;
|
||||
private int wpadCount = 0;
|
||||
private int currentControllerType = NativeLibrary.EMULATED_CONTROLLER_TYPE_DISABLED;
|
||||
|
||||
public void setCurrentControllerType(int currentControllerType) {
|
||||
this.currentControllerType = currentControllerType;
|
||||
notifyDataSetChanged();
|
||||
public EmulatedControllerTypeAdapter() {
|
||||
choiceItems = Stream.of(NativeLibrary.EMULATED_CONTROLLER_TYPE_DISABLED,
|
||||
NativeLibrary.EMULATED_CONTROLLER_TYPE_VPAD,
|
||||
NativeLibrary.EMULATED_CONTROLLER_TYPE_PRO,
|
||||
NativeLibrary.EMULATED_CONTROLLER_TYPE_CLASSIC,
|
||||
NativeLibrary.EMULATED_CONTROLLER_TYPE_WIIMOTE)
|
||||
.map(type -> new ChoiceItem<>(NativeLibrary.controllerTypeToResourceNameId(type), type))
|
||||
.collect(Collectors.toList());
|
||||
setSelectedValue(NativeLibrary.EMULATED_CONTROLLER_TYPE_DISABLED);
|
||||
}
|
||||
|
||||
public void setControllerTypeCounts(int vpadCount, int wpadCount) {
|
||||
@@ -28,7 +27,8 @@ public class EmulatedControllerTypeAdapter extends BaseAdapter {
|
||||
|
||||
@Override
|
||||
public boolean isEnabled(int position) {
|
||||
int type = controllerTypes.get(position);
|
||||
int currentControllerType = getItem(selectedPosition);
|
||||
int type = getItem(position);
|
||||
if (type == NativeLibrary.EMULATED_CONTROLLER_TYPE_DISABLED)
|
||||
return true;
|
||||
if (type == NativeLibrary.EMULATED_CONTROLLER_TYPE_VPAD)
|
||||
@@ -36,36 +36,4 @@ public class EmulatedControllerTypeAdapter extends BaseAdapter {
|
||||
boolean isWPAD = currentControllerType != NativeLibrary.EMULATED_CONTROLLER_TYPE_VPAD && currentControllerType != NativeLibrary.EMULATED_CONTROLLER_TYPE_DISABLED;
|
||||
return isWPAD || wpadCount < NativeLibrary.MAX_WPAD_CONTROLLERS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return controllerTypes.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getItem(int position) {
|
||||
return controllerTypes.get(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View view, ViewGroup viewGroup) {
|
||||
int type = controllerTypes.get(position);
|
||||
if (view == null)
|
||||
view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_choice, viewGroup, false);
|
||||
TextView textView = view.findViewById(R.id.textview_choice);
|
||||
textView.setText(NativeLibrary.controllerTypeToResourceNameId(type));
|
||||
float DISABLED_ALPHA = 0.6f;
|
||||
if (!isEnabled(position))
|
||||
view.setAlpha(DISABLED_ALPHA);
|
||||
return view;
|
||||
}
|
||||
|
||||
public int getPosition(int controllerType) {
|
||||
return controllerTypes.indexOf(controllerType);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -26,6 +28,11 @@ public class GamesFragment extends Fragment {
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
binding = FragmentGamesBinding.inflate(inflater, container, false);
|
||||
|
||||
SharedPreferences cemuPreferences = requireActivity().getSharedPreferences(CemuPreferences.PREFERENCES_NAME, Context.MODE_PRIVATE);
|
||||
String gamesPath = cemuPreferences.getString(CemuPreferences.GAMES_PATH_KEY, null);
|
||||
if (gamesPath != null)
|
||||
NativeLibrary.addGamePath(gamesPath);
|
||||
RecyclerView recyclerView = binding.gamesRecyclerView;
|
||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||
View rootView = binding.getRoot();
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import info.cemu.Cemu.databinding.FragmentGraphicsSettingsBinding;
|
||||
|
||||
public class GraphicsSettingsFragment extends Fragment {
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
FragmentGraphicsSettingsBinding binding = FragmentGraphicsSettingsBinding.inflate(inflater, container, false);
|
||||
|
||||
GenericRecyclerViewAdapter genericRecyclerViewAdapter = new GenericRecyclerViewAdapter();
|
||||
|
||||
CheckboxRecyclerViewItem asyncShaderCheckbox = new CheckboxRecyclerViewItem(getString(R.string.async_shader_compile), getString(R.string.async_shader_compile_description), NativeLibrary.getAsyncShaderCompile(), NativeLibrary::setAsyncShaderCompile);
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(asyncShaderCheckbox);
|
||||
|
||||
int vsyncMode = NativeLibrary.getVSyncMode();
|
||||
var vsyncChoices = Stream.of(NativeLibrary.VSYNC_MODE_OFF, NativeLibrary.VSYNC_MODE_DOUBLE_BUFFERING, NativeLibrary.VSYNC_MODE_TRIPLE_BUFFERING)
|
||||
.map(vsync -> new SelectionAdapter.ChoiceItem<>(NativeLibrary.vsyncModeToResourceNameId(vsync), vsync))
|
||||
.collect(Collectors.toList());
|
||||
SelectionAdapter<Integer> vsyncSelectionAdapter = new SelectionAdapter<>(vsyncChoices, vsyncMode);
|
||||
SingleSelectionRecyclerViewItem<Integer> vsyncModeSelection = new SingleSelectionRecyclerViewItem<>(getString(R.string.vsync),
|
||||
getString(NativeLibrary.vsyncModeToResourceNameId(vsyncMode)), vsyncSelectionAdapter,
|
||||
(vsync, selectionRecyclerViewItem) -> {
|
||||
NativeLibrary.setVSyncMode(vsync);
|
||||
selectionRecyclerViewItem.setDescription(getString(NativeLibrary.vsyncModeToResourceNameId(vsync)));
|
||||
});
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(vsyncModeSelection);
|
||||
|
||||
CheckboxRecyclerViewItem accurateBarriersCheckbox = new CheckboxRecyclerViewItem(getString(R.string.accurate_barriers), getString(R.string.accurate_barriers_description), NativeLibrary.getAccurateBarriers(), NativeLibrary::setAccurateBarriers);
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(accurateBarriersCheckbox);
|
||||
|
||||
binding.graphicsSettingsRecyclerView.setAdapter(genericRecyclerViewAdapter);
|
||||
return binding.getRoot();
|
||||
}
|
||||
}
|
||||
@@ -3,32 +3,17 @@ package info.cemu.Cemu;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
import androidx.navigation.NavController;
|
||||
import androidx.navigation.Navigation;
|
||||
import androidx.navigation.ui.AppBarConfiguration;
|
||||
import androidx.navigation.ui.NavigationUI;
|
||||
|
||||
import info.cemu.Cemu.databinding.ActivityMainBinding;
|
||||
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
|
||||
|
||||
public class MainActivity extends AppCompatActivity {
|
||||
private ActivityMainBinding binding;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
ActivityMainBinding binding = ActivityMainBinding.inflate(getLayoutInflater());
|
||||
setContentView(binding.getRoot());
|
||||
|
||||
binding.fab.setOnClickListener(
|
||||
view -> {
|
||||
Intent intent = new Intent(this, SettingsActivity.class);
|
||||
@@ -36,19 +21,4 @@ public class MainActivity extends AppCompatActivity {
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
// Handle action bar item clicks here. The action bar will
|
||||
// automatically handle clicks on the Home/Up button, so long
|
||||
// as you specify a parent activity in AndroidManifest.xml.
|
||||
int id = item.getItemId();
|
||||
|
||||
//noinspection SimplifiableIfStatement
|
||||
if (id == R.id.action_settings) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
}
|
||||
@@ -198,17 +198,14 @@ public class NativeLibrary {
|
||||
static final int MAX_WPAD_CONTROLLERS = 7;
|
||||
|
||||
public static int controllerTypeToResourceNameId(int type) {
|
||||
if (type == NativeLibrary.EMULATED_CONTROLLER_TYPE_DISABLED)
|
||||
return R.string.disabled;
|
||||
else if (type == NativeLibrary.EMULATED_CONTROLLER_TYPE_VPAD)
|
||||
return R.string.vpad_controller;
|
||||
else if (type == NativeLibrary.EMULATED_CONTROLLER_TYPE_PRO)
|
||||
return R.string.pro_controller;
|
||||
else if (type == NativeLibrary.EMULATED_CONTROLLER_TYPE_WIIMOTE)
|
||||
return R.string.wiimote_controller;
|
||||
else if (type == NativeLibrary.EMULATED_CONTROLLER_TYPE_CLASSIC)
|
||||
return R.string.classic_controller;
|
||||
throw new RuntimeException("Invalid controller type: " + type);
|
||||
return switch (type) {
|
||||
case EMULATED_CONTROLLER_TYPE_DISABLED -> R.string.disabled;
|
||||
case EMULATED_CONTROLLER_TYPE_VPAD -> R.string.vpad_controller;
|
||||
case EMULATED_CONTROLLER_TYPE_PRO -> R.string.pro_controller;
|
||||
case EMULATED_CONTROLLER_TYPE_WIIMOTE -> R.string.wiimote_controller;
|
||||
case EMULATED_CONTROLLER_TYPE_CLASSIC -> R.string.classic_controller;
|
||||
default -> throw new RuntimeException("Invalid controller type: " + type);
|
||||
};
|
||||
}
|
||||
|
||||
public static native void setControllerType(int index, int emulatedControllerType);
|
||||
@@ -232,4 +229,58 @@ public class NativeLibrary {
|
||||
public static native void onKeyEvent(String deviceDescriptor, String deviceName, int keyCode, boolean isPressed);
|
||||
|
||||
public static native void onAxisEvent(String deviceDescriptor, String deviceName, int axisCode, float value);
|
||||
|
||||
public static native boolean getAsyncShaderCompile();
|
||||
|
||||
public static native void setAsyncShaderCompile(boolean enabled);
|
||||
|
||||
static final int VSYNC_MODE_OFF = 0;
|
||||
static final int VSYNC_MODE_DOUBLE_BUFFERING = 1;
|
||||
static final int VSYNC_MODE_TRIPLE_BUFFERING = 2;
|
||||
|
||||
public static int vsyncModeToResourceNameId(int vsyncMode) {
|
||||
return switch (vsyncMode) {
|
||||
case VSYNC_MODE_OFF -> R.string.off;
|
||||
case VSYNC_MODE_DOUBLE_BUFFERING -> R.string.double_buffering;
|
||||
case VSYNC_MODE_TRIPLE_BUFFERING -> R.string.triple_buffering;
|
||||
default -> throw new RuntimeException("Invalid vsync mode: " + vsyncMode);
|
||||
};
|
||||
}
|
||||
|
||||
public static native int getVSyncMode();
|
||||
|
||||
public static native void setVSyncMode(int vsyncMode);
|
||||
|
||||
public static native boolean getAccurateBarriers();
|
||||
|
||||
public static native void setAccurateBarriers(boolean enabled);
|
||||
|
||||
public static native boolean getAudioDeviceEnabled(boolean tv);
|
||||
|
||||
public static native void setAudioDeviceEnabled(boolean enabled, boolean tv);
|
||||
|
||||
static final int AUDIO_CHANNELS_MONO = 0;
|
||||
static final int AUDIO_CHANNELS_STEREO = 1;
|
||||
static final int AUDIO_CHANNELS_SURROUND = 2;
|
||||
|
||||
public static int channelsToResourceNameId(int channels) {
|
||||
return switch (channels) {
|
||||
case AUDIO_CHANNELS_MONO -> R.string.mono;
|
||||
case AUDIO_CHANNELS_STEREO -> R.string.stereo;
|
||||
case AUDIO_CHANNELS_SURROUND -> R.string.surround;
|
||||
default -> throw new RuntimeException("Invalid channels type: " + channels);
|
||||
};
|
||||
}
|
||||
|
||||
public static native void setAudioDeviceChannels(int channels, boolean tv);
|
||||
|
||||
public static native int getAudioDeviceChannels(boolean tv);
|
||||
|
||||
static final int AUDIO_MIN_VOLUME = 0;
|
||||
static final int AUDIO_MAX_VOLUME = 100;
|
||||
|
||||
public static native void setAudioDeviceVolume(int volume, boolean tv);
|
||||
|
||||
public static native int getAudioDeviceVolume(boolean tv);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
import static android.app.Activity.RESULT_OK;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.documentfile.provider.DocumentFile;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.navigation.fragment.NavHostFragment;
|
||||
|
||||
import info.cemu.Cemu.databinding.FragmentOptionsBinding;
|
||||
|
||||
public class OptionsFragment extends Fragment {
|
||||
private ActivityResultLauncher<Intent> folderSelectionLauncher;
|
||||
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
FragmentOptionsBinding binding = FragmentOptionsBinding.inflate(inflater, container, false);
|
||||
GenericRecyclerViewAdapter genericRecyclerViewAdapter = new GenericRecyclerViewAdapter();
|
||||
folderSelectionLauncher = registerForActivityResult(new ActivityResultContracts.StartActivityForResult(), result -> {
|
||||
if (result.getResultCode() == RESULT_OK) {
|
||||
Intent data = result.getData();
|
||||
if (data != null) {
|
||||
Uri uri = data.getData();
|
||||
requireActivity().getContentResolver().takePersistableUriPermission(uri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
||||
DocumentFile documentFile = DocumentFile.fromTreeUri(requireContext(), uri);
|
||||
if (documentFile == null) return;
|
||||
String gamePath = documentFile.getUri().toString();
|
||||
NativeLibrary.addGamePath(gamePath);
|
||||
SharedPreferences.Editor preferencesEditor = requireActivity().getSharedPreferences(CemuPreferences.PREFERENCES_NAME, Context.MODE_PRIVATE).edit();
|
||||
preferencesEditor.putString(CemuPreferences.GAMES_PATH_KEY, gamePath);
|
||||
preferencesEditor.apply();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(new ButtonRecyclerViewItem(getString(R.string.games_folder_label), getString(R.string.games_folder_description), () -> {
|
||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
folderSelectionLauncher.launch(intent);
|
||||
}));
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(new SimpleButtonRecyclerViewItem(getString(R.string.input_settings), () -> NavHostFragment.findNavController(OptionsFragment.this).navigate(R.id.action_optionsFragment_to_inputSettingsFragment)));
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(new SimpleButtonRecyclerViewItem(getString(R.string.graphics_settings), () -> NavHostFragment.findNavController(OptionsFragment.this).navigate(R.id.action_optionsFragment_to_graphicSettingsFragment)));
|
||||
genericRecyclerViewAdapter.addRecyclerViewItem(new SimpleButtonRecyclerViewItem(getString(R.string.audio_settings), () -> NavHostFragment.findNavController(OptionsFragment.this).navigate(R.id.action_optionsFragment_to_audioSettingsFragment)));
|
||||
binding.optionsRecyclerView.setAdapter(genericRecyclerViewAdapter);
|
||||
|
||||
return binding.getRoot();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.BaseAdapter;
|
||||
|
||||
import com.google.android.material.radiobutton.MaterialRadioButton;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.OptionalInt;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
public class SelectionAdapter<T> extends BaseAdapter {
|
||||
public static class ChoiceItem<T> {
|
||||
int choiceTextResourceId;
|
||||
T choiceValue;
|
||||
|
||||
public ChoiceItem(int choiceTextResourceId, T choiceValue) {
|
||||
this.choiceTextResourceId = choiceTextResourceId;
|
||||
this.choiceValue = choiceValue;
|
||||
}
|
||||
}
|
||||
|
||||
protected List<ChoiceItem<T>> choiceItems = new ArrayList<>();
|
||||
protected int selectedPosition = 0;
|
||||
|
||||
public SelectionAdapter() {
|
||||
super();
|
||||
}
|
||||
|
||||
public SelectionAdapter(List<ChoiceItem<T>> choiceItems, T selectedValue) {
|
||||
super();
|
||||
this.choiceItems = choiceItems;
|
||||
setSelectedValue(selectedValue);
|
||||
}
|
||||
|
||||
public void setSelectedValue(T selectedValue) {
|
||||
selectedPosition = getPositionOf(selectedValue);
|
||||
}
|
||||
|
||||
public int getPositionOf(T value) {
|
||||
OptionalInt optionalInt = IntStream.range(0, choiceItems.size()).filter(position -> choiceItems.get(position).choiceValue.equals(value)).findFirst();
|
||||
if (!optionalInt.isPresent())
|
||||
throw new RuntimeException("value " + value + " was not found in the list of choiceItems");
|
||||
return optionalInt.getAsInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return choiceItems.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public T getItem(int position) {
|
||||
return choiceItems.get(position).choiceValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View view, ViewGroup viewGroup) {
|
||||
if (view == null)
|
||||
view = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.layout_single_selection_item, viewGroup, false);
|
||||
MaterialRadioButton radioButton = view.findViewById(R.id.single_selection_item_radio_button);
|
||||
radioButton.setEnabled(isEnabled(position));
|
||||
radioButton.setText(choiceItems.get(position).choiceTextResourceId);
|
||||
radioButton.setChecked(position == selectedPosition);
|
||||
return view;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class SimpleButtonRecyclerViewItem implements RecyclerViewItem {
|
||||
public interface OnButtonClickListener {
|
||||
void onButtonClick();
|
||||
}
|
||||
|
||||
private static class SimpleButtonViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView text;
|
||||
|
||||
public SimpleButtonViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
text = itemView.findViewById(R.id.simple_button_text);
|
||||
}
|
||||
}
|
||||
|
||||
private final SimpleButtonRecyclerViewItem.OnButtonClickListener onButtonClickListener;
|
||||
private final String text;
|
||||
|
||||
public SimpleButtonRecyclerViewItem(String text, OnButtonClickListener onButtonClickListener) {
|
||||
this.text = text;
|
||||
this.onButtonClickListener = onButtonClickListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
return new SimpleButtonRecyclerViewItem.SimpleButtonViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_simple_button, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, RecyclerView.Adapter<RecyclerView.ViewHolder> adapter) {
|
||||
SimpleButtonRecyclerViewItem.SimpleButtonViewHolder buttonViewHolder = (SimpleButtonRecyclerViewItem.SimpleButtonViewHolder) viewHolder;
|
||||
buttonViewHolder.text.setText(text);
|
||||
buttonViewHolder.itemView.setOnClickListener(view -> {
|
||||
if (onButtonClickListener != null)
|
||||
onButtonClickListener.onButtonClick();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
public class SingleSelectionRecyclerViewItem<T> implements RecyclerViewItem {
|
||||
private static class SingleSelectionViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView label;
|
||||
TextView description;
|
||||
|
||||
public SingleSelectionViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
label = itemView.findViewById(R.id.selection_label);
|
||||
description = itemView.findViewById(R.id.selection_description);
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnItemSelectedListener<T> {
|
||||
void onItemSelected(T selectedValue, SingleSelectionRecyclerViewItem<T> selectionRecyclerViewItem);
|
||||
}
|
||||
|
||||
private final SelectionAdapter<T> selectionAdapter;
|
||||
private final String label;
|
||||
private String description;
|
||||
private final OnItemSelectedListener<T> onItemSelectedListener;
|
||||
private SingleSelectionViewHolder singleSelectionViewHolder;
|
||||
private RecyclerView.Adapter<RecyclerView.ViewHolder> recyclerViewAdapter;
|
||||
|
||||
public SingleSelectionRecyclerViewItem(String label, String description, SelectionAdapter<T> selectionAdapter, OnItemSelectedListener<T> onItemSelectedListener) {
|
||||
this.label = label;
|
||||
this.description = description;
|
||||
this.selectionAdapter = selectionAdapter;
|
||||
this.onItemSelectedListener = onItemSelectedListener;
|
||||
}
|
||||
|
||||
public void setDescription(String description) {
|
||||
this.description = description;
|
||||
recyclerViewAdapter.notifyItemChanged(singleSelectionViewHolder.getAdapterPosition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
return new SingleSelectionViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_single_selection, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, RecyclerView.Adapter<RecyclerView.ViewHolder> recyclerViewAdapter) {
|
||||
this.recyclerViewAdapter = recyclerViewAdapter;
|
||||
singleSelectionViewHolder = (SingleSelectionViewHolder) viewHolder;
|
||||
singleSelectionViewHolder.label.setText(label);
|
||||
singleSelectionViewHolder.description.setText(description);
|
||||
singleSelectionViewHolder.itemView.setOnClickListener(view -> {
|
||||
MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(viewHolder.itemView.getContext());
|
||||
builder.setTitle(label).setAdapter(selectionAdapter, (dialogInterface, position) -> {
|
||||
if (!selectionAdapter.isEnabled(position))
|
||||
return;
|
||||
T selectedValue = selectionAdapter.getItem(position);
|
||||
selectionAdapter.setSelectedValue(selectedValue);
|
||||
if (onItemSelectedListener != null)
|
||||
onItemSelectedListener.onItemSelected(selectedValue, SingleSelectionRecyclerViewItem.this);
|
||||
|
||||
}).setNegativeButton(R.string.cancel, (dialogInterface, i) -> dialogInterface.dismiss()).show();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.google.android.material.slider.LabelFormatter;
|
||||
import com.google.android.material.slider.Slider;
|
||||
|
||||
public class SliderRecyclerViewItem implements RecyclerViewItem {
|
||||
public interface OnChangeListener {
|
||||
void onChange(float value);
|
||||
}
|
||||
|
||||
private static class SliderViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView label;
|
||||
Slider slider;
|
||||
|
||||
public SliderViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
label = itemView.findViewById(R.id.slider_label);
|
||||
slider = itemView.findViewById(R.id.slider);
|
||||
}
|
||||
}
|
||||
|
||||
private final String label;
|
||||
private final float valueFrom;
|
||||
private final float valueTo;
|
||||
private float currentValue;
|
||||
private final OnChangeListener onChangeListener;
|
||||
private LabelFormatter labelFormatter;
|
||||
|
||||
public SliderRecyclerViewItem(String label, float valueFrom, float valueTo, float currentValue, OnChangeListener onChangeListener, LabelFormatter labelFormatter) {
|
||||
this.label = label;
|
||||
this.valueFrom = valueFrom;
|
||||
this.valueTo = valueTo;
|
||||
this.currentValue = currentValue;
|
||||
this.onChangeListener = onChangeListener;
|
||||
this.labelFormatter = labelFormatter;
|
||||
}
|
||||
|
||||
public SliderRecyclerViewItem(String label, float valueFrom, float valueTo, float currentValue, OnChangeListener onChangeListener) {
|
||||
this.label = label;
|
||||
this.valueFrom = valueFrom;
|
||||
this.valueTo = valueTo;
|
||||
this.currentValue = currentValue;
|
||||
this.onChangeListener = onChangeListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
return new SliderViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_slider, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, RecyclerView.Adapter<RecyclerView.ViewHolder> adapter) {
|
||||
SliderViewHolder sliderViewHolder = (SliderViewHolder) viewHolder;
|
||||
sliderViewHolder.label.setText(label);
|
||||
if (labelFormatter != null) sliderViewHolder.slider.setLabelFormatter(labelFormatter);
|
||||
sliderViewHolder.slider.setValueFrom(valueFrom);
|
||||
sliderViewHolder.slider.setValueTo(valueTo);
|
||||
float stepSize = 1.0f;
|
||||
sliderViewHolder.slider.setStepSize(stepSize);
|
||||
sliderViewHolder.slider.setValue(currentValue);
|
||||
sliderViewHolder.slider.addOnChangeListener((slider, value, fromUser) -> {
|
||||
currentValue = value;
|
||||
if (onChangeListener != null) onChangeListener.onChange(currentValue);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
package info.cemu.Cemu;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Spinner;
|
||||
import android.widget.SpinnerAdapter;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
public class SpinnerRecyclerViewItem implements RecyclerViewItem {
|
||||
public interface OnItemSelectedListener {
|
||||
void onItemSelected(int position);
|
||||
}
|
||||
|
||||
private static class SpinnerViewHolder extends RecyclerView.ViewHolder {
|
||||
TextView text;
|
||||
Spinner spinner;
|
||||
|
||||
public SpinnerViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
text = itemView.findViewById(R.id.spinner_label);
|
||||
spinner = itemView.findViewById(R.id.spinner);
|
||||
}
|
||||
}
|
||||
|
||||
private final SpinnerAdapter spinnerAdapter;
|
||||
private final int spinnerLabelResourceId;
|
||||
private final int initialSelection;
|
||||
private final OnItemSelectedListener onItemSelectedListener;
|
||||
|
||||
public SpinnerRecyclerViewItem(int spinnerLabelResourceId, SpinnerAdapter spinnerAdapter, int initialSelection, OnItemSelectedListener onItemSelectedListener) {
|
||||
this.spinnerLabelResourceId = spinnerLabelResourceId;
|
||||
this.spinnerAdapter = spinnerAdapter;
|
||||
this.initialSelection = initialSelection;
|
||||
this.onItemSelectedListener = onItemSelectedListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) {
|
||||
return new SpinnerViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.layout_spinner, parent, false));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, RecyclerView.Adapter<RecyclerView.ViewHolder> adapter) {
|
||||
SpinnerViewHolder spinnerViewHolder = (SpinnerViewHolder) viewHolder;
|
||||
spinnerViewHolder.text.setText(spinnerLabelResourceId);
|
||||
spinnerViewHolder.spinner.setAdapter(spinnerAdapter);
|
||||
spinnerViewHolder.spinner.setSelection(initialSelection);
|
||||
spinnerViewHolder.spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
@Override
|
||||
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {
|
||||
if (onItemSelectedListener != null)
|
||||
onItemSelectedListener.onItemSelected(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> adapterView) {
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".AudioSettingsFragment">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/audio_settings_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:orientation="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,16 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".GraphicsSettingsFragment">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/graphics_settings_recycler_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="8dp"
|
||||
android:orientation="vertical"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />
|
||||
</FrameLayout>
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user