mirror of
https://github.com/RetroDECK/Duckstation.git
synced 2025-02-18 11:55:38 +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_reportError;
|
||||||
static jmethodID s_EmulationActivity_method_onEmulationStarted;
|
static jmethodID s_EmulationActivity_method_onEmulationStarted;
|
||||||
static jmethodID s_EmulationActivity_method_onEmulationStopped;
|
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_setVibration;
|
||||||
static jmethodID s_EmulationActivity_method_getRefreshRate;
|
static jmethodID s_EmulationActivity_method_getRefreshRate;
|
||||||
static jmethodID s_EmulationActivity_method_openPauseMenu;
|
static jmethodID s_EmulationActivity_method_openPauseMenu;
|
||||||
|
@ -703,9 +703,29 @@ void AndroidHostInterface::OnRunningGameChanged(const std::string& path, CDImage
|
||||||
if (m_emulation_activity_object)
|
if (m_emulation_activity_object)
|
||||||
{
|
{
|
||||||
JNIEnv* env = AndroidHelpers::GetJNIEnv();
|
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(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 ||
|
env->GetMethodID(s_EmulationActivity_class, "onEmulationStarted", "()V")) == nullptr ||
|
||||||
(s_EmulationActivity_method_onEmulationStopped =
|
(s_EmulationActivity_method_onEmulationStopped =
|
||||||
env->GetMethodID(s_EmulationActivity_class, "onEmulationStopped", "()V")) == nullptr ||
|
env->GetMethodID(s_EmulationActivity_class, "onEmulationStopped", "()V")) == nullptr ||
|
||||||
(s_EmulationActivity_method_onGameTitleChanged =
|
(s_EmulationActivity_method_onRunningGameChanged =
|
||||||
env->GetMethodID(s_EmulationActivity_class, "onGameTitleChanged", "(Ljava/lang/String;)V")) == nullptr ||
|
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")) ==
|
(s_EmulationActivity_method_setVibration = env->GetMethodID(emulation_activity_class, "setVibration", "(Z)V")) ==
|
||||||
nullptr ||
|
nullptr ||
|
||||||
(s_EmulationActivity_method_getRefreshRate =
|
(s_EmulationActivity_method_getRefreshRate =
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package com.github.stenzek.duckstation;
|
package com.github.stenzek.duckstation;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.text.InputType;
|
import android.text.InputType;
|
||||||
|
@ -20,8 +21,8 @@ public class ControllerAutoMapper {
|
||||||
public void onComplete();
|
public void onComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
final private ControllerSettingsActivity parent;
|
private final Context context;
|
||||||
final private int port;
|
private final int port;
|
||||||
private final CompleteCallback completeCallback;
|
private final CompleteCallback completeCallback;
|
||||||
|
|
||||||
private InputDevice device;
|
private InputDevice device;
|
||||||
|
@ -31,8 +32,8 @@ public class ControllerAutoMapper {
|
||||||
private String keyBase;
|
private String keyBase;
|
||||||
private String controllerType;
|
private String controllerType;
|
||||||
|
|
||||||
public ControllerAutoMapper(ControllerSettingsActivity activity, int port, CompleteCallback completeCallback) {
|
public ControllerAutoMapper(Context context, int port, CompleteCallback completeCallback) {
|
||||||
this.parent = activity;
|
this.context = context;
|
||||||
this.port = port;
|
this.port = port;
|
||||||
this.completeCallback = completeCallback;
|
this.completeCallback = completeCallback;
|
||||||
}
|
}
|
||||||
|
@ -126,7 +127,7 @@ public class ControllerAutoMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (deviceList.isEmpty()) {
|
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.setTitle(R.string.main_activity_error);
|
||||||
builder.setMessage(R.string.controller_auto_mapping_no_devices);
|
builder.setMessage(R.string.controller_auto_mapping_no_devices);
|
||||||
builder.setPositiveButton(R.string.main_activity_ok, (dialog, which) -> dialog.dismiss());
|
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++)
|
for (int i = 0; i < deviceList.size(); i++)
|
||||||
deviceNames[i] = deviceList.get(i).getName();
|
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.setTitle(R.string.controller_auto_mapping_select_device);
|
||||||
builder.setItems(deviceNames, (dialog, which) -> {
|
builder.setItems(deviceNames, (dialog, which) -> {
|
||||||
process(deviceList.get(which));
|
process(deviceList.get(which));
|
||||||
|
@ -147,13 +148,13 @@ public class ControllerAutoMapper {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void process(InputDevice device) {
|
private void process(InputDevice device) {
|
||||||
this.prefs = PreferenceManager.getDefaultSharedPreferences(parent);
|
this.prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
this.editor = prefs.edit();
|
this.editor = prefs.edit();
|
||||||
this.log = new StringBuilder();
|
this.log = new StringBuilder();
|
||||||
this.device = device;
|
this.device = device;
|
||||||
|
|
||||||
this.keyBase = String.format("Controller%d/", port);
|
this.keyBase = String.format("Controller%d/", port);
|
||||||
this.controllerType = parent.getControllerType(prefs, port);
|
this.controllerType = ControllerSettingsCollectionFragment.getControllerType(prefs, port);
|
||||||
|
|
||||||
setButtonBindings();
|
setButtonBindings();
|
||||||
setAxisBindings();
|
setAxisBindings();
|
||||||
|
@ -162,10 +163,10 @@ public class ControllerAutoMapper {
|
||||||
this.editor.commit();
|
this.editor.commit();
|
||||||
this.editor = null;
|
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);
|
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.setText(log.toString());
|
||||||
editText.setInputType(InputType.TYPE_NULL | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
editText.setInputType(InputType.TYPE_NULL | InputType.TYPE_TEXT_FLAG_MULTI_LINE);
|
||||||
editText.setSingleLine(false);
|
editText.setSingleLine(false);
|
||||||
|
|
|
@ -2,50 +2,33 @@ package com.github.stenzek.duckstation;
|
||||||
|
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.Menu;
|
import android.view.Menu;
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.EditText;
|
import android.widget.EditText;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
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.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.ArrayList;
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
public class ControllerSettingsActivity extends AppCompatActivity {
|
public class ControllerSettingsActivity extends AppCompatActivity {
|
||||||
|
private ControllerSettingsCollectionFragment fragment;
|
||||||
private static final int NUM_CONTROLLER_PORTS = 2;
|
|
||||||
public static final String MULTITAP_MODE_SETTINGS_KEY = "ControllerPorts/MultitapMode";
|
|
||||||
|
|
||||||
private ArrayList<ControllerBindingPreference> mPreferences = new ArrayList<>();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.settings_activity);
|
setContentView(R.layout.settings_activity);
|
||||||
|
|
||||||
|
fragment = new ControllerSettingsCollectionFragment();
|
||||||
|
fragment.setMultitapModeChangedListener(this::recreate);
|
||||||
|
|
||||||
getSupportFragmentManager()
|
getSupportFragmentManager()
|
||||||
.beginTransaction()
|
.beginTransaction()
|
||||||
.replace(R.id.settings, new SettingsCollectionFragment(this))
|
.replace(R.id.settings, fragment)
|
||||||
.commit();
|
.commit();
|
||||||
ActionBar actionBar = getSupportActionBar();
|
ActionBar actionBar = getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
|
@ -84,7 +67,7 @@ public class ControllerSettingsActivity extends AppCompatActivity {
|
||||||
doSaveProfile();
|
doSaveProfile();
|
||||||
return true;
|
return true;
|
||||||
} else if (id == R.id.action_clear_bindings) {
|
} else if (id == R.id.action_clear_bindings) {
|
||||||
doClearBindings();
|
fragment.clearAllBindings();
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return super.onOptionsItemSelected(item);
|
return super.onOptionsItemSelected(item);
|
||||||
|
@ -124,7 +107,7 @@ public class ControllerSettingsActivity extends AppCompatActivity {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateAllBindings();
|
fragment.updateAllBindings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void doSaveProfile() {
|
private void doSaveProfile() {
|
||||||
|
@ -151,355 +134,5 @@ public class ControllerSettingsActivity extends AppCompatActivity {
|
||||||
builder.create().show();
|
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;
|
package com.github.stenzek.duckstation;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.DialogInterface;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.pm.ActivityInfo;
|
import android.content.pm.ActivityInfo;
|
||||||
import android.content.res.Configuration;
|
import android.content.res.Configuration;
|
||||||
import android.hardware.input.InputManager;
|
import android.hardware.input.InputManager;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.AsyncTask;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Vibrator;
|
import android.os.Vibrator;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.Display;
|
import android.view.Display;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.SurfaceHolder;
|
import android.view.SurfaceHolder;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
import android.view.WindowManager;
|
import android.view.WindowManager;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ImageView;
|
||||||
import android.widget.ListView;
|
import android.widget.ListView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
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;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -38,7 +50,10 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
private boolean mWasDestroyed = false;
|
private boolean mWasDestroyed = false;
|
||||||
private boolean mStopRequested = false;
|
private boolean mStopRequested = false;
|
||||||
private boolean mApplySettingsOnSurfaceRestored = false;
|
private boolean mApplySettingsOnSurfaceRestored = false;
|
||||||
|
private String mGamePath = null;
|
||||||
|
private String mGameCode = null;
|
||||||
private String mGameTitle = null;
|
private String mGameTitle = null;
|
||||||
|
private String mGameCoverPath = null;
|
||||||
private EmulationSurfaceView mContentView;
|
private EmulationSurfaceView mContentView;
|
||||||
|
|
||||||
private boolean getBooleanSetting(String key, boolean defaultValue) {
|
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(() -> {
|
runOnUiThread(() -> {
|
||||||
|
mGamePath = path;
|
||||||
mGameTitle = title;
|
mGameTitle = title;
|
||||||
|
mGameCode = code;
|
||||||
|
mGameCoverPath = coverPath;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +180,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
|
|
||||||
public void openPauseMenu() {
|
public void openPauseMenu() {
|
||||||
runOnUiThread(() -> {
|
runOnUiThread(() -> {
|
||||||
showMenu();
|
showPauseMenu();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -332,7 +350,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBackPressed() {
|
public void onBackPressed() {
|
||||||
showMenu();
|
showPauseMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -427,70 +445,13 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMenu() {
|
private void showPauseMenu() {
|
||||||
if (getBooleanSetting("Main/PauseOnMenu", true) &&
|
if (!AndroidHostInterface.getInstance().isEmulationThreadPaused()) {
|
||||||
!AndroidHostInterface.getInstance().isEmulationThreadPaused()) {
|
|
||||||
AndroidHostInterface.getInstance().pauseEmulationThread(true);
|
AndroidHostInterface.getInstance().pauseEmulationThread(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
final MenuDialogFragment fragment = new MenuDialogFragment(this);
|
||||||
if (mGameTitle != null && !mGameTitle.isEmpty())
|
fragment.show(getSupportFragmentManager(), "MenuDialogFragment");
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showSaveStateMenu(boolean saving) {
|
private void showSaveStateMenu(boolean saving) {
|
||||||
|
@ -523,66 +484,6 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
dialog.show();
|
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() {
|
private void showTouchscreenControllerMenu() {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||||
builder.setTitle(R.string.dialog_touchscreen_controller_settings);
|
builder.setTitle(R.string.dialog_touchscreen_controller_settings);
|
||||||
|
@ -882,4 +783,170 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
mSustainedPerformanceModeEnabled = enabled;
|
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;
|
package com.github.stenzek.duckstation;
|
||||||
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.MenuItem;
|
import android.view.MenuItem;
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.appcompat.app.ActionBar;
|
import androidx.appcompat.app.ActionBar;
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
import androidx.preference.PreferenceFragmentCompat;
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
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 {
|
public class SettingsActivity extends AppCompatActivity {
|
||||||
|
|
||||||
|
@ -49,78 +41,4 @@ public class SettingsActivity extends AppCompatActivity {
|
||||||
|
|
||||||
return super.onOptionsItemSelected(item);
|
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 (Código)</item>
|
||||||
<item>Tarjeta separada por juego (Título)</item>
|
<item>Tarjeta separada por juego (Título)</item>
|
||||||
</string-array>
|
</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">
|
<string-array name="settings_cdrom_read_speedup_entries">
|
||||||
<item>Ninguno (Velocidad doble)</item>
|
<item>Ninguno (Velocidad doble)</item>
|
||||||
<item>2x (Velocidad cuádruple)</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 (Codice Gioco)</item>
|
||||||
<item>MC separata per ogni gioco (Titolo Gioco)</item>
|
<item>MC separata per ogni gioco (Titolo Gioco)</item>
|
||||||
</string-array>
|
</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">
|
<string-array name="settings_cdrom_read_speedup_entries">
|
||||||
<item>Nessuna Velocità Doppia)</item>
|
<item>Nessuna Velocità Doppia)</item>
|
||||||
<item>2x (Velocità Quadrupla</item>
|
<item>2x (Velocità Quadrupla</item>
|
||||||
|
|
|
@ -75,22 +75,6 @@
|
||||||
<item>Aparte Kaart Per Spel (Spelcode)</item>
|
<item>Aparte Kaart Per Spel (Spelcode)</item>
|
||||||
<item>Aparte Kaart Per Spel (Speltitel)</item>
|
<item>Aparte Kaart Per Spel (Speltitel)</item>
|
||||||
</string-array>
|
</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">
|
<string-array name="settings_cdrom_read_speedup_entries">
|
||||||
<item>Geen (Dubbele Snelheid)</item>
|
<item>Geen (Dubbele Snelheid)</item>
|
||||||
<item>2x (Vierdubbele Snelheid)</item>
|
<item>2x (Vierdubbele Snelheid)</item>
|
||||||
|
|
|
@ -75,23 +75,7 @@
|
||||||
<item>Separado Por Jogo (Cód. Jogo)</item>
|
<item>Separado Por Jogo (Cód. Jogo)</item>
|
||||||
<item>Separado Por Jogo (Título Jogo)</item>
|
<item>Separado Por Jogo (Título Jogo)</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
<string-array name="emulation_menu">
|
<string-array name="emulation_touchscreen_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>
|
<item>Mudar</item>
|
||||||
<item>Ajustar Visibilidade</item>
|
<item>Ajustar Visibilidade</item>
|
||||||
<item>Adicionar/Remover botões</item>
|
<item>Adicionar/Remover botões</item>
|
||||||
|
|
|
@ -75,22 +75,6 @@
|
||||||
<item>Своя карта для каждой игры (по коду)</item>
|
<item>Своя карта для каждой игры (по коду)</item>
|
||||||
<item>Своя карта для каждой игры (по названию)</item>
|
<item>Своя карта для каждой игры (по названию)</item>
|
||||||
</string-array>
|
</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">
|
<string-array name="emulation_touchscreen_menu">
|
||||||
<item>Сменить вид</item>
|
<item>Сменить вид</item>
|
||||||
<item>Настроить видимость</item>
|
<item>Настроить видимость</item>
|
||||||
|
|
|
@ -151,22 +151,6 @@
|
||||||
<item>PerGame</item>
|
<item>PerGame</item>
|
||||||
<item>PerGameTitle</item>
|
<item>PerGameTitle</item>
|
||||||
</string-array>
|
</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">
|
<string-array name="emulation_touchscreen_menu">
|
||||||
<item>Change Type</item>
|
<item>Change Type</item>
|
||||||
<item>Change Opacity</item>
|
<item>Change Opacity</item>
|
||||||
|
|
|
@ -7,4 +7,6 @@
|
||||||
|
|
||||||
<color name="black_overlay">#66000000</color>
|
<color name="black_overlay">#66000000</color>
|
||||||
<color name="fab_background">#ffffffff</color>
|
<color name="fab_background">#ffffffff</color>
|
||||||
|
|
||||||
|
<color name="settings_overlay_background">#dd111111</color>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -336,4 +336,13 @@
|
||||||
<string name="settings_category_achievements">Achievement Settings</string>
|
<string name="settings_category_achievements">Achievement Settings</string>
|
||||||
<string name="settings_multitap_mode">Multitap Mode</string>
|
<string name="settings_multitap_mode">Multitap Mode</string>
|
||||||
<string name="settings_touchscreen_controller_port">Touchscreen Controller Port</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>
|
</resources>
|
||||||
|
|
|
@ -35,4 +35,13 @@
|
||||||
<item name="android:textAllCaps">false</item>
|
<item name="android:textAllCaps">false</item>
|
||||||
</style>
|
</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>
|
</resources>
|
||||||
|
|
Loading…
Reference in a new issue