mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2024-11-30 01:25:51 +00:00
Android: New/improved ingame pause menu
This commit is contained in:
parent
19b84cbe4d
commit
70aae89219
|
@ -47,7 +47,7 @@ static jclass s_EmulationActivity_class;
|
|||
static jmethodID s_EmulationActivity_method_reportError;
|
||||
static jmethodID s_EmulationActivity_method_onEmulationStarted;
|
||||
static jmethodID s_EmulationActivity_method_onEmulationStopped;
|
||||
static jmethodID s_EmulationActivity_method_onGameTitleChanged;
|
||||
static jmethodID s_EmulationActivity_method_onRunningGameChanged;
|
||||
static jmethodID s_EmulationActivity_method_setVibration;
|
||||
static jmethodID s_EmulationActivity_method_getRefreshRate;
|
||||
static jmethodID s_EmulationActivity_method_openPauseMenu;
|
||||
|
@ -703,9 +703,29 @@ void AndroidHostInterface::OnRunningGameChanged(const std::string& path, CDImage
|
|||
if (m_emulation_activity_object)
|
||||
{
|
||||
JNIEnv* env = AndroidHelpers::GetJNIEnv();
|
||||
jstring title_string = env->NewStringUTF(System::GetRunningTitle().c_str());
|
||||
env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onGameTitleChanged, title_string);
|
||||
|
||||
jstring path_string = env->NewStringUTF(path.c_str());
|
||||
jstring code_string = env->NewStringUTF(game_code.c_str());
|
||||
jstring title_string = env->NewStringUTF(game_title.c_str());
|
||||
|
||||
const GameListEntry* game_list_entry = m_game_list->GetEntryForPath(path.c_str());
|
||||
std::string cover_path_str;
|
||||
if (game_list_entry)
|
||||
cover_path_str = m_game_list->GetCoverImagePathForEntry(game_list_entry);
|
||||
else
|
||||
cover_path_str = m_game_list->GetCoverImagePath(path, game_code, game_title);
|
||||
|
||||
jstring cover_path = nullptr;
|
||||
if (!cover_path_str.empty())
|
||||
cover_path = env->NewStringUTF(cover_path_str.c_str());
|
||||
|
||||
env->CallVoidMethod(m_emulation_activity_object, s_EmulationActivity_method_onRunningGameChanged, path_string, code_string, title_string, cover_path);
|
||||
|
||||
if (cover_path)
|
||||
env->DeleteLocalRef(cover_path);
|
||||
env->DeleteLocalRef(title_string);
|
||||
env->DeleteLocalRef(code_string);
|
||||
env->DeleteLocalRef(path_string);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -994,8 +1014,8 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
|
|||
env->GetMethodID(s_EmulationActivity_class, "onEmulationStarted", "()V")) == nullptr ||
|
||||
(s_EmulationActivity_method_onEmulationStopped =
|
||||
env->GetMethodID(s_EmulationActivity_class, "onEmulationStopped", "()V")) == nullptr ||
|
||||
(s_EmulationActivity_method_onGameTitleChanged =
|
||||
env->GetMethodID(s_EmulationActivity_class, "onGameTitleChanged", "(Ljava/lang/String;)V")) == nullptr ||
|
||||
(s_EmulationActivity_method_onRunningGameChanged =
|
||||
env->GetMethodID(s_EmulationActivity_class, "onRunningGameChanged", "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V")) == nullptr ||
|
||||
(s_EmulationActivity_method_setVibration = env->GetMethodID(emulation_activity_class, "setVibration", "(Z)V")) ==
|
||||
nullptr ||
|
||||
(s_EmulationActivity_method_getRefreshRate =
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package com.github.stenzek.duckstation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Vibrator;
|
||||
import android.text.InputType;
|
||||
|
@ -20,8 +21,8 @@ public class ControllerAutoMapper {
|
|||
public void onComplete();
|
||||
}
|
||||
|
||||
final private ControllerSettingsActivity parent;
|
||||
final private int port;
|
||||
private final Context context;
|
||||
private final int port;
|
||||
private final CompleteCallback completeCallback;
|
||||
|
||||
private InputDevice device;
|
||||
|
@ -31,8 +32,8 @@ public class ControllerAutoMapper {
|
|||
private String keyBase;
|
||||
private String controllerType;
|
||||
|
||||
public ControllerAutoMapper(ControllerSettingsActivity activity, int port, CompleteCallback completeCallback) {
|
||||
this.parent = activity;
|
||||
public ControllerAutoMapper(Context context, int port, CompleteCallback completeCallback) {
|
||||
this.context = context;
|
||||
this.port = port;
|
||||
this.completeCallback = completeCallback;
|
||||
}
|
||||
|
@ -126,7 +127,7 @@ public class ControllerAutoMapper {
|
|||
}
|
||||
|
||||
if (deviceList.isEmpty()) {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(parent);
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.main_activity_error);
|
||||
builder.setMessage(R.string.controller_auto_mapping_no_devices);
|
||||
builder.setPositiveButton(R.string.main_activity_ok, (dialog, which) -> dialog.dismiss());
|
||||
|
@ -138,7 +139,7 @@ public class ControllerAutoMapper {
|
|||
for (int i = 0; i < deviceList.size(); i++)
|
||||
deviceNames[i] = deviceList.get(i).getName();
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(parent);
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.controller_auto_mapping_select_device);
|
||||
builder.setItems(deviceNames, (dialog, which) -> {
|
||||
process(deviceList.get(which));
|
||||
|
@ -147,13 +148,13 @@ public class ControllerAutoMapper {
|
|||
}
|
||||
|
||||
private void process(InputDevice device) {
|
||||
this.prefs = PreferenceManager.getDefaultSharedPreferences(parent);
|
||||
this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||
this.editor = prefs.edit();
|
||||
this.log = new StringBuilder();
|
||||
this.device = device;
|
||||
|
||||
this.keyBase = String.format("Controller%d/", port);
|
||||
this.controllerType = parent.getControllerType(prefs, port);
|
||||
this.controllerType = ControllerSettingsCollectionFragment.getControllerType(prefs, port);
|
||||
|
||||
setButtonBindings();
|
||||
setAxisBindings();
|
||||
|
@ -162,10 +163,10 @@ public class ControllerAutoMapper {
|
|||
this.editor.commit();
|
||||
this.editor = null;
|
||||
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(parent);
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
|
||||
builder.setTitle(R.string.controller_auto_mapping_results);
|
||||
|
||||
final EditText editText = new EditText(parent);
|
||||
final EditText editText = new EditText(context);
|
||||
editText.setText(log.toString());
|
||||
editText.setInputType(InputType.TYPE_NULL | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
||||
editText.setSingleLine(false);
|
||||
|
|
|
@ -2,50 +2,33 @@ package com.github.stenzek.duckstation;
|
|||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreferenceCompat;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ControllerSettingsActivity extends AppCompatActivity {
|
||||
|
||||
private static final int NUM_CONTROLLER_PORTS = 2;
|
||||
public static final String MULTITAP_MODE_SETTINGS_KEY = "ControllerPorts/MultitapMode";
|
||||
|
||||
private ArrayList<ControllerBindingPreference> mPreferences = new ArrayList<>();
|
||||
private ControllerSettingsCollectionFragment fragment;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(R.layout.settings_activity);
|
||||
|
||||
fragment = new ControllerSettingsCollectionFragment();
|
||||
fragment.setMultitapModeChangedListener(this::recreate);
|
||||
|
||||
getSupportFragmentManager()
|
||||
.beginTransaction()
|
||||
.replace(R.id.settings, new SettingsCollectionFragment(this))
|
||||
.replace(R.id.settings, fragment)
|
||||
.commit();
|
||||
ActionBar actionBar = getSupportActionBar();
|
||||
if (actionBar != null) {
|
||||
|
@ -84,7 +67,7 @@ public class ControllerSettingsActivity extends AppCompatActivity {
|
|||
doSaveProfile();
|
||||
return true;
|
||||
} else if (id == R.id.action_clear_bindings) {
|
||||
doClearBindings();
|
||||
fragment.clearAllBindings();
|
||||
return true;
|
||||
} else {
|
||||
return super.onOptionsItemSelected(item);
|
||||
|
@ -124,7 +107,7 @@ public class ControllerSettingsActivity extends AppCompatActivity {
|
|||
return;
|
||||
}
|
||||
|
||||
updateAllBindings();
|
||||
fragment.updateAllBindings();
|
||||
}
|
||||
|
||||
private void doSaveProfile() {
|
||||
|
@ -151,355 +134,5 @@ public class ControllerSettingsActivity extends AppCompatActivity {
|
|||
builder.create().show();
|
||||
}
|
||||
|
||||
private void doClearBindings() {
|
||||
SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(this).edit();
|
||||
for (ControllerBindingPreference pref : mPreferences)
|
||||
pref.clearBinding(prefEdit);
|
||||
prefEdit.commit();
|
||||
}
|
||||
|
||||
private void updateAllBindings() {
|
||||
for (ControllerBindingPreference pref : mPreferences)
|
||||
pref.updateValue();
|
||||
}
|
||||
|
||||
public static String getControllerTypeKey(int port) {
|
||||
return String.format("Controller%d/Type", port);
|
||||
}
|
||||
|
||||
public static String getControllerType(SharedPreferences prefs, int port) {
|
||||
final String defaultControllerType = (port == 1) ? "DigitalController" : "None";
|
||||
return prefs.getString(getControllerTypeKey(port), defaultControllerType);
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragmentCompat {
|
||||
ControllerSettingsActivity parent;
|
||||
|
||||
public SettingsFragment(ControllerSettingsActivity parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.controllers_preferences, rootKey);
|
||||
|
||||
final Preference multitapModePreference = getPreferenceScreen().findPreference(MULTITAP_MODE_SETTINGS_KEY);
|
||||
if (multitapModePreference != null) {
|
||||
multitapModePreference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
parent.recreate();
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ControllerPortFragment extends PreferenceFragmentCompat {
|
||||
private ControllerSettingsActivity activity;
|
||||
private int controllerIndex;
|
||||
private PreferenceCategory mButtonsCategory;
|
||||
private PreferenceCategory mAxisCategory;
|
||||
private PreferenceCategory mSettingsCategory;
|
||||
|
||||
public ControllerPortFragment(ControllerSettingsActivity activity, int controllerIndex) {
|
||||
this.activity = activity;
|
||||
this.controllerIndex = controllerIndex;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
final PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(getContext());
|
||||
setPreferenceScreen(ps);
|
||||
createPreferences();
|
||||
}
|
||||
|
||||
private SwitchPreferenceCompat createTogglePreference(String key, int title, int summary, boolean defaultValue) {
|
||||
final SwitchPreferenceCompat pref = new SwitchPreferenceCompat(getContext());
|
||||
pref.setKey(key);
|
||||
pref.setTitle(title);
|
||||
pref.setSummary(summary);
|
||||
pref.setIconSpaceReserved(false);
|
||||
pref.setDefaultValue(defaultValue);
|
||||
return pref;
|
||||
}
|
||||
|
||||
private void createPreferences() {
|
||||
final PreferenceScreen ps = getPreferenceScreen();
|
||||
final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
|
||||
final String controllerType = getControllerType(sp, controllerIndex);
|
||||
final String[] controllerButtons = AndroidHostInterface.getControllerButtonNames(controllerType);
|
||||
final String[] axisButtons = AndroidHostInterface.getControllerAxisNames(controllerType);
|
||||
final int vibrationMotors = AndroidHostInterface.getControllerVibrationMotorCount(controllerType);
|
||||
|
||||
final ListPreference typePreference = new ListPreference(getContext());
|
||||
typePreference.setEntries(R.array.settings_controller_type_entries);
|
||||
typePreference.setEntryValues(R.array.settings_controller_type_values);
|
||||
typePreference.setKey(getControllerTypeKey(controllerIndex));
|
||||
typePreference.setValue(controllerType);
|
||||
typePreference.setTitle(R.string.settings_controller_type);
|
||||
typePreference.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance());
|
||||
typePreference.setIconSpaceReserved(false);
|
||||
typePreference.setOnPreferenceChangeListener((pref, value) -> {
|
||||
removePreferences();
|
||||
createPreferences(value.toString());
|
||||
return true;
|
||||
});
|
||||
ps.addPreference(typePreference);
|
||||
|
||||
final Preference autoBindPreference = new Preference(getContext());
|
||||
autoBindPreference.setTitle(R.string.controller_settings_automatic_mapping);
|
||||
autoBindPreference.setSummary(R.string.controller_settings_summary_automatic_mapping);
|
||||
autoBindPreference.setIconSpaceReserved(false);
|
||||
autoBindPreference.setOnPreferenceClickListener(preference -> {
|
||||
final ControllerAutoMapper mapper = new ControllerAutoMapper(activity, controllerIndex, () -> {
|
||||
removePreferences();
|
||||
createPreferences(typePreference.getValue());
|
||||
});
|
||||
mapper.start();
|
||||
return true;
|
||||
});
|
||||
ps.addPreference(autoBindPreference);
|
||||
|
||||
final Preference clearBindingsPreference = new Preference(getContext());
|
||||
clearBindingsPreference.setTitle(R.string.controller_settings_clear_controller_bindings);
|
||||
clearBindingsPreference.setSummary(R.string.controller_settings_summary_clear_controller_bindings);
|
||||
clearBindingsPreference.setIconSpaceReserved(false);
|
||||
clearBindingsPreference.setOnPreferenceClickListener(preference -> {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(activity);
|
||||
builder.setMessage(R.string.controller_settings_clear_controller_bindings_confirm);
|
||||
builder.setPositiveButton(R.string.main_activity_yes, (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
clearBindings();
|
||||
});
|
||||
builder.setNegativeButton(R.string.main_activity_no, (dialog, which) -> dialog.dismiss());
|
||||
builder.create().show();
|
||||
return true;
|
||||
});
|
||||
ps.addPreference(clearBindingsPreference);
|
||||
|
||||
mButtonsCategory = new PreferenceCategory(getContext());
|
||||
mButtonsCategory.setTitle(getContext().getString(R.string.controller_settings_category_button_bindings));
|
||||
mButtonsCategory.setIconSpaceReserved(false);
|
||||
ps.addPreference(mButtonsCategory);
|
||||
|
||||
mAxisCategory = new PreferenceCategory(getContext());
|
||||
mAxisCategory.setTitle(getContext().getString(R.string.controller_settings_category_axis_bindings));
|
||||
mAxisCategory.setIconSpaceReserved(false);
|
||||
ps.addPreference(mAxisCategory);
|
||||
|
||||
mSettingsCategory = new PreferenceCategory(getContext());
|
||||
mSettingsCategory.setTitle(getContext().getString(R.string.controller_settings_category_settings));
|
||||
mSettingsCategory.setIconSpaceReserved(false);
|
||||
ps.addPreference(mSettingsCategory);
|
||||
|
||||
createPreferences(controllerType);
|
||||
}
|
||||
|
||||
private void createPreferences(String controllerType) {
|
||||
final PreferenceScreen ps = getPreferenceScreen();
|
||||
final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
|
||||
final String[] buttonNames = AndroidHostInterface.getControllerButtonNames(controllerType);
|
||||
final String[] axisNames = AndroidHostInterface.getControllerAxisNames(controllerType);
|
||||
final int vibrationMotors = AndroidHostInterface.getControllerVibrationMotorCount(controllerType);
|
||||
|
||||
if (buttonNames != null) {
|
||||
for (String buttonName : buttonNames) {
|
||||
final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
|
||||
cbp.initButton(controllerIndex, buttonName);
|
||||
mButtonsCategory.addPreference(cbp);
|
||||
activity.mPreferences.add(cbp);
|
||||
}
|
||||
}
|
||||
|
||||
if (axisNames != null) {
|
||||
for (String axisName : axisNames) {
|
||||
final int axisType = AndroidHostInterface.getControllerAxisType(controllerType, axisName);
|
||||
final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
|
||||
cbp.initAxis(controllerIndex, axisName, axisType);
|
||||
mAxisCategory.addPreference(cbp);
|
||||
activity.mPreferences.add(cbp);
|
||||
}
|
||||
}
|
||||
|
||||
if (vibrationMotors > 0) {
|
||||
final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
|
||||
cbp.initVibration(controllerIndex);
|
||||
mSettingsCategory.addPreference(cbp);
|
||||
activity.mPreferences.add(cbp);
|
||||
}
|
||||
|
||||
if (controllerType.equals("AnalogController")) {
|
||||
mSettingsCategory.addPreference(
|
||||
createTogglePreference(String.format("Controller%d/ForceAnalogOnReset", controllerIndex),
|
||||
R.string.settings_enable_analog_mode_on_reset, R.string.settings_summary_enable_analog_mode_on_reset, true));
|
||||
|
||||
mSettingsCategory.addPreference(
|
||||
createTogglePreference(String.format("Controller%d/AnalogDPadInDigitalMode", controllerIndex),
|
||||
R.string.settings_use_analog_sticks_for_dpad, R.string.settings_summary_use_analog_sticks_for_dpad, true));
|
||||
}
|
||||
}
|
||||
|
||||
private void removePreferences() {
|
||||
for (int i = 0; i < mButtonsCategory.getPreferenceCount(); i++) {
|
||||
activity.mPreferences.remove(mButtonsCategory.getPreference(i));
|
||||
}
|
||||
mButtonsCategory.removeAll();
|
||||
|
||||
for (int i = 0; i < mAxisCategory.getPreferenceCount(); i++) {
|
||||
activity.mPreferences.remove(mAxisCategory.getPreference(i));
|
||||
}
|
||||
mAxisCategory.removeAll();
|
||||
|
||||
for (int i = 0; i < mSettingsCategory.getPreferenceCount(); i++) {
|
||||
activity.mPreferences.remove(mSettingsCategory.getPreference(i));
|
||||
}
|
||||
mSettingsCategory.removeAll();
|
||||
}
|
||||
|
||||
private static void clearBindingsInCategory(SharedPreferences.Editor editor, PreferenceCategory category) {
|
||||
for (int i = 0; i < category.getPreferenceCount(); i++) {
|
||||
final Preference preference = category.getPreference(i);
|
||||
if (preference instanceof ControllerBindingPreference)
|
||||
((ControllerBindingPreference)preference).clearBinding(editor);
|
||||
}
|
||||
}
|
||||
|
||||
private void clearBindings() {
|
||||
final SharedPreferences.Editor editor = getPreferenceManager().getSharedPreferences().edit();
|
||||
clearBindingsInCategory(editor, mButtonsCategory);
|
||||
clearBindingsInCategory(editor, mAxisCategory);
|
||||
clearBindingsInCategory(editor, mSettingsCategory);
|
||||
editor.commit();
|
||||
|
||||
Toast.makeText(activity, activity.getString(
|
||||
R.string.controller_settings_clear_controller_bindings_done, controllerIndex),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
public static class HotkeyFragment extends PreferenceFragmentCompat {
|
||||
private ControllerSettingsActivity activity;
|
||||
private HotkeyInfo[] mHotkeyInfo;
|
||||
|
||||
public HotkeyFragment(ControllerSettingsActivity activity) {
|
||||
this.activity = activity;
|
||||
this.mHotkeyInfo = AndroidHostInterface.getInstance().getHotkeyInfoList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
final PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(getContext());
|
||||
if (mHotkeyInfo != null) {
|
||||
final HashMap<String, PreferenceCategory> categoryMap = new HashMap<>();
|
||||
|
||||
for (HotkeyInfo hotkeyInfo : mHotkeyInfo) {
|
||||
PreferenceCategory category = categoryMap.containsKey(hotkeyInfo.getCategory()) ?
|
||||
categoryMap.get(hotkeyInfo.getCategory()) : null;
|
||||
if (category == null) {
|
||||
category = new PreferenceCategory(getContext());
|
||||
category.setTitle(hotkeyInfo.getCategory());
|
||||
category.setIconSpaceReserved(false);
|
||||
categoryMap.put(hotkeyInfo.getCategory(), category);
|
||||
ps.addPreference(category);
|
||||
}
|
||||
|
||||
final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
|
||||
cbp.initHotkey(hotkeyInfo);
|
||||
category.addPreference(cbp);
|
||||
activity.mPreferences.add(cbp);
|
||||
}
|
||||
}
|
||||
|
||||
setPreferenceScreen(ps);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsCollectionFragment extends Fragment {
|
||||
private ControllerSettingsActivity activity;
|
||||
private SettingsCollectionAdapter adapter;
|
||||
private ViewPager2 viewPager;
|
||||
private String[] controllerPortNames;
|
||||
|
||||
private static final int NUM_MAIN_CONTROLLER_PORTS = 2;
|
||||
private static final int NUM_SUB_CONTROLLER_PORTS = 4;
|
||||
private static final char[] SUB_CONTROLLER_PORT_NAMES = new char[] {'A', 'B', 'C', 'D'};
|
||||
|
||||
public SettingsCollectionFragment(ControllerSettingsActivity activity) {
|
||||
this.activity = activity;
|
||||
|
||||
final String multitapMode = PreferenceManager.getDefaultSharedPreferences(activity).getString(
|
||||
MULTITAP_MODE_SETTINGS_KEY, "Disabled");
|
||||
|
||||
final ArrayList<String> portNames = new ArrayList<>();
|
||||
for (int i = 0; i < NUM_MAIN_CONTROLLER_PORTS; i++) {
|
||||
final boolean isMultitap = (multitapMode.equals("BothPorts") ||
|
||||
(i == 0 && multitapMode.equals("Port1Only")) ||
|
||||
(i == 1 && multitapMode.equals("Port2Only")));
|
||||
|
||||
if (isMultitap) {
|
||||
for (int j = 0; j < NUM_SUB_CONTROLLER_PORTS; j++) {
|
||||
portNames.add(activity.getString(
|
||||
R.string.controller_settings_sub_port_format,
|
||||
i + 1, SUB_CONTROLLER_PORT_NAMES[j]));
|
||||
}
|
||||
} else {
|
||||
portNames.add(activity.getString(
|
||||
R.string.controller_settings_main_port_format,
|
||||
i + 1));
|
||||
}
|
||||
}
|
||||
|
||||
controllerPortNames = new String[portNames.size()];
|
||||
portNames.toArray(controllerPortNames);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_controller_settings, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
adapter = new SettingsCollectionAdapter(activity, this, controllerPortNames.length);
|
||||
viewPager = view.findViewById(R.id.view_pager);
|
||||
viewPager.setAdapter(adapter);
|
||||
|
||||
TabLayout tabLayout = view.findViewById(R.id.tab_layout);
|
||||
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
|
||||
if (position == 0)
|
||||
tab.setText(R.string.controller_settings_tab_settings);
|
||||
else if (position <= controllerPortNames.length)
|
||||
tab.setText(controllerPortNames[position - 1]);
|
||||
else
|
||||
tab.setText(R.string.controller_settings_tab_hotkeys);
|
||||
}).attach();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsCollectionAdapter extends FragmentStateAdapter {
|
||||
private ControllerSettingsActivity activity;
|
||||
private int controllerPorts;
|
||||
|
||||
public SettingsCollectionAdapter(@NonNull ControllerSettingsActivity activity, @NonNull Fragment fragment, int controllerPorts) {
|
||||
super(fragment);
|
||||
this.activity = activity;
|
||||
this.controllerPorts = controllerPorts;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
if (position == 0)
|
||||
return new SettingsFragment(activity);
|
||||
else if (position <= controllerPorts)
|
||||
return new ControllerPortFragment(activity, position);
|
||||
else
|
||||
return new HotkeyFragment(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return controllerPorts + 2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,393 @@
|
|||
package com.github.stenzek.duckstation;
|
||||
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.ListPreference;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceCategory;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
import androidx.preference.PreferenceScreen;
|
||||
import androidx.preference.SwitchPreferenceCompat;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ControllerSettingsCollectionFragment extends Fragment {
|
||||
public static final String MULTITAP_MODE_SETTINGS_KEY = "ControllerPorts/MultitapMode";
|
||||
private static final int NUM_MAIN_CONTROLLER_PORTS = 2;
|
||||
private static final int NUM_SUB_CONTROLLER_PORTS = 4;
|
||||
private static final char[] SUB_CONTROLLER_PORT_NAMES = new char[]{'A', 'B', 'C', 'D'};
|
||||
|
||||
public interface MultitapModeChangedListener {
|
||||
void onChanged();
|
||||
}
|
||||
|
||||
private final ArrayList<ControllerBindingPreference> preferences = new ArrayList<>();
|
||||
private SettingsCollectionAdapter adapter;
|
||||
private ViewPager2 viewPager;
|
||||
private String[] controllerPortNames;
|
||||
|
||||
private MultitapModeChangedListener multitapModeChangedListener;
|
||||
|
||||
public ControllerSettingsCollectionFragment() {
|
||||
}
|
||||
|
||||
public static String getControllerTypeKey(int port) {
|
||||
return String.format("Controller%d/Type", port);
|
||||
}
|
||||
|
||||
public static String getControllerType(SharedPreferences prefs, int port) {
|
||||
final String defaultControllerType = (port == 1) ? "DigitalController" : "None";
|
||||
return prefs.getString(getControllerTypeKey(port), defaultControllerType);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_controller_settings, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
final String multitapMode = PreferenceManager.getDefaultSharedPreferences(getContext()).getString(
|
||||
MULTITAP_MODE_SETTINGS_KEY, "Disabled");
|
||||
|
||||
final ArrayList<String> portNames = new ArrayList<>();
|
||||
for (int i = 0; i < NUM_MAIN_CONTROLLER_PORTS; i++) {
|
||||
final boolean isMultitap = (multitapMode.equals("BothPorts") ||
|
||||
(i == 0 && multitapMode.equals("Port1Only")) ||
|
||||
(i == 1 && multitapMode.equals("Port2Only")));
|
||||
|
||||
if (isMultitap) {
|
||||
for (int j = 0; j < NUM_SUB_CONTROLLER_PORTS; j++) {
|
||||
portNames.add(getContext().getString(
|
||||
R.string.controller_settings_sub_port_format,
|
||||
i + 1, SUB_CONTROLLER_PORT_NAMES[j]));
|
||||
}
|
||||
} else {
|
||||
portNames.add(getContext().getString(
|
||||
R.string.controller_settings_main_port_format,
|
||||
i + 1));
|
||||
}
|
||||
}
|
||||
|
||||
controllerPortNames = new String[portNames.size()];
|
||||
portNames.toArray(controllerPortNames);
|
||||
|
||||
adapter = new SettingsCollectionAdapter(this, controllerPortNames.length);
|
||||
viewPager = view.findViewById(R.id.view_pager);
|
||||
viewPager.setAdapter(adapter);
|
||||
|
||||
TabLayout tabLayout = view.findViewById(R.id.tab_layout);
|
||||
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
|
||||
if (position == 0)
|
||||
tab.setText(R.string.controller_settings_tab_settings);
|
||||
else if (position <= controllerPortNames.length)
|
||||
tab.setText(controllerPortNames[position - 1]);
|
||||
else
|
||||
tab.setText(R.string.controller_settings_tab_hotkeys);
|
||||
}).attach();
|
||||
}
|
||||
|
||||
public void setMultitapModeChangedListener(MultitapModeChangedListener multitapModeChangedListener) {
|
||||
this.multitapModeChangedListener = multitapModeChangedListener;
|
||||
}
|
||||
|
||||
public void clearAllBindings() {
|
||||
SharedPreferences.Editor prefEdit = PreferenceManager.getDefaultSharedPreferences(getContext()).edit();
|
||||
for (ControllerBindingPreference pref : preferences)
|
||||
pref.clearBinding(prefEdit);
|
||||
prefEdit.commit();
|
||||
}
|
||||
|
||||
public void updateAllBindings() {
|
||||
for (ControllerBindingPreference pref : preferences)
|
||||
pref.updateValue();
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragmentCompat {
|
||||
private final ControllerSettingsCollectionFragment parent;
|
||||
|
||||
public SettingsFragment(ControllerSettingsCollectionFragment parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(R.xml.controllers_preferences, rootKey);
|
||||
|
||||
final Preference multitapModePreference = getPreferenceScreen().findPreference(MULTITAP_MODE_SETTINGS_KEY);
|
||||
if (multitapModePreference != null) {
|
||||
multitapModePreference.setOnPreferenceChangeListener((pref, newValue) -> {
|
||||
if (parent.multitapModeChangedListener != null)
|
||||
parent.multitapModeChangedListener.onChanged();
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ControllerPortFragment extends PreferenceFragmentCompat {
|
||||
private final ControllerSettingsCollectionFragment parent;
|
||||
private final int controllerIndex;
|
||||
private PreferenceCategory mButtonsCategory;
|
||||
private PreferenceCategory mAxisCategory;
|
||||
private PreferenceCategory mSettingsCategory;
|
||||
|
||||
public ControllerPortFragment(ControllerSettingsCollectionFragment parent, int controllerIndex) {
|
||||
this.parent = parent;
|
||||
this.controllerIndex = controllerIndex;
|
||||
}
|
||||
|
||||
private static void clearBindingsInCategory(SharedPreferences.Editor editor, PreferenceCategory category) {
|
||||
for (int i = 0; i < category.getPreferenceCount(); i++) {
|
||||
final Preference preference = category.getPreference(i);
|
||||
if (preference instanceof ControllerBindingPreference)
|
||||
((ControllerBindingPreference) preference).clearBinding(editor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
final PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(getContext());
|
||||
setPreferenceScreen(ps);
|
||||
createPreferences();
|
||||
}
|
||||
|
||||
private SwitchPreferenceCompat createTogglePreference(String key, int title, int summary, boolean defaultValue) {
|
||||
final SwitchPreferenceCompat pref = new SwitchPreferenceCompat(getContext());
|
||||
pref.setKey(key);
|
||||
pref.setTitle(title);
|
||||
pref.setSummary(summary);
|
||||
pref.setIconSpaceReserved(false);
|
||||
pref.setDefaultValue(defaultValue);
|
||||
return pref;
|
||||
}
|
||||
|
||||
private void createPreferences() {
|
||||
final PreferenceScreen ps = getPreferenceScreen();
|
||||
final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
|
||||
final String controllerType = getControllerType(sp, controllerIndex);
|
||||
final String[] controllerButtons = AndroidHostInterface.getControllerButtonNames(controllerType);
|
||||
final String[] axisButtons = AndroidHostInterface.getControllerAxisNames(controllerType);
|
||||
final int vibrationMotors = AndroidHostInterface.getControllerVibrationMotorCount(controllerType);
|
||||
|
||||
final ListPreference typePreference = new ListPreference(getContext());
|
||||
typePreference.setEntries(R.array.settings_controller_type_entries);
|
||||
typePreference.setEntryValues(R.array.settings_controller_type_values);
|
||||
typePreference.setKey(getControllerTypeKey(controllerIndex));
|
||||
typePreference.setValue(controllerType);
|
||||
typePreference.setTitle(R.string.settings_controller_type);
|
||||
typePreference.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance());
|
||||
typePreference.setIconSpaceReserved(false);
|
||||
typePreference.setOnPreferenceChangeListener((pref, value) -> {
|
||||
removePreferences();
|
||||
createPreferences(value.toString());
|
||||
return true;
|
||||
});
|
||||
ps.addPreference(typePreference);
|
||||
|
||||
final Preference autoBindPreference = new Preference(getContext());
|
||||
autoBindPreference.setTitle(R.string.controller_settings_automatic_mapping);
|
||||
autoBindPreference.setSummary(R.string.controller_settings_summary_automatic_mapping);
|
||||
autoBindPreference.setIconSpaceReserved(false);
|
||||
autoBindPreference.setOnPreferenceClickListener(preference -> {
|
||||
final ControllerAutoMapper mapper = new ControllerAutoMapper(getContext(), controllerIndex, () -> {
|
||||
removePreferences();
|
||||
createPreferences(typePreference.getValue());
|
||||
});
|
||||
mapper.start();
|
||||
return true;
|
||||
});
|
||||
ps.addPreference(autoBindPreference);
|
||||
|
||||
final Preference clearBindingsPreference = new Preference(getContext());
|
||||
clearBindingsPreference.setTitle(R.string.controller_settings_clear_controller_bindings);
|
||||
clearBindingsPreference.setSummary(R.string.controller_settings_summary_clear_controller_bindings);
|
||||
clearBindingsPreference.setIconSpaceReserved(false);
|
||||
clearBindingsPreference.setOnPreferenceClickListener(preference -> {
|
||||
final AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
builder.setMessage(R.string.controller_settings_clear_controller_bindings_confirm);
|
||||
builder.setPositiveButton(R.string.main_activity_yes, (dialog, which) -> {
|
||||
dialog.dismiss();
|
||||
clearBindings();
|
||||
});
|
||||
builder.setNegativeButton(R.string.main_activity_no, (dialog, which) -> dialog.dismiss());
|
||||
builder.create().show();
|
||||
return true;
|
||||
});
|
||||
ps.addPreference(clearBindingsPreference);
|
||||
|
||||
mButtonsCategory = new PreferenceCategory(getContext());
|
||||
mButtonsCategory.setTitle(getContext().getString(R.string.controller_settings_category_button_bindings));
|
||||
mButtonsCategory.setIconSpaceReserved(false);
|
||||
ps.addPreference(mButtonsCategory);
|
||||
|
||||
mAxisCategory = new PreferenceCategory(getContext());
|
||||
mAxisCategory.setTitle(getContext().getString(R.string.controller_settings_category_axis_bindings));
|
||||
mAxisCategory.setIconSpaceReserved(false);
|
||||
ps.addPreference(mAxisCategory);
|
||||
|
||||
mSettingsCategory = new PreferenceCategory(getContext());
|
||||
mSettingsCategory.setTitle(getContext().getString(R.string.controller_settings_category_settings));
|
||||
mSettingsCategory.setIconSpaceReserved(false);
|
||||
ps.addPreference(mSettingsCategory);
|
||||
|
||||
createPreferences(controllerType);
|
||||
}
|
||||
|
||||
private void createPreferences(String controllerType) {
|
||||
final PreferenceScreen ps = getPreferenceScreen();
|
||||
final SharedPreferences sp = getPreferenceManager().getSharedPreferences();
|
||||
final String[] buttonNames = AndroidHostInterface.getControllerButtonNames(controllerType);
|
||||
final String[] axisNames = AndroidHostInterface.getControllerAxisNames(controllerType);
|
||||
final int vibrationMotors = AndroidHostInterface.getControllerVibrationMotorCount(controllerType);
|
||||
|
||||
if (buttonNames != null) {
|
||||
for (String buttonName : buttonNames) {
|
||||
final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
|
||||
cbp.initButton(controllerIndex, buttonName);
|
||||
mButtonsCategory.addPreference(cbp);
|
||||
parent.preferences.add(cbp);
|
||||
}
|
||||
}
|
||||
|
||||
if (axisNames != null) {
|
||||
for (String axisName : axisNames) {
|
||||
final int axisType = AndroidHostInterface.getControllerAxisType(controllerType, axisName);
|
||||
final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
|
||||
cbp.initAxis(controllerIndex, axisName, axisType);
|
||||
mAxisCategory.addPreference(cbp);
|
||||
parent.preferences.add(cbp);
|
||||
}
|
||||
}
|
||||
|
||||
if (vibrationMotors > 0) {
|
||||
final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
|
||||
cbp.initVibration(controllerIndex);
|
||||
mSettingsCategory.addPreference(cbp);
|
||||
parent.preferences.add(cbp);
|
||||
}
|
||||
|
||||
if (controllerType.equals("AnalogController")) {
|
||||
mSettingsCategory.addPreference(
|
||||
createTogglePreference(String.format("Controller%d/ForceAnalogOnReset", controllerIndex),
|
||||
R.string.settings_enable_analog_mode_on_reset, R.string.settings_summary_enable_analog_mode_on_reset, true));
|
||||
|
||||
mSettingsCategory.addPreference(
|
||||
createTogglePreference(String.format("Controller%d/AnalogDPadInDigitalMode", controllerIndex),
|
||||
R.string.settings_use_analog_sticks_for_dpad, R.string.settings_summary_use_analog_sticks_for_dpad, true));
|
||||
}
|
||||
}
|
||||
|
||||
private void removePreferences() {
|
||||
for (int i = 0; i < mButtonsCategory.getPreferenceCount(); i++) {
|
||||
parent.preferences.remove(mButtonsCategory.getPreference(i));
|
||||
}
|
||||
mButtonsCategory.removeAll();
|
||||
|
||||
for (int i = 0; i < mAxisCategory.getPreferenceCount(); i++) {
|
||||
parent.preferences.remove(mAxisCategory.getPreference(i));
|
||||
}
|
||||
mAxisCategory.removeAll();
|
||||
|
||||
for (int i = 0; i < mSettingsCategory.getPreferenceCount(); i++) {
|
||||
parent.preferences.remove(mSettingsCategory.getPreference(i));
|
||||
}
|
||||
mSettingsCategory.removeAll();
|
||||
}
|
||||
|
||||
private void clearBindings() {
|
||||
final SharedPreferences.Editor editor = getPreferenceManager().getSharedPreferences().edit();
|
||||
clearBindingsInCategory(editor, mButtonsCategory);
|
||||
clearBindingsInCategory(editor, mAxisCategory);
|
||||
clearBindingsInCategory(editor, mSettingsCategory);
|
||||
editor.commit();
|
||||
|
||||
Toast.makeText(parent.getContext(), parent.getString(
|
||||
R.string.controller_settings_clear_controller_bindings_done, controllerIndex),
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
public static class HotkeyFragment extends PreferenceFragmentCompat {
|
||||
private final ControllerSettingsCollectionFragment parent;
|
||||
private final HotkeyInfo[] mHotkeyInfo;
|
||||
|
||||
public HotkeyFragment(ControllerSettingsCollectionFragment parent) {
|
||||
this.parent = parent;
|
||||
this.mHotkeyInfo = AndroidHostInterface.getInstance().getHotkeyInfoList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
final PreferenceScreen ps = getPreferenceManager().createPreferenceScreen(getContext());
|
||||
if (mHotkeyInfo != null) {
|
||||
final HashMap<String, PreferenceCategory> categoryMap = new HashMap<>();
|
||||
|
||||
for (HotkeyInfo hotkeyInfo : mHotkeyInfo) {
|
||||
PreferenceCategory category = categoryMap.containsKey(hotkeyInfo.getCategory()) ?
|
||||
categoryMap.get(hotkeyInfo.getCategory()) : null;
|
||||
if (category == null) {
|
||||
category = new PreferenceCategory(getContext());
|
||||
category.setTitle(hotkeyInfo.getCategory());
|
||||
category.setIconSpaceReserved(false);
|
||||
categoryMap.put(hotkeyInfo.getCategory(), category);
|
||||
ps.addPreference(category);
|
||||
}
|
||||
|
||||
final ControllerBindingPreference cbp = new ControllerBindingPreference(getContext(), null);
|
||||
cbp.initHotkey(hotkeyInfo);
|
||||
category.addPreference(cbp);
|
||||
parent.preferences.add(cbp);
|
||||
}
|
||||
}
|
||||
|
||||
setPreferenceScreen(ps);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsCollectionAdapter extends FragmentStateAdapter {
|
||||
private final ControllerSettingsCollectionFragment parent;
|
||||
private final int controllerPorts;
|
||||
|
||||
public SettingsCollectionAdapter(@NonNull ControllerSettingsCollectionFragment parent, int controllerPorts) {
|
||||
super(parent);
|
||||
this.parent = parent;
|
||||
this.controllerPorts = controllerPorts;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
if (position == 0)
|
||||
return new SettingsFragment(parent);
|
||||
else if (position <= controllerPorts)
|
||||
return new ControllerPortFragment(parent, position);
|
||||
else
|
||||
return new HotkeyFragment(parent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return controllerPorts + 2;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,29 +1,41 @@
|
|||
package com.github.stenzek.duckstation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.res.Configuration;
|
||||
import android.hardware.input.InputManager;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Vibrator;
|
||||
import android.util.Log;
|
||||
import android.view.Display;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentTransaction;
|
||||
import androidx.preference.Preference;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.preference.PreferenceManager;
|
||||
|
||||
/**
|
||||
|
@ -38,7 +50,10 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
private boolean mWasDestroyed = false;
|
||||
private boolean mStopRequested = false;
|
||||
private boolean mApplySettingsOnSurfaceRestored = false;
|
||||
private String mGamePath = null;
|
||||
private String mGameCode = null;
|
||||
private String mGameTitle = null;
|
||||
private String mGameCoverPath = null;
|
||||
private EmulationSurfaceView mContentView;
|
||||
|
||||
private boolean getBooleanSetting(String key, boolean defaultValue) {
|
||||
|
@ -139,9 +154,12 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
});
|
||||
}
|
||||
|
||||
public void onGameTitleChanged(String title) {
|
||||
public void onRunningGameChanged(String path, String code, String title, String coverPath) {
|
||||
runOnUiThread(() -> {
|
||||
mGamePath = path;
|
||||
mGameTitle = title;
|
||||
mGameCode = code;
|
||||
mGameCoverPath = coverPath;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -162,7 +180,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
|
||||
public void openPauseMenu() {
|
||||
runOnUiThread(() -> {
|
||||
showMenu();
|
||||
showPauseMenu();
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -332,7 +350,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
showMenu();
|
||||
showPauseMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -427,70 +445,13 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
return true;
|
||||
}
|
||||
|
||||
private void showMenu() {
|
||||
if (getBooleanSetting("Main/PauseOnMenu", true) &&
|
||||
!AndroidHostInterface.getInstance().isEmulationThreadPaused()) {
|
||||
private void showPauseMenu() {
|
||||
if (!AndroidHostInterface.getInstance().isEmulationThreadPaused()) {
|
||||
AndroidHostInterface.getInstance().pauseEmulationThread(true);
|
||||
}
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
if (mGameTitle != null && !mGameTitle.isEmpty())
|
||||
builder.setTitle(mGameTitle);
|
||||
|
||||
builder.setItems(R.array.emulation_menu, (dialogInterface, i) -> {
|
||||
switch (i) {
|
||||
case 0: // Load State
|
||||
{
|
||||
showSaveStateMenu(false);
|
||||
return;
|
||||
}
|
||||
|
||||
case 1: // Save State
|
||||
{
|
||||
showSaveStateMenu(true);
|
||||
return;
|
||||
}
|
||||
|
||||
case 2: // Toggle Fast Forward
|
||||
{
|
||||
AndroidHostInterface.getInstance().setFastForwardEnabled(!AndroidHostInterface.getInstance().isFastForwardEnabled());
|
||||
onMenuClosed();
|
||||
return;
|
||||
}
|
||||
|
||||
case 3: // Achievements
|
||||
{
|
||||
showAchievementsPopup();
|
||||
return;
|
||||
}
|
||||
|
||||
case 4: // More Options
|
||||
{
|
||||
showMoreMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
case 5: // Quit
|
||||
{
|
||||
mStopRequested = true;
|
||||
finish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setOnCancelListener(dialogInterface -> onMenuClosed());
|
||||
|
||||
final AlertDialog dialog = builder.create();
|
||||
dialog.setOnShowListener(dialogInterface -> {
|
||||
// Disable cheevos if not loaded.
|
||||
if (AndroidHostInterface.getInstance().getCheevoCount() == 0)
|
||||
disableDialogMenuItem(dialog, 3);
|
||||
|
||||
// Disable load state for challenge mode.
|
||||
if (AndroidHostInterface.getInstance().isCheevosChallengeModeActive())
|
||||
disableDialogMenuItem(dialog, 0);
|
||||
});
|
||||
dialog.show();
|
||||
final MenuDialogFragment fragment = new MenuDialogFragment(this);
|
||||
fragment.show(getSupportFragmentManager(), "MenuDialogFragment");
|
||||
}
|
||||
|
||||
private void showSaveStateMenu(boolean saving) {
|
||||
|
@ -523,66 +484,6 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
dialog.show();
|
||||
}
|
||||
|
||||
private void showMoreMenu() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
if (mGameTitle != null && !mGameTitle.isEmpty())
|
||||
builder.setTitle(mGameTitle);
|
||||
|
||||
builder.setItems(R.array.emulation_more_menu, (dialogInterface, i) -> {
|
||||
switch (i) {
|
||||
case 0: // Reset
|
||||
{
|
||||
AndroidHostInterface.getInstance().resetSystem();
|
||||
onMenuClosed();
|
||||
return;
|
||||
}
|
||||
|
||||
case 1: // Patch Codes
|
||||
{
|
||||
showPatchesMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
case 2: // Change Disc
|
||||
{
|
||||
showDiscChangeMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
case 3: // Change Touchscreen Controller
|
||||
{
|
||||
showTouchscreenControllerMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
case 4: // Settings
|
||||
{
|
||||
Intent intent = new Intent(EmulationActivity.this, ControllerSettingsActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivityForResult(intent, REQUEST_CODE_SETTINGS);
|
||||
return;
|
||||
}
|
||||
|
||||
case 5: // Controller Settings
|
||||
{
|
||||
Intent intent = new Intent(EmulationActivity.this, SettingsActivity.class);
|
||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||
startActivityForResult(intent, REQUEST_CODE_SETTINGS);
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
builder.setOnCancelListener(dialogInterface -> onMenuClosed());
|
||||
|
||||
final AlertDialog dialog = builder.create();
|
||||
dialog.setOnShowListener(dialogInterface -> {
|
||||
// Disable patch codes when challenge mode is active.
|
||||
if (AndroidHostInterface.getInstance().isCheevosChallengeModeActive())
|
||||
disableDialogMenuItem(dialog, 1);
|
||||
});
|
||||
dialog.show();
|
||||
}
|
||||
|
||||
private void showTouchscreenControllerMenu() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setTitle(R.string.dialog_touchscreen_controller_settings);
|
||||
|
@ -882,4 +783,170 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
|||
mSustainedPerformanceModeEnabled = enabled;
|
||||
|
||||
}
|
||||
|
||||
public static class MenuDialogFragment extends DialogFragment {
|
||||
private EmulationActivity emulationActivity;
|
||||
private boolean settingsChanged = false;
|
||||
|
||||
public MenuDialogFragment(EmulationActivity emulationActivity) {
|
||||
this.emulationActivity = emulationActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setStyle(STYLE_NO_FRAME, R.style.EmulationActivityOverlay);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_emulation_activity_overlay, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(View view, Bundle savedInstanceState) {
|
||||
setContentFragment(new MenuSettingsFragment(this, emulationActivity), false);
|
||||
|
||||
final ImageView coverView =((ImageView)view.findViewById(R.id.cover_image));
|
||||
if (emulationActivity.mGameCoverPath != null && !emulationActivity.mGameCoverPath.isEmpty()) {
|
||||
new ImageLoadTask(coverView).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
|
||||
emulationActivity.mGameCoverPath);
|
||||
} else {
|
||||
new GenerateCoverTask(getContext(), coverView, emulationActivity.mGameTitle)
|
||||
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
coverView.setOnClickListener(v -> close(true));
|
||||
|
||||
((TextView)view.findViewById(R.id.title)).setText(emulationActivity.mGameTitle);
|
||||
final String subtitle = String.format("%s - %s", emulationActivity.mGameCode,
|
||||
FileHelper.getFileNameForPath(emulationActivity.mGamePath));
|
||||
((TextView)view.findViewById(R.id.subtitle)).setText(subtitle);
|
||||
|
||||
((ImageButton)view.findViewById(R.id.menu)).setOnClickListener(v -> onMenuClicked());
|
||||
((ImageButton)view.findViewById(R.id.controller_settings)).setOnClickListener(v -> onControllerSettingsClicked());
|
||||
((ImageButton)view.findViewById(R.id.settings)).setOnClickListener(v -> onSettingsClicked());
|
||||
((ImageButton)view.findViewById(R.id.quit)).setOnClickListener(v -> onQuitClicked());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel(@NonNull DialogInterface dialog) {
|
||||
onClosed(true);
|
||||
}
|
||||
|
||||
private void onClosed(boolean resumeGame) {
|
||||
if (settingsChanged)
|
||||
emulationActivity.applySettings();
|
||||
|
||||
if (resumeGame)
|
||||
emulationActivity.onMenuClosed();
|
||||
}
|
||||
|
||||
private void close(boolean resumeGame) {
|
||||
dismiss();
|
||||
onClosed(resumeGame);
|
||||
}
|
||||
|
||||
private void setContentFragment(Fragment fragment, boolean transition) {
|
||||
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
|
||||
if (transition)
|
||||
transaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
|
||||
transaction.replace(R.id.content, fragment).commit();
|
||||
}
|
||||
|
||||
private void onMenuClicked() {
|
||||
setContentFragment(new MenuSettingsFragment(this, emulationActivity), true);
|
||||
}
|
||||
|
||||
private void onControllerSettingsClicked() {
|
||||
ControllerSettingsCollectionFragment fragment = new ControllerSettingsCollectionFragment();
|
||||
setContentFragment(fragment, true);
|
||||
fragment.setMultitapModeChangedListener(this::onControllerSettingsClicked);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
private void onSettingsClicked() {
|
||||
setContentFragment(new SettingsCollectionFragment(), true);
|
||||
settingsChanged = true;
|
||||
}
|
||||
|
||||
private void onQuitClicked() {
|
||||
close(false);
|
||||
emulationActivity.mStopRequested = true;
|
||||
emulationActivity.finish();
|
||||
}
|
||||
}
|
||||
|
||||
public static class MenuSettingsFragment extends PreferenceFragmentCompat {
|
||||
private MenuDialogFragment menuDialogFragment;
|
||||
private EmulationActivity emulationActivity;
|
||||
|
||||
public MenuSettingsFragment(MenuDialogFragment menuDialogFragment, EmulationActivity emulationActivity) {
|
||||
this.menuDialogFragment = menuDialogFragment;
|
||||
this.emulationActivity = emulationActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferenceScreen(getPreferenceManager().createPreferenceScreen(getContext()));
|
||||
|
||||
final boolean cheevosActive = AndroidHostInterface.getInstance().isCheevosActive();
|
||||
final boolean cheevosChallengeModeEnabled = AndroidHostInterface.getInstance().isCheevosChallengeModeActive();
|
||||
|
||||
createPreference(R.string.emulation_menu_load_state, R.drawable.ic_baseline_folder_open_24, !cheevosChallengeModeEnabled, preference -> {
|
||||
menuDialogFragment.close(false);
|
||||
emulationActivity.showSaveStateMenu(false);
|
||||
return true;
|
||||
});
|
||||
createPreference(R.string.emulation_menu_save_state, R.drawable.ic_baseline_save_24, true, preference -> {
|
||||
menuDialogFragment.close(false);
|
||||
emulationActivity.showSaveStateMenu(true);
|
||||
return true;
|
||||
});
|
||||
createPreference(R.string.emulation_menu_toggle_fast_forward, R.drawable.ic_baseline_fast_forward_24, !cheevosChallengeModeEnabled, preference -> {
|
||||
AndroidHostInterface.getInstance().setFastForwardEnabled(!AndroidHostInterface.getInstance().isFastForwardEnabled());
|
||||
menuDialogFragment.close(true);
|
||||
return true;
|
||||
});
|
||||
createPreference(R.string.emulation_menu_achievements, R.drawable.ic_baseline_trophy_24, cheevosActive, preference -> {
|
||||
menuDialogFragment.close(false);
|
||||
emulationActivity.showAchievementsPopup();
|
||||
return true;
|
||||
});
|
||||
createPreference(R.string.emulation_menu_patch_codes, R.drawable.ic_baseline_tips_and_updates_24, !cheevosChallengeModeEnabled, preference -> {
|
||||
menuDialogFragment.close(false);
|
||||
emulationActivity.showPatchesMenu();
|
||||
return true;
|
||||
});
|
||||
createPreference(R.string.emulation_menu_change_disc, R.drawable.ic_baseline_album_24, true, preference -> {
|
||||
menuDialogFragment.close(false);
|
||||
emulationActivity.showDiscChangeMenu();
|
||||
return true;
|
||||
});
|
||||
createPreference(R.string.emulation_menu_touchscreen_controller_settings, R.drawable.ic_baseline_touch_app_24, true, preference -> {
|
||||
menuDialogFragment.close(false);
|
||||
emulationActivity.showTouchscreenControllerMenu();
|
||||
return true;
|
||||
});
|
||||
createPreference(R.string.emulation_menu_toggle_analog_mode, R.drawable.ic_baseline_gamepad_24, true, preference -> {
|
||||
AndroidHostInterface.getInstance().toggleControllerAnalogMode();
|
||||
menuDialogFragment.close(true);
|
||||
return true;
|
||||
});
|
||||
createPreference(R.string.emulation_menu_reset_console, R.drawable.ic_baseline_restart_alt_24, true, preference -> {
|
||||
AndroidHostInterface.getInstance().resetSystem();
|
||||
menuDialogFragment.close(true);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
private void createPreference(int titleId, int icon, boolean enabled, Preference.OnPreferenceClickListener action) {
|
||||
final Preference preference = new Preference(getContext());
|
||||
preference.setTitle(titleId);
|
||||
preference.setIcon(icon);
|
||||
preference.setOnPreferenceClickListener(action);
|
||||
preference.setEnabled(enabled);
|
||||
getPreferenceScreen().addPreference(preference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,22 +1,14 @@
|
|||
package com.github.stenzek.duckstation;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.app.ActionBar;
|
||||
import androidx.appcompat.app.AppCompatActivity;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
public class SettingsActivity extends AppCompatActivity {
|
||||
|
||||
|
@ -49,78 +41,4 @@ public class SettingsActivity extends AppCompatActivity {
|
|||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragmentCompat {
|
||||
private final int resourceId;
|
||||
|
||||
public SettingsFragment(int resourceId) {
|
||||
this.resourceId = resourceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(resourceId, rootKey);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsCollectionFragment extends Fragment {
|
||||
private SettingsCollectionAdapter adapter;
|
||||
private ViewPager2 viewPager;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_settings_collection, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
adapter = new SettingsCollectionAdapter(this);
|
||||
viewPager = view.findViewById(R.id.view_pager);
|
||||
viewPager.setAdapter(adapter);
|
||||
|
||||
TabLayout tabLayout = view.findViewById(R.id.tab_layout);
|
||||
new TabLayoutMediator(tabLayout, viewPager,
|
||||
(tab, position) -> tab.setText(getResources().getStringArray(R.array.settings_tabs)[position])
|
||||
).attach();
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsCollectionAdapter extends FragmentStateAdapter {
|
||||
public SettingsCollectionAdapter(@NonNull Fragment fragment) {
|
||||
super(fragment);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
switch (position) {
|
||||
case 0: // General
|
||||
return new SettingsFragment(R.xml.general_preferences);
|
||||
|
||||
case 1: // Display
|
||||
return new SettingsFragment(R.xml.display_preferences);
|
||||
|
||||
case 2: // Audio
|
||||
return new SettingsFragment(R.xml.audio_preferences);
|
||||
|
||||
case 3: // Enhancements
|
||||
return new SettingsFragment(R.xml.enhancements_preferences);
|
||||
|
||||
case 4: // Achievements
|
||||
return new AchievementSettingsFragment();
|
||||
|
||||
case 5: // Advanced
|
||||
return new SettingsFragment(R.xml.advanced_preferences);
|
||||
|
||||
default:
|
||||
return new Fragment();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
package com.github.stenzek.duckstation;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.preference.PreferenceFragmentCompat;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
public class SettingsCollectionFragment extends Fragment {
|
||||
private SettingsCollectionAdapter adapter;
|
||||
private ViewPager2 viewPager;
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.fragment_settings_collection, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
adapter = new SettingsCollectionAdapter(this);
|
||||
viewPager = view.findViewById(R.id.view_pager);
|
||||
viewPager.setAdapter(adapter);
|
||||
|
||||
TabLayout tabLayout = view.findViewById(R.id.tab_layout);
|
||||
new TabLayoutMediator(tabLayout, viewPager,
|
||||
(tab, position) -> tab.setText(getResources().getStringArray(R.array.settings_tabs)[position])
|
||||
).attach();
|
||||
}
|
||||
|
||||
public static class SettingsFragment extends PreferenceFragmentCompat {
|
||||
private final int resourceId;
|
||||
|
||||
public SettingsFragment(int resourceId) {
|
||||
this.resourceId = resourceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
|
||||
setPreferencesFromResource(resourceId, rootKey);
|
||||
}
|
||||
}
|
||||
|
||||
public static class SettingsCollectionAdapter extends FragmentStateAdapter {
|
||||
public SettingsCollectionAdapter(@NonNull Fragment fragment) {
|
||||
super(fragment);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
switch (position) {
|
||||
case 0: // General
|
||||
return new SettingsFragment(R.xml.general_preferences);
|
||||
|
||||
case 1: // Display
|
||||
return new SettingsFragment(R.xml.display_preferences);
|
||||
|
||||
case 2: // Audio
|
||||
return new SettingsFragment(R.xml.audio_preferences);
|
||||
|
||||
case 3: // Enhancements
|
||||
return new SettingsFragment(R.xml.enhancements_preferences);
|
||||
|
||||
case 4: // Achievements
|
||||
return new AchievementSettingsFragment();
|
||||
|
||||
case 5: // Advanced
|
||||
return new SettingsFragment(R.xml.advanced_preferences);
|
||||
|
||||
default:
|
||||
return new Fragment();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return 6;
|
||||
}
|
||||
}
|
||||
}
|
10
android/app/src/main/res/drawable/ic_baseline_album_24.xml
Normal file
10
android/app/src/main/res/drawable/ic_baseline_album_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,16.5c-2.49,0 -4.5,-2.01 -4.5,-4.5S9.51,7.5 12,7.5s4.5,2.01 4.5,4.5 -2.01,4.5 -4.5,4.5zM12,11c-0.55,0 -1,0.45 -1,1s0.45,1 1,1 1,-0.45 1,-1 -0.45,-1 -1,-1z"/>
|
||||
</vector>
|
|
@ -0,0 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:autoMirrored="true">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M20,11H7.83l5.59,-5.59L12,4l-8,8 8,8 1.41,-1.41L7.83,13H20v-2z"/>
|
||||
</vector>
|
|
@ -0,0 +1,11 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:autoMirrored="true">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M10.09,15.59L11.5,17l5,-5 -5,-5 -1.41,1.41L12.67,11H3v2h9.67l-2.58,2.59zM19,3H5c-1.11,0 -2,0.9 -2,2v4h2V5h14v14H5v-4H3v4c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V5c0,-1.1 -0.9,-2 -2,-2z"/>
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M4,18l8.5,-6L4,6v12zM13,6v12l8.5,-6L13,6z"/>
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M11,18L11,6l-8.5,6 8.5,6zM11.5,12l8.5,6L20,6l-8.5,6z"/>
|
||||
</vector>
|
10
android/app/src/main/res/drawable/ic_baseline_menu_24.xml
Normal file
10
android/app/src/main/res/drawable/ic_baseline_menu_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z"/>
|
||||
</vector>
|
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,5V2L8,6l4,4V7c3.31,0 6,2.69 6,6c0,2.97 -2.17,5.43 -5,5.91v2.02c3.95,-0.49 7,-3.85 7,-7.93C20,8.58 16.42,5 12,5z"/>
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M6,13c0,-1.65 0.67,-3.15 1.76,-4.24L6.34,7.34C4.9,8.79 4,10.79 4,13c0,4.08 3.05,7.44 7,7.93v-2.02C8.17,18.43 6,15.97 6,13z"/>
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M7,20h4c0,1.1 -0.9,2 -2,2S7,21.1 7,20zM5,19h8v-2H5V19zM16.5,9.5c0,3.82 -2.66,5.86 -3.77,6.5H5.27C4.16,15.36 1.5,13.32 1.5,9.5C1.5,5.36 4.86,2 9,2S16.5,5.36 16.5,9.5zM21.37,7.37L20,8l1.37,0.63L22,10l0.63,-1.37L24,8l-1.37,-0.63L22,6L21.37,7.37zM19,6l0.94,-2.06L22,3l-2.06,-0.94L19,0l-0.94,2.06L16,3l2.06,0.94L19,6z"/>
|
||||
</vector>
|
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M9,11.24V7.5C9,6.12 10.12,5 11.5,5S14,6.12 14,7.5v3.74c1.21,-0.81 2,-2.18 2,-3.74C16,5.01 13.99,3 11.5,3S7,5.01 7,7.5C7,9.06 7.79,10.43 9,11.24zM18.84,15.87l-4.54,-2.26c-0.17,-0.07 -0.35,-0.11 -0.54,-0.11H13v-6C13,6.67 12.33,6 11.5,6S10,6.67 10,7.5v10.74c-3.6,-0.76 -3.54,-0.75 -3.67,-0.75c-0.31,0 -0.59,0.13 -0.79,0.33l-0.79,0.8l4.94,4.94C9.96,23.83 10.34,24 10.75,24h6.79c0.75,0 1.33,-0.55 1.44,-1.28l0.75,-5.27c0.01,-0.07 0.02,-0.14 0.02,-0.2C19.75,16.63 19.37,16.09 18.84,15.87z"/>
|
||||
</vector>
|
10
android/app/src/main/res/drawable/ic_baseline_trophy_24.xml
Normal file
10
android/app/src/main/res/drawable/ic_baseline_trophy_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24"
|
||||
android:tint="?attr/colorControlNormal">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,5h-2V3H7v2H5C3.9,5 3,5.9 3,7v1c0,2.55 1.92,4.63 4.39,4.94c0.63,1.5 1.98,2.63 3.61,2.96V19H7v2h10v-2h-4v-3.1c1.63,-0.33 2.98,-1.46 3.61,-2.96C19.08,12.63 21,10.55 21,8V7C21,5.9 20.1,5 19,5zM5,8V7h2v3.82C5.84,10.4 5,9.3 5,8zM19,8c0,1.3 -0.84,2.4 -2,2.82V7h2V8z"/>
|
||||
</vector>
|
|
@ -0,0 +1,107 @@
|
|||
<LinearLayout 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"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="#99111111"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/cover_image"
|
||||
android:layout_width="60dp"
|
||||
android:layout_height="60dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:text="Title"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Large"
|
||||
android:scrollHorizontally="true"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
app:layout_constraintEnd_toStartOf="@id/button_container"
|
||||
app:layout_constraintStart_toEndOf="@id/cover_image"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="Code - Path"
|
||||
android:scrollHorizontally="true"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Small"
|
||||
app:layout_constraintEnd_toStartOf="@id/button_container"
|
||||
app:layout_constraintStart_toEndOf="@id/cover_image"
|
||||
app:layout_constraintTop_toBottomOf="@id/title" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:id="@+id/button_container"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/menu"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="Pause Menu"
|
||||
android:src="@drawable/ic_baseline_menu_24" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/controller_settings"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="Controller Settings"
|
||||
android:src="@drawable/ic_baseline_gamepad_24" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/settings"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="Settings"
|
||||
android:src="@drawable/ic_baseline_settings_24" />
|
||||
|
||||
<ImageButton
|
||||
android:id="@+id/quit"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="60dp"
|
||||
android:layout_marginEnd="5dp"
|
||||
android:background="?android:attr/selectableItemBackground"
|
||||
android:contentDescription="Quit"
|
||||
android:src="@drawable/ic_baseline_exit_to_app_24" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
</LinearLayout>
|
|
@ -75,22 +75,6 @@
|
|||
<item>Tarjeta separada por juego (Código)</item>
|
||||
<item>Tarjeta separada por juego (Título)</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_menu">
|
||||
<item>Cargar Estado</item>
|
||||
<item>Guardar Estado</item>
|
||||
<item>Activar Avance rápido</item>
|
||||
<item>Logros</item>
|
||||
<item>Más Opciones</item>
|
||||
<item>Salir</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_more_menu">
|
||||
<item>Reiniciar</item>
|
||||
<item>Código de trucos</item>
|
||||
<item>Cambiar disco</item>
|
||||
<item>Cambiar control de pantalla tactil</item>
|
||||
<item>Configuración del control</item>
|
||||
<item>Configuraciones</item>
|
||||
</string-array>
|
||||
<string-array name="settings_cdrom_read_speedup_entries">
|
||||
<item>Ninguno (Velocidad doble)</item>
|
||||
<item>2x (Velocidad cuádruple)</item>
|
||||
|
|
|
@ -75,22 +75,6 @@
|
|||
<item>MC separata per ogni gioco (Codice Gioco)</item>
|
||||
<item>MC separata per ogni gioco (Titolo Gioco)</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_menu">
|
||||
<item>Carica Stato</item>
|
||||
<item>Salva Stato</item>
|
||||
<item>Abilita/Disabilita Avanti Veloce</item>
|
||||
<item>Achievements</item>
|
||||
<item>Altre Opzioni</item>
|
||||
<item>Esci</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_more_menu">
|
||||
<item>Reset</item>
|
||||
<item>Codici Patch</item>
|
||||
<item>Cambia Disco</item>
|
||||
<item>Cambia Controller Touchscreen</item>
|
||||
<item>Controller Settings</item>
|
||||
<item>Impostazioni</item>
|
||||
</string-array>
|
||||
<string-array name="settings_cdrom_read_speedup_entries">
|
||||
<item>Nessuna Velocità Doppia)</item>
|
||||
<item>2x (Velocità Quadrupla</item>
|
||||
|
|
|
@ -75,22 +75,6 @@
|
|||
<item>Aparte Kaart Per Spel (Spelcode)</item>
|
||||
<item>Aparte Kaart Per Spel (Speltitel)</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_menu">
|
||||
<item>Staat Laden</item>
|
||||
<item>Staat Opslaan</item>
|
||||
<item>Doorspoelen aan/uitzetten</item>
|
||||
<item>Achievements</item>
|
||||
<item>Meer Opties</item>
|
||||
<item>Afsluiten</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_more_menu">
|
||||
<item>Resetten</item>
|
||||
<item>Patch Codes</item>
|
||||
<item>Disc Veranderen</item>
|
||||
<item>Touchscreen Controller Aanpassen</item>
|
||||
<item>Controller Settings</item>
|
||||
<item>Instellingen</item>
|
||||
</string-array>
|
||||
<string-array name="settings_cdrom_read_speedup_entries">
|
||||
<item>Geen (Dubbele Snelheid)</item>
|
||||
<item>2x (Vierdubbele Snelheid)</item>
|
||||
|
|
|
@ -74,22 +74,6 @@
|
|||
<item>Compartilhada entre Jogos</item>
|
||||
<item>Separado Por Jogo (Cód. Jogo)</item>
|
||||
<item>Separado Por Jogo (Título Jogo)</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_menu">
|
||||
<item>Carregar Estado</item>
|
||||
<item>Salvar Estado</item>
|
||||
<item>Avanço (Fixo)</item>
|
||||
<item>Achievements</item>
|
||||
<item>Mais Opções</item>
|
||||
<item>Sair</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_more_menu">
|
||||
<item>Reiniciar</item>
|
||||
<item>Trapaças</item>
|
||||
<item>Mudar Disco</item>
|
||||
<item>Mudar controle em Tela</item>
|
||||
<item>Controller Settings</item>
|
||||
<item>Configurações</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_touchscreen_menu">
|
||||
<item>Mudar</item>
|
||||
|
|
|
@ -75,22 +75,6 @@
|
|||
<item>Своя карта для каждой игры (по коду)</item>
|
||||
<item>Своя карта для каждой игры (по названию)</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_menu">
|
||||
<item>Загрузить состояние</item>
|
||||
<item>Сохранить состояние</item>
|
||||
<item>Включить ускорение</item>
|
||||
<item>Достижения</item>
|
||||
<item>Опции</item>
|
||||
<item>Выход</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_more_menu">
|
||||
<item>Сброс</item>
|
||||
<item>Чит-коды</item>
|
||||
<item>Сменить диск</item>
|
||||
<item>Экранный геймпад</item>
|
||||
<item>Управление</item>
|
||||
<item>Настройки</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_touchscreen_menu">
|
||||
<item>Сменить вид</item>
|
||||
<item>Настроить видимость</item>
|
||||
|
|
|
@ -151,22 +151,6 @@
|
|||
<item>PerGame</item>
|
||||
<item>PerGameTitle</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_menu">
|
||||
<item>Load State</item>
|
||||
<item>Save State</item>
|
||||
<item>Toggle Fast Forward</item>
|
||||
<item>Achievements</item>
|
||||
<item>More Options</item>
|
||||
<item>Quit</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_more_menu">
|
||||
<item>Reset</item>
|
||||
<item>Patch Codes</item>
|
||||
<item>Change Disc</item>
|
||||
<item>Change Touchscreen Controller</item>
|
||||
<item>Controller Settings</item>
|
||||
<item>Settings</item>
|
||||
</string-array>
|
||||
<string-array name="emulation_touchscreen_menu">
|
||||
<item>Change Type</item>
|
||||
<item>Change Opacity</item>
|
||||
|
|
|
@ -7,4 +7,6 @@
|
|||
|
||||
<color name="black_overlay">#66000000</color>
|
||||
<color name="fab_background">#ffffffff</color>
|
||||
|
||||
<color name="settings_overlay_background">#dd111111</color>
|
||||
</resources>
|
||||
|
|
|
@ -336,4 +336,13 @@
|
|||
<string name="settings_category_achievements">Achievement Settings</string>
|
||||
<string name="settings_multitap_mode">Multitap Mode</string>
|
||||
<string name="settings_touchscreen_controller_port">Touchscreen Controller Port</string>
|
||||
<string name="emulation_menu_load_state">Load State</string>
|
||||
<string name="emulation_menu_save_state">Save State</string>
|
||||
<string name="emulation_menu_toggle_fast_forward">Toggle Fast Forward</string>
|
||||
<string name="emulation_menu_achievements">Achievements</string>
|
||||
<string name="emulation_menu_patch_codes">Patch Codes</string>
|
||||
<string name="emulation_menu_change_disc">Change Disc</string>
|
||||
<string name="emulation_menu_touchscreen_controller_settings">Touchscreen Controller Settings</string>
|
||||
<string name="emulation_menu_toggle_analog_mode">Toggle Controller Analog Mode</string>
|
||||
<string name="emulation_menu_reset_console">Reset Console</string>
|
||||
</resources>
|
||||
|
|
|
@ -35,4 +35,13 @@
|
|||
<item name="android:textAllCaps">false</item>
|
||||
</style>
|
||||
|
||||
<style name="EmulationActivityOverlay" parent="Theme.AppCompat.DayNight.DarkActionBar">
|
||||
<item name="android:windowNoTitle">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
<item name="android:colorBackgroundCacheHint">@null</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
<item name="android:windowAnimationStyle">@android:style/Animation.Dialog</item>
|
||||
<item name="android:backgroundDimEnabled">true</item>
|
||||
<item name="android:backgroundDimAmount">0.8</item>
|
||||
</style>
|
||||
</resources>
|
||||
|
|
Loading…
Reference in a new issue