summaryrefslogtreecommitdiff
path: root/Source/Android/app/src/main/java
diff options
context:
space:
mode:
authorJosJuice <josjuice@gmail.com>2022-12-26 19:26:58 +0100
committerJosJuice <josjuice@gmail.com>2023-03-03 22:28:25 +0100
commit1eeded23df829973065d51c2595bf743910bc07e (patch)
treea43a727a3233c02f4832be63d5d173c31a61aae1 /Source/Android/app/src/main/java
parent7ef229d9082f72795e71db58ed13824bdd3d3e2c (diff)
Android: Add input profile management
Co-authored-by: Charles Lombardo <clombardo169@gmail.com>
Diffstat (limited to 'Source/Android/app/src/main/java')
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.java4
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileAdapter.java65
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialog.kt76
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java150
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileViewHolder.java76
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java15
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java14
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java16
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java14
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java15
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java11
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java14
12 files changed, 464 insertions, 6 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.java
index 5f6275ffcd..47d4dc5c96 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/model/controlleremu/EmulatedController.java
@@ -35,6 +35,10 @@ public class EmulatedController
public native void clearSettings();
+ public native void loadProfile(String path);
+
+ public native void saveProfile(String path);
+
public static native EmulatedController getGcPad(int controllerIndex);
public static native EmulatedController getWiimote(int controllerIndex);
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileAdapter.java
new file mode 100644
index 0000000000..9908d6f5fd
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileAdapter.java
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.input.ui;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.ViewGroup;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import org.dolphinemu.dolphinemu.databinding.ListItemProfileBinding;
+
+public final class ProfileAdapter extends RecyclerView.Adapter<ProfileViewHolder>
+{
+ private final Context mContext;
+ private final ProfileDialogPresenter mPresenter;
+
+ private final String[] mStockProfileNames;
+ private final String[] mUserProfileNames;
+
+ public ProfileAdapter(Context context, ProfileDialogPresenter presenter)
+ {
+ mContext = context;
+ mPresenter = presenter;
+
+ mStockProfileNames = presenter.getProfileNames(true);
+ mUserProfileNames = presenter.getProfileNames(false);
+ }
+
+ @NonNull @Override
+ public ProfileViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType)
+ {
+ LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+
+ ListItemProfileBinding binding = ListItemProfileBinding.inflate(inflater, parent, false);
+ return new ProfileViewHolder(mPresenter, binding);
+ }
+
+ @Override
+ public void onBindViewHolder(@NonNull ProfileViewHolder holder, int position)
+ {
+ if (position < mStockProfileNames.length)
+ {
+ holder.bind(mStockProfileNames[position], true);
+ return;
+ }
+
+ position -= mStockProfileNames.length;
+
+ if (position < mUserProfileNames.length)
+ {
+ holder.bind(mUserProfileNames[position], false);
+ return;
+ }
+
+ holder.bindAsEmpty(mContext);
+ }
+
+ @Override
+ public int getItemCount()
+ {
+ return mStockProfileNames.length + mUserProfileNames.length + 1;
+ }
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialog.kt b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialog.kt
new file mode 100644
index 0000000000..2779ee7473
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialog.kt
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.input.ui
+
+import android.os.Build
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.recyclerview.widget.LinearLayoutManager
+import com.google.android.material.bottomsheet.BottomSheetBehavior
+import com.google.android.material.bottomsheet.BottomSheetDialogFragment
+import com.google.android.material.divider.MaterialDividerItemDecoration
+import org.dolphinemu.dolphinemu.R
+import org.dolphinemu.dolphinemu.databinding.DialogInputProfilesBinding
+import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag
+
+class ProfileDialog : BottomSheetDialogFragment() {
+ private var presenter: ProfileDialogPresenter? = null
+
+ private var _binding: DialogInputProfilesBinding? = null
+ private val binding get() = _binding!!
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ val menuTag: MenuTag = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ requireArguments().getSerializable(KEY_MENU_TAG, MenuTag::class.java) as MenuTag
+ } else {
+ requireArguments().getSerializable(KEY_MENU_TAG) as MenuTag
+ }
+
+ presenter = ProfileDialogPresenter(this, menuTag)
+
+ super.onCreate(savedInstanceState)
+ }
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ _binding = DialogInputProfilesBinding.inflate(inflater, container, false)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ binding.profileList.adapter = ProfileAdapter(context, presenter)
+ binding.profileList.layoutManager = LinearLayoutManager(context)
+ val divider = MaterialDividerItemDecoration(requireActivity(), LinearLayoutManager.VERTICAL)
+ divider.isLastItemDecorated = false
+ binding.profileList.addItemDecoration(divider)
+
+ // You can't expand a bottom sheet with a controller/remote/other non-touch devices
+ val behavior: BottomSheetBehavior<View> = BottomSheetBehavior.from(view.parent as View)
+ if (!resources.getBoolean(R.bool.hasTouch)) {
+ behavior.state = BottomSheetBehavior.STATE_EXPANDED
+ }
+ }
+
+ override fun onDestroyView() {
+ super.onDestroyView()
+ _binding = null
+ }
+
+ companion object {
+ private const val KEY_MENU_TAG = "menu_tag"
+
+ @JvmStatic
+ fun create(menuTag: MenuTag): ProfileDialog {
+ val dialog = ProfileDialog()
+ val args = Bundle()
+ args.putSerializable(KEY_MENU_TAG, menuTag)
+ dialog.arguments = args
+ return dialog
+ }
+ }
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java
new file mode 100644
index 0000000000..ae35aec46d
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileDialogPresenter.java
@@ -0,0 +1,150 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.input.ui;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+
+import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
+
+import com.google.android.material.dialog.MaterialAlertDialogBuilder;
+import com.google.android.material.textfield.TextInputEditText;
+
+import org.dolphinemu.dolphinemu.R;
+import org.dolphinemu.dolphinemu.databinding.DialogInputStringBinding;
+import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag;
+import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivityView;
+import org.dolphinemu.dolphinemu.utils.DirectoryInitialization;
+
+import java.io.File;
+import java.text.Collator;
+import java.util.Arrays;
+
+public final class ProfileDialogPresenter
+{
+ private static final String EXTENSION = ".ini";
+
+ private final Context mContext;
+ private final DialogFragment mDialog;
+ private final MenuTag mMenuTag;
+
+ public ProfileDialogPresenter(DialogFragment dialog, MenuTag menuTag)
+ {
+ mContext = dialog.getContext();
+ mDialog = dialog;
+ mMenuTag = menuTag;
+ }
+
+ public String[] getProfileNames(boolean stock)
+ {
+ File[] profiles = new File(getProfileDirectoryPath(stock)).listFiles(
+ file -> !file.isDirectory() && file.getName().endsWith(EXTENSION));
+
+ if (profiles == null)
+ return new String[0];
+
+ return Arrays.stream(profiles)
+ .map(file -> file.getName().substring(0, file.getName().length() - EXTENSION.length()))
+ .sorted(Collator.getInstance())
+ .toArray(String[]::new);
+ }
+
+ public void loadProfile(@NonNull String profileName, boolean stock)
+ {
+ new MaterialAlertDialogBuilder(mContext)
+ .setMessage(mContext.getString(R.string.input_profile_confirm_load, profileName))
+ .setPositiveButton(R.string.yes, (dialogInterface, i) ->
+ {
+ mMenuTag.getCorrespondingEmulatedController()
+ .loadProfile(getProfilePath(profileName, stock));
+ ((SettingsActivityView) mDialog.requireActivity()).onControllerSettingsChanged();
+ mDialog.dismiss();
+ })
+ .setNegativeButton(R.string.no, null)
+ .show();
+ }
+
+ public void saveProfile(@NonNull String profileName)
+ {
+ // If the user is saving over an existing profile, we should show an overwrite warning.
+ // If the user is creating a new profile, we normally shouldn't show a warning,
+ // but if they've entered the name of an existing profile, we should shown an overwrite warning.
+
+ String profilePath = getProfilePath(profileName, false);
+ if (!new File(profilePath).exists())
+ {
+ mMenuTag.getCorrespondingEmulatedController().saveProfile(profilePath);
+ mDialog.dismiss();
+ }
+ else
+ {
+ new MaterialAlertDialogBuilder(mContext)
+ .setMessage(mContext.getString(R.string.input_profile_confirm_save, profileName))
+ .setPositiveButton(R.string.yes, (dialogInterface, i) ->
+ {
+ mMenuTag.getCorrespondingEmulatedController().saveProfile(profilePath);
+ mDialog.dismiss();
+ })
+ .setNegativeButton(R.string.no, null)
+ .show();
+ }
+ }
+
+ public void saveProfileAndPromptForName()
+ {
+ LayoutInflater inflater = LayoutInflater.from(mContext);
+
+ DialogInputStringBinding binding = DialogInputStringBinding.inflate(inflater);
+ TextInputEditText input = binding.input;
+
+ new MaterialAlertDialogBuilder(mContext)
+ .setView(binding.getRoot())
+ .setPositiveButton(R.string.ok, (dialogInterface, i) ->
+ saveProfile(input.getText().toString()))
+ .setNegativeButton(R.string.cancel, null)
+ .show();
+ }
+
+ public void deleteProfile(@NonNull String profileName)
+ {
+ new MaterialAlertDialogBuilder(mContext)
+ .setMessage(mContext.getString(R.string.input_profile_confirm_delete, profileName))
+ .setPositiveButton(R.string.yes, (dialogInterface, i) ->
+ {
+ new File(getProfilePath(profileName, false)).delete();
+ mDialog.dismiss();
+ })
+ .setNegativeButton(R.string.no, null)
+ .show();
+ }
+
+ private String getProfileDirectoryName()
+ {
+ if (mMenuTag.isGCPadMenu())
+ return "GCPad";
+ else if (mMenuTag.isWiimoteMenu())
+ return "Wiimote";
+ else
+ throw new UnsupportedOperationException();
+ }
+
+ private String getProfileDirectoryPath(boolean stock)
+ {
+ if (stock)
+ {
+ return DirectoryInitialization.getSysDirectory() + "/Profiles/" + getProfileDirectoryName() +
+ '/';
+ }
+ else
+ {
+ return DirectoryInitialization.getUserDirectory() + "/Config/Profiles/" +
+ getProfileDirectoryName() + '/';
+ }
+ }
+
+ private String getProfilePath(String profileName, boolean stock)
+ {
+ return getProfileDirectoryPath(stock) + profileName + EXTENSION;
+ }
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileViewHolder.java
new file mode 100644
index 0000000000..d4d40c0c65
--- /dev/null
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/input/ui/ProfileViewHolder.java
@@ -0,0 +1,76 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+package org.dolphinemu.dolphinemu.features.input.ui;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.RecyclerView;
+
+import org.dolphinemu.dolphinemu.R;
+import org.dolphinemu.dolphinemu.databinding.ListItemProfileBinding;
+
+public class ProfileViewHolder extends RecyclerView.ViewHolder
+{
+ private final ProfileDialogPresenter mPresenter;
+ private final ListItemProfileBinding mBinding;
+
+ private String mProfileName;
+ private boolean mStock;
+
+ public ProfileViewHolder(@NonNull ProfileDialogPresenter presenter,
+ @NonNull ListItemProfileBinding binding)
+ {
+ super(binding.getRoot());
+
+ mPresenter = presenter;
+ mBinding = binding;
+
+ binding.buttonLoad.setOnClickListener(view -> loadProfile());
+ binding.buttonSave.setOnClickListener(view -> saveProfile());
+ binding.buttonDelete.setOnClickListener(view -> deleteProfile());
+ }
+
+ public void bind(String profileName, boolean stock)
+ {
+ mProfileName = profileName;
+ mStock = stock;
+
+ mBinding.textName.setText(profileName);
+
+ mBinding.buttonLoad.setVisibility(View.VISIBLE);
+ mBinding.buttonSave.setVisibility(stock ? View.GONE : View.VISIBLE);
+ mBinding.buttonDelete.setVisibility(stock ? View.GONE : View.VISIBLE);
+ }
+
+ public void bindAsEmpty(Context context)
+ {
+ mProfileName = null;
+ mStock = false;
+
+ mBinding.textName.setText(context.getText(R.string.input_profile_new));
+
+ mBinding.buttonLoad.setVisibility(View.GONE);
+ mBinding.buttonSave.setVisibility(View.VISIBLE);
+ mBinding.buttonDelete.setVisibility(View.GONE);
+ }
+
+ private void loadProfile()
+ {
+ mPresenter.loadProfile(mProfileName, mStock);
+ }
+
+ private void saveProfile()
+ {
+ if (mProfileName == null)
+ mPresenter.saveProfileAndPromptForName();
+ else
+ mPresenter.saveProfile(mProfileName);
+ }
+
+ private void deleteProfile()
+ {
+ mPresenter.deleteProfile(mProfileName);
+ }
+}
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java
index f97a013074..a0a67dd838 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/MenuTag.java
@@ -4,6 +4,8 @@ package org.dolphinemu.dolphinemu.features.settings.ui;
import androidx.annotation.NonNull;
+import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedController;
+
public enum MenuTag
{
SETTINGS("settings"),
@@ -88,6 +90,16 @@ public enum MenuTag
return subType;
}
+ public EmulatedController getCorrespondingEmulatedController()
+ {
+ if (isGCPadMenu())
+ return EmulatedController.getGcPad(getSubType());
+ else if (isWiimoteMenu())
+ return EmulatedController.getWiimote(getSubType());
+ else
+ throw new UnsupportedOperationException();
+ }
+
public boolean isSerialPort1Menu()
{
return this == CONFIG_SERIALPORT1;
@@ -143,7 +155,8 @@ public enum MenuTag
{
for (MenuTag menuTag : MenuTag.values())
{
- if (menuTag.tag.equals(tag) && menuTag.subType == subtype) return menuTag;
+ if (menuTag.tag.equals(tag) && menuTag.subType == subtype)
+ return menuTag;
}
throw new IllegalArgumentException("You are asking for a menu that is not available or " +
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java
index d4ec285681..bce24c1c46 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivity.java
@@ -19,6 +19,7 @@ import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowCompat;
import androidx.core.view.WindowInsetsCompat;
+import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentTransaction;
import androidx.lifecycle.ViewModelProvider;
@@ -44,6 +45,7 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
private static final String ARG_IS_WII = "is_wii";
private static final String KEY_MAPPING_ALL_DEVICES = "all_devices";
private static final String FRAGMENT_TAG = "settings";
+ private static final String FRAGMENT_DIALOG_TAG = "settings_dialog";
private SettingsActivityPresenter mPresenter;
private AlertDialog dialog;
@@ -191,6 +193,12 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
transaction.commit();
}
+ @Override
+ public void showDialogFragment(DialogFragment fragment)
+ {
+ fragment.show(getSupportFragmentManager(), FRAGMENT_DIALOG_TAG);
+ }
+
private boolean areSystemAnimationsEnabled()
{
float duration = Settings.Global.getFloat(
@@ -315,6 +323,12 @@ public final class SettingsActivity extends AppCompatActivity implements Setting
}
@Override
+ public void onControllerSettingsChanged()
+ {
+ getFragment().onControllerSettingsChanged();
+ }
+
+ @Override
public void onMenuTagAction(@NonNull MenuTag menuTag, int value)
{
mPresenter.onMenuTagAction(menuTag, value);
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java
index 203b14ca4b..464d0ea165 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityView.java
@@ -5,6 +5,7 @@ package org.dolphinemu.dolphinemu.features.settings.ui;
import android.os.Bundle;
import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
@@ -22,6 +23,13 @@ public interface SettingsActivityView
void showSettingsFragment(MenuTag menuTag, Bundle extras, boolean addToStack, String gameId);
/**
+ * Shows a DialogFragment.
+ *
+ * Only one can be shown at a time.
+ */
+ void showDialogFragment(DialogFragment fragment);
+
+ /**
* Called by a contained Fragment to get access to the Setting HashMap
* loaded from disk, so that each Fragment doesn't need to perform its own
* read operation.
@@ -61,6 +69,14 @@ public interface SettingsActivityView
void onSettingChanged();
/**
+ * Refetches the values of all controller settings.
+ *
+ * To be used when loading an input profile or performing some other action that changes all
+ * controller settings at once.
+ */
+ void onControllerSettingsChanged();
+
+ /**
* Called by a containing Fragment to tell the containing Activity that the user wants to open the
* MenuTag associated with a setting.
*
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java
index fcc27c4e5d..5f3202e63e 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragment.java
@@ -13,6 +13,7 @@ import androidx.annotation.Nullable;
import androidx.core.graphics.Insets;
import androidx.core.view.ViewCompat;
import androidx.core.view.WindowInsetsCompat;
+import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -222,6 +223,12 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
}
@Override
+ public void showDialogFragment(DialogFragment fragment)
+ {
+ mActivity.showDialogFragment(fragment);
+ }
+
+ @Override
public void showToastMessage(String message)
{
mActivity.showToastMessage(message);
@@ -240,6 +247,13 @@ public final class SettingsFragment extends Fragment implements SettingsFragment
}
@Override
+ public void onControllerSettingsChanged()
+ {
+ mAdapter.notifyAllSettingsChanged();
+ mPresenter.updateOldControllerSettingsWarningVisibility();
+ }
+
+ @Override
public void onMenuTagAction(@NonNull MenuTag menuTag, int value)
{
mActivity.onMenuTagAction(menuTag, value);
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java
index 6cce1361ec..3d33237439 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentPresenter.java
@@ -24,6 +24,7 @@ import org.dolphinemu.dolphinemu.features.input.model.controlleremu.EmulatedCont
import org.dolphinemu.dolphinemu.features.input.model.controlleremu.NumericSetting;
import org.dolphinemu.dolphinemu.features.input.model.view.InputDeviceSetting;
import org.dolphinemu.dolphinemu.features.input.model.view.InputMappingControlSetting;
+import org.dolphinemu.dolphinemu.features.input.ui.ProfileDialog;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractBooleanSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AbstractIntSetting;
import org.dolphinemu.dolphinemu.features.settings.model.AdHocBooleanSetting;
@@ -1223,6 +1224,9 @@ public final class SettingsFragmentPresenter
sl.add(new RunRunnable(mContext, R.string.input_clear, R.string.input_clear_description,
R.string.input_reset_warning, 0, true, () -> clearControllerSettings(controller)));
+ sl.add(new RunRunnable(mContext, R.string.input_profiles, 0, 0, 0, true,
+ () -> mView.showDialogFragment(ProfileDialog.create(mMenuTag))));
+
updateOldControllerSettingsWarningVisibility(controller);
}
@@ -1293,6 +1297,11 @@ public final class SettingsFragmentPresenter
}
}
+ public void updateOldControllerSettingsWarningVisibility()
+ {
+ updateOldControllerSettingsWarningVisibility(mMenuTag.getCorrespondingEmulatedController());
+ }
+
private void updateOldControllerSettingsWarningVisibility(EmulatedController controller)
{
String defaultDevice = controller.getDefaultDevice();
@@ -1306,15 +1315,13 @@ public final class SettingsFragmentPresenter
private void loadDefaultControllerSettings(EmulatedController controller)
{
controller.loadDefaultSettings();
- mView.getAdapter().notifyAllSettingsChanged();
- updateOldControllerSettingsWarningVisibility(controller);
+ mView.onControllerSettingsChanged();
}
private void clearControllerSettings(EmulatedController controller)
{
controller.clearSettings();
- mView.getAdapter().notifyAllSettingsChanged();
- updateOldControllerSettingsWarningVisibility(controller);
+ mView.onControllerSettingsChanged();
}
private static int getLogVerbosityEntries()
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java
index 53a3010962..809f26f7cc 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsFragmentView.java
@@ -3,6 +3,7 @@
package org.dolphinemu.dolphinemu.features.settings.ui;
import androidx.annotation.NonNull;
+import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentActivity;
import org.dolphinemu.dolphinemu.features.settings.model.Settings;
@@ -55,6 +56,8 @@ public interface SettingsFragmentView
*/
void loadSubMenu(MenuTag menuKey);
+ void showDialogFragment(DialogFragment fragment);
+
/**
* Tell the Fragment to tell the containing activity to display a toast message.
*
@@ -73,6 +76,14 @@ public interface SettingsFragmentView
void onSettingChanged();
/**
+ * Refetches the values of all controller settings.
+ *
+ * To be used when loading an input profile or performing some other action that changes all
+ * controller settings at once.
+ */
+ void onControllerSettingsChanged();
+
+ /**
* Have the fragment tell the containing Activity that the user wants to open the MenuTag
* associated with a setting.
*
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java
index cf85e12740..45f2960bd9 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/DirectoryInitialization.java
@@ -45,6 +45,7 @@ public final class DirectoryInitialization
new MutableLiveData<>(DirectoryInitializationState.NOT_YET_INITIALIZED);
private static volatile boolean areDirectoriesAvailable = false;
private static String userPath;
+ private static String sysPath;
private static boolean isUsingLegacyUserDirectory = false;
public enum DirectoryInitializationState
@@ -153,7 +154,8 @@ public final class DirectoryInitialization
}
// Let the native code know where the Sys directory is.
- SetSysDirectory(sysDirectory.getPath());
+ sysPath = sysDirectory.getPath();
+ SetSysDirectory(sysPath);
}
private static void deleteDirectoryRecursively(@NonNull final File file)
@@ -204,6 +206,16 @@ public final class DirectoryInitialization
return userPath;
}
+ public static String getSysDirectory()
+ {
+ if (!areDirectoriesAvailable)
+ {
+ throw new IllegalStateException(
+ "DirectoryInitialization must run before accessing the Sys directory!");
+ }
+ return sysPath;
+ }
+
public static File getGameListCache(Context context)
{
return new File(context.getExternalCacheDir(), "gamelist.cache");