diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/CustomFilePickerActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/CustomFilePickerActivity.java index f715766bffa0..0edf7aea17bd 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/CustomFilePickerActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/CustomFilePickerActivity.java @@ -1,5 +1,7 @@ package org.dolphinemu.dolphinemu.activities; +import android.content.Intent; +import android.os.Bundle; import android.os.Environment; import androidx.annotation.Nullable; @@ -10,21 +12,38 @@ import org.dolphinemu.dolphinemu.fragments.CustomFilePickerFragment; import java.io.File; +import java.util.HashSet; public class CustomFilePickerActivity extends FilePickerActivity - { + public static final String EXTRA_EXTENSIONS = "dolphinemu.org.filepicker.extensions"; + + private HashSet mExtensions; + + @Override + protected void onCreate(Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + + Intent intent = getIntent(); + if (intent != null) + { + mExtensions = (HashSet) intent.getSerializableExtra(EXTRA_EXTENSIONS); + } + } + @Override protected AbstractFilePickerFragment getFragment( @Nullable final String startPath, final int mode, final boolean allowMultiple, final boolean allowCreateDir, final boolean allowExistingFile, final boolean singleClick) { - AbstractFilePickerFragment fragment = new CustomFilePickerFragment(); + CustomFilePickerFragment fragment = new CustomFilePickerFragment(); // startPath is allowed to be null. In that case, default folder should be SD-card and not "/" fragment.setArgs( startPath != null ? startPath : Environment.getExternalStorageDirectory().getPath(), mode, allowMultiple, allowCreateDir, allowExistingFile, singleClick); + fragment.setExtensions(mExtensions); return fragment; } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java index 334ecb671c27..aaad6b725037 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/activities/EmulationActivity.java @@ -25,7 +25,6 @@ import android.view.Menu; import android.view.MenuItem; import android.view.MotionEvent; -import android.view.Surface; import android.view.View; import android.widget.SeekBar; import android.widget.TextView; @@ -411,7 +410,7 @@ protected void onActivityResult(int requestCode, int resultCode, Intent result) // If the user picked a file, as opposed to just backing out. if (resultCode == MainActivity.RESULT_OK) { - String newDiscPath = FileBrowserHelper.getSelectedDirectory(result); + String newDiscPath = FileBrowserHelper.getSelectedPath(result); if (!TextUtils.isEmpty(newDiscPath)) { NativeLibrary.ChangeDisc(newDiscPath); @@ -643,7 +642,8 @@ public void handleMenuAction(@MenuAction int menuAction) return; case MENU_ACTION_CHANGE_DISC: - FileBrowserHelper.openFilePicker(this, REQUEST_CHANGE_DISC, false); + FileBrowserHelper.openFilePicker(this, REQUEST_CHANGE_DISC, false, + FileBrowserHelper.GAME_EXTENSIONS); return; case MENU_SET_IR_SENSITIVITY: diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GamePropertiesDialog.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GamePropertiesDialog.java index f5f6ea5eaea4..aa6fc806d95c 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GamePropertiesDialog.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/dialogs/GamePropertiesDialog.java @@ -10,9 +10,12 @@ import android.widget.Toast; +import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.ui.MenuTag; import org.dolphinemu.dolphinemu.features.settings.ui.SettingsActivity; +import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; import org.dolphinemu.dolphinemu.ui.platform.Platform; import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; @@ -61,22 +64,28 @@ public Dialog onCreateDialog(Bundle savedInstanceState) .getSupportFragmentManager(), "game_details"); break; case 1: - SettingsActivity.launch(getContext(), MenuTag.CONFIG, gameId); + NativeLibrary.SetConfig(SettingsFile.FILE_NAME_DOLPHIN + ".ini", + Settings.SECTION_INI_CORE, SettingsFile.KEY_DEFAULT_ISO, path); + NativeLibrary.ReloadConfig(); + Toast.makeText(getContext(), "Default ISO set", Toast.LENGTH_SHORT).show(); break; case 2: - SettingsActivity.launch(getContext(), MenuTag.GRAPHICS, gameId); + SettingsActivity.launch(getContext(), MenuTag.CONFIG, gameId); break; case 3: - SettingsActivity.launch(getContext(), MenuTag.GCPAD_TYPE, gameId); + SettingsActivity.launch(getContext(), MenuTag.GRAPHICS, gameId); break; case 4: + SettingsActivity.launch(getContext(), MenuTag.GCPAD_TYPE, gameId); + break; + case 5: // Clear option for GC, Wii controls for else if (platform == Platform.GAMECUBE.toInt()) clearGameSettings(gameId); else SettingsActivity.launch(getActivity(), MenuTag.WIIMOTE, gameId); break; - case 5: + case 6: clearGameSettings(gameId); break; } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java index ce3e82aa9d17..fcbf6c60edc1 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/Settings.java @@ -8,13 +8,13 @@ import java.util.Arrays; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.TreeMap; public class Settings { + public static final String SECTION_INI_GENERAL = "General"; public static final String SECTION_INI_CORE = "Core"; public static final String SECTION_INI_INTERFACE = "Interface"; public static final String SECTION_INI_DSP = "DSP"; @@ -42,7 +42,8 @@ public class Settings static { configFileSectionsMap.put(SettingsFile.FILE_NAME_DOLPHIN, - Arrays.asList(SECTION_INI_CORE, SECTION_INI_INTERFACE, SECTION_INI_DSP, + Arrays.asList(SECTION_INI_GENERAL, SECTION_INI_CORE, SECTION_INI_INTERFACE, + SECTION_INI_DSP, SECTION_BINDINGS, SECTION_ANALYTICS, SECTION_DEBUG)); configFileSectionsMap.put(SettingsFile.FILE_NAME_GFX, Arrays.asList(SECTION_GFX_SETTINGS, SECTION_GFX_ENHANCEMENTS, SECTION_GFX_HACKS, diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/ConfirmRunnable.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/ConfirmRunnable.java new file mode 100644 index 000000000000..4950778b64ad --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/ConfirmRunnable.java @@ -0,0 +1,38 @@ +package org.dolphinemu.dolphinemu.features.settings.model.view; + +public final class ConfirmRunnable extends SettingsItem +{ + private int mAlertText; + private int mConfirmationText; + private Runnable mRunnable; + + public ConfirmRunnable(int titleId, int descriptionId, int alertText, int confirmationText, + Runnable runnable) + { + super(null, null, null, titleId, descriptionId); + mAlertText = alertText; + mConfirmationText = confirmationText; + mRunnable = runnable; + } + + public int getAlertText() + { + return mAlertText; + } + + public int getConfirmationText() + { + return mConfirmationText; + } + + public Runnable getRunnable() + { + return mRunnable; + } + + @Override + public int getType() + { + return TYPE_CONFIRM_RUNNABLE; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/FilePicker.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/FilePicker.java new file mode 100644 index 000000000000..ad9456a9cc5e --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/FilePicker.java @@ -0,0 +1,50 @@ +package org.dolphinemu.dolphinemu.features.settings.model.view; + +import org.dolphinemu.dolphinemu.features.settings.model.Setting; +import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; + +public final class FilePicker extends SettingsItem +{ + private String mFile; + private String mDefaultValue; + private int mRequestType; + + public FilePicker(String file, String key, String section, int titleId, int descriptionId, + String defaultVault, int requestType, Setting setting) + { + super(key, section, setting, titleId, descriptionId); + mFile = file; + mDefaultValue = defaultVault; + mRequestType = requestType; + } + + public String getFile() + { + return mFile + ".ini"; + } + + public String getSelectedValue() + { + StringSetting setting = (StringSetting) getSetting(); + + if (setting == null) + { + return mDefaultValue; + } + else + { + return setting.getValue(); + } + } + + public int getRequestType() + { + return mRequestType; + } + + @Override + public int getType() + { + return TYPE_FILE_PICKER; + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java index 944d7f1491e9..c56293fcdf81 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/model/view/SettingsItem.java @@ -21,6 +21,8 @@ public abstract class SettingsItem public static final int TYPE_STRING_SINGLE_CHOICE = 6; public static final int TYPE_RUMBLE_BINDING = 7; public static final int TYPE_SINGLE_CHOICE_DYNAMIC_DESCRIPTIONS = 8; + public static final int TYPE_FILE_PICKER = 9; + public static final int TYPE_CONFIRM_RUNNABLE = 10; private String mKey; private String mSection; 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 a88219b4a1cd..ef7aca9f047d 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 @@ -5,6 +5,7 @@ public enum MenuTag CONFIG("config"), CONFIG_GENERAL("config_general"), CONFIG_INTERFACE("config_interface"), + CONFIG_PATHS("config_paths"), CONFIG_GAME_CUBE("config_gamecube"), CONFIG_WII("config_wii"), WIIMOTE("wiimote"), 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 85ab6d328b95..bfaf6daf80eb 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,8 +19,10 @@ import android.widget.Toast; import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.ui.main.MainActivity; import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; import org.dolphinemu.dolphinemu.utils.DirectoryStateReceiver; +import org.dolphinemu.dolphinemu.utils.FileBrowserHelper; public final class SettingsActivity extends AppCompatActivity implements SettingsActivityView { @@ -154,6 +156,32 @@ public void stopListeningToDirectoryInitializationService(DirectoryStateReceiver LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver); } + @Override + protected void onActivityResult(int requestCode, int resultCode, Intent result) + { + super.onActivityResult(requestCode, resultCode, result); + + // Save modified non-FilePicker settings beforehand since finish() won't save them. + // onStop() must come before handling the resultCode to properly save FilePicker selection. + mPresenter.onStop(true); + + // If the user picked a file, as opposed to just backing out. + if (resultCode == MainActivity.RESULT_OK) + { + mPresenter.onFileConfirmed(FileBrowserHelper.getSelectedPath(result)); + + // Prevent duplicate Toasts. + if (!mPresenter.shouldSave()) + { + Toast.makeText(this, "Saved settings to INI files", Toast.LENGTH_SHORT).show(); + } + } + + // TODO: After result of FilePicker, duplicate SettingsActivity appears. + // Finish to avoid this. Is there a better method? + finish(); + } + @Override public void showLoading() { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityPresenter.java index 21115e464d39..77ce9cee9cdf 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsActivityPresenter.java @@ -184,6 +184,11 @@ public void saveState(Bundle outState) outState.putBoolean(KEY_SHOULD_SAVE, mShouldSave); } + public boolean shouldSave() + { + return mShouldSave; + } + public void onGcPadSettingChanged(MenuTag key, int value) { if (value != 0) // Not disabled @@ -217,4 +222,9 @@ public void onExtensionSettingChanged(MenuTag menuTag, int value) mView.showSettingsFragment(menuTag, bundle, true, gameId); } } + + public void onFileConfirmed(String file) + { + SettingsAdapter.onFilePickerConfirmation(file); + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java index cc7f586105ae..f11a183626ec 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/SettingsAdapter.java @@ -14,6 +14,7 @@ import android.widget.SeekBar; import android.widget.TextView; +import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.dialogs.MotionAlertDialog; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; @@ -22,6 +23,7 @@ import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting; +import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker; import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.RumbleBindingSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; @@ -31,6 +33,8 @@ import org.dolphinemu.dolphinemu.features.settings.model.view.StringSingleChoiceSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SubmenuSetting; import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.CheckBoxSettingViewHolder; +import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.ConfirmRunnableViewHolder; +import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.FilePickerViewHolder; import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.HeaderViewHolder; import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.InputBindingSettingViewHolder; import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.RumbleBindingViewHolder; @@ -39,14 +43,19 @@ import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SliderViewHolder; import org.dolphinemu.dolphinemu.features.settings.ui.viewholder.SubmenuViewHolder; import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; +import org.dolphinemu.dolphinemu.ui.main.MainPresenter; +import org.dolphinemu.dolphinemu.utils.FileBrowserHelper; import org.dolphinemu.dolphinemu.utils.Log; +import java.security.InvalidParameterException; import java.util.ArrayList; +import java.util.HashSet; public final class SettingsAdapter extends RecyclerView.Adapter implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener { private SettingsFragmentView mView; + private static SettingsFragmentView sView; private Context mContext; private ArrayList mSettings; @@ -57,9 +66,14 @@ public final class SettingsAdapter extends RecyclerView.Adapter extensions; + switch (sFilePicker.getRequestType()) + { + case MainPresenter.REQUEST_SD_FILE: + extensions = FileBrowserHelper.RAW_EXTENSION; + break; + case MainPresenter.REQUEST_GAME_FILE: + extensions = FileBrowserHelper.GAME_EXTENSIONS; + break; + default: + throw new InvalidParameterException("Unhandled request code"); + } + + FileBrowserHelper.openFilePicker(mView.getActivity(), sFilePicker.getRequestType(), false, + extensions); + } + + public static void onFilePickerConfirmation(String file) + { + NativeLibrary.SetConfig(sFilePicker.getFile(), sItem.getSection(), sItem.getKey(), file); + NativeLibrary.ReloadConfig(); + } + + public static void resetPaths() + { + StringSetting defaultISO = + new StringSetting(SettingsFile.KEY_DEFAULT_ISO, Settings.SECTION_INI_CORE, ""); + StringSetting NANDRootPath = + new StringSetting(SettingsFile.KEY_NAND_ROOT_PATH, Settings.SECTION_INI_GENERAL, + SettingsFragmentPresenter.getDefaultNANDRootPath()); + StringSetting dumpPath = + new StringSetting(SettingsFile.KEY_DUMP_PATH, Settings.SECTION_INI_GENERAL, + SettingsFragmentPresenter.getDefaultDumpPath()); + StringSetting loadPath = + new StringSetting(SettingsFile.KEY_LOAD_PATH, Settings.SECTION_INI_GENERAL, + SettingsFragmentPresenter.getDefaultLoadPath()); + StringSetting resourcePackPath = + new StringSetting(SettingsFile.KEY_RESOURCE_PACK_PATH, Settings.SECTION_INI_GENERAL, + SettingsFragmentPresenter.getDefaultResourcePackPath()); + StringSetting sdPath = + new StringSetting(SettingsFile.KEY_WII_SD_CARD_PATH, Settings.SECTION_INI_GENERAL, + SettingsFragmentPresenter.getDefaultSDPath()); + + sView.putSetting(defaultISO); + sView.putSetting(NANDRootPath); + sView.putSetting(dumpPath); + sView.putSetting(loadPath); + sView.putSetting(resourcePackPath); + sView.putSetting(sdPath); + + sView.onSettingChanged(); + } + @Override public void onClick(DialogInterface dialog, int which) { 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 8e9816d54489..0fdafbb89064 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 @@ -1,6 +1,5 @@ package org.dolphinemu.dolphinemu.features.settings.ui; -import android.app.Activity; import android.content.Context; import android.os.Bundle; @@ -39,6 +38,7 @@ public final class SettingsFragment extends Fragment implements SettingsFragment titles.put(MenuTag.CONFIG, R.string.preferences_settings); titles.put(MenuTag.CONFIG_GENERAL, R.string.general_submenu); titles.put(MenuTag.CONFIG_INTERFACE, R.string.interface_submenu); + titles.put(MenuTag.CONFIG_PATHS, R.string.paths_submenu); titles.put(MenuTag.CONFIG_GAME_CUBE, R.string.gamecube_submenu); titles.put(MenuTag.CONFIG_WII, R.string.wii_submenu); titles.put(MenuTag.WIIMOTE, R.string.grid_menu_wiimote_settings); @@ -217,5 +217,4 @@ public void onExtensionSettingChanged(MenuTag menuTag, int value) { mActivity.onExtensionSettingChanged(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 1b2b4ddad5fc..d0db5c8a1cc6 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 @@ -3,7 +3,6 @@ import android.os.Bundle; import android.text.TextUtils; -import org.dolphinemu.dolphinemu.DolphinApplication; import org.dolphinemu.dolphinemu.NativeLibrary; import org.dolphinemu.dolphinemu.R; import org.dolphinemu.dolphinemu.features.settings.model.BooleanSetting; @@ -13,6 +12,8 @@ import org.dolphinemu.dolphinemu.features.settings.model.Settings; import org.dolphinemu.dolphinemu.features.settings.model.StringSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.CheckBoxSetting; +import org.dolphinemu.dolphinemu.features.settings.model.view.ConfirmRunnable; +import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker; import org.dolphinemu.dolphinemu.features.settings.model.view.HeaderSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.InputBindingSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.RumbleBindingSetting; @@ -23,10 +24,10 @@ import org.dolphinemu.dolphinemu.features.settings.model.view.StringSingleChoiceSetting; import org.dolphinemu.dolphinemu.features.settings.model.view.SubmenuSetting; import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; +import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import org.dolphinemu.dolphinemu.utils.DirectoryInitialization; import org.dolphinemu.dolphinemu.utils.EGLHelper; import org.dolphinemu.dolphinemu.utils.Log; -import org.dolphinemu.dolphinemu.utils.TvUtil; import java.io.File; import java.util.ArrayList; @@ -135,6 +136,10 @@ private void loadSettingsList() addInterfaceSettings(sl); break; + case CONFIG_PATHS: + addPathsSettings(sl); + break; + case CONFIG_GAME_CUBE: addGameCubeSettings(sl); break; @@ -205,6 +210,7 @@ private void addConfigSettings(ArrayList sl) { sl.add(new SubmenuSetting(null, null, R.string.general_submenu, 0, MenuTag.CONFIG_GENERAL)); sl.add(new SubmenuSetting(null, null, R.string.interface_submenu, 0, MenuTag.CONFIG_INTERFACE)); + sl.add(new SubmenuSetting(null, null, R.string.paths_submenu, 0, MenuTag.CONFIG_PATHS)); sl.add(new SubmenuSetting(null, null, R.string.gamecube_submenu, 0, MenuTag.CONFIG_GAME_CUBE)); sl.add(new SubmenuSetting(null, null, R.string.wii_submenu, 0, MenuTag.CONFIG_WII)); @@ -307,6 +313,47 @@ private void addInterfaceSettings(ArrayList sl) onScreenDisplayMessages)); } + private void addPathsSettings(ArrayList sl) + { + Setting defaultISO = null; + Setting NANDRootPath = null; + Setting dumpPath = null; + Setting loadPath = null; + Setting resourcePackPath = null; + Setting wiiSDCardPath = null; + + SettingSection coreSection = mSettings.getSection(Settings.SECTION_INI_CORE); + SettingSection generalSection = mSettings.getSection(Settings.SECTION_INI_GENERAL); + defaultISO = coreSection.getSetting(SettingsFile.KEY_DEFAULT_ISO); + NANDRootPath = generalSection.getSetting(SettingsFile.KEY_NAND_ROOT_PATH); + dumpPath = generalSection.getSetting(SettingsFile.KEY_DUMP_PATH); + loadPath = generalSection.getSetting(SettingsFile.KEY_LOAD_PATH); + resourcePackPath = generalSection.getSetting(SettingsFile.KEY_RESOURCE_PACK_PATH); + wiiSDCardPath = generalSection.getSetting(SettingsFile.KEY_WII_SD_CARD_PATH); + + sl.add(new FilePicker(SettingsFile.FILE_NAME_DOLPHIN, SettingsFile.KEY_DEFAULT_ISO, + Settings.SECTION_INI_CORE, R.string.default_ISO, 0, "", + MainPresenter.REQUEST_GAME_FILE, defaultISO)); + sl.add(new FilePicker(SettingsFile.FILE_NAME_DOLPHIN, SettingsFile.KEY_NAND_ROOT_PATH, + Settings.SECTION_INI_GENERAL, R.string.wii_NAND_root, 0, getDefaultNANDRootPath(), + MainPresenter.REQUEST_DIRECTORY, NANDRootPath)); + sl.add(new FilePicker(SettingsFile.FILE_NAME_DOLPHIN, SettingsFile.KEY_DUMP_PATH, + Settings.SECTION_INI_GENERAL, R.string.dump_path, 0, getDefaultDumpPath(), + MainPresenter.REQUEST_DIRECTORY, dumpPath)); + sl.add(new FilePicker(SettingsFile.FILE_NAME_DOLPHIN, SettingsFile.KEY_LOAD_PATH, + Settings.SECTION_INI_GENERAL, R.string.load_path, 0, getDefaultLoadPath(), + MainPresenter.REQUEST_DIRECTORY, loadPath)); + sl.add(new FilePicker(SettingsFile.FILE_NAME_DOLPHIN, SettingsFile.KEY_RESOURCE_PACK_PATH, + Settings.SECTION_INI_GENERAL, R.string.resource_pack_path, 0, + getDefaultResourcePackPath(), + MainPresenter.REQUEST_DIRECTORY, resourcePackPath)); + sl.add(new FilePicker(SettingsFile.FILE_NAME_DOLPHIN, SettingsFile.KEY_WII_SD_CARD_PATH, + Settings.SECTION_INI_GENERAL, R.string.SD_card_path, 0, getDefaultSDPath(), + MainPresenter.REQUEST_SD_FILE, wiiSDCardPath)); + sl.add(new ConfirmRunnable(R.string.reset_paths, 0, R.string.reset_paths_confirmation, 0, + SettingsAdapter::resetPaths)); + } + private void addGameCubeSettings(ArrayList sl) { Setting systemLanguage = null; @@ -1545,4 +1592,29 @@ else if (extension.equals("Turntable")) return extensionValue; } + + public static String getDefaultNANDRootPath() + { + return DirectoryInitialization.getUserDirectory() + "/Wii"; + } + + public static String getDefaultDumpPath() + { + return DirectoryInitialization.getUserDirectory() + "/Dump"; + } + + public static String getDefaultLoadPath() + { + return DirectoryInitialization.getUserDirectory() + "/Load"; + } + + public static String getDefaultResourcePackPath() + { + return DirectoryInitialization.getUserDirectory() + "/ResourcePacks"; + } + + public static String getDefaultSDPath() + { + return DirectoryInitialization.getUserDirectory() + "/Wii/sd.raw"; + } } diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/ConfirmRunnableViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/ConfirmRunnableViewHolder.java new file mode 100644 index 000000000000..32be613bc2fa --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/ConfirmRunnableViewHolder.java @@ -0,0 +1,87 @@ +package org.dolphinemu.dolphinemu.features.settings.ui.viewholder; + +import android.content.Context; +import android.view.View; +import android.widget.TextView; +import android.widget.Toast; + +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.features.settings.model.view.ConfirmRunnable; +import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; +import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; +import org.dolphinemu.dolphinemu.features.settings.ui.SettingsFragmentView; + +import androidx.appcompat.app.AlertDialog; + +public final class ConfirmRunnableViewHolder extends SettingViewHolder +{ + private ConfirmRunnable mItem; + private SettingsFragmentView mView; + + private Context mContext; + + private TextView mTextSettingName; + private TextView mTextSettingDescription; + + public ConfirmRunnableViewHolder(View itemView, SettingsAdapter adapter, Context context, + SettingsFragmentView view) + { + super(itemView, adapter); + + mContext = context; + mView = view; + } + + @Override + protected void findViews(View root) + { + mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name); + mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description); + } + + @Override + public void bind(SettingsItem item) + { + mItem = (ConfirmRunnable) item; + + mTextSettingName.setText(item.getNameId()); + + if (item.getDescriptionId() > 0) + { + mTextSettingDescription.setText(item.getDescriptionId()); + } + } + + @Override + public void onClick(View clicked) + { + String alertTitle = mContext.getString(mItem.getNameId()); + String alertText = mContext.getString(mItem.getAlertText()); + + AlertDialog.Builder builder = new AlertDialog.Builder(mContext) + .setTitle(alertTitle) + .setMessage(alertText); + + builder + .setPositiveButton("Yes", (dialog, whichButton) -> + { + mItem.getRunnable().run(); + + if (mItem.getConfirmationText() > 0) + { + String confirmationText = mContext.getString(mItem.getConfirmationText()); + Toast.makeText(mContext, confirmationText, Toast.LENGTH_SHORT).show(); + } + dialog.dismiss(); + + // TODO: Remove finish and properly update dynamic settings descriptions. + mView.getActivity().finish(); + }) + .setNegativeButton("No", (dialog, whichButton) -> + { + dialog.dismiss(); + }); + + builder.show(); + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/FilePickerViewHolder.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/FilePickerViewHolder.java new file mode 100644 index 000000000000..b72785756db5 --- /dev/null +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/ui/viewholder/FilePickerViewHolder.java @@ -0,0 +1,66 @@ +package org.dolphinemu.dolphinemu.features.settings.ui.viewholder; + +import android.view.View; +import android.widget.TextView; + +import org.dolphinemu.dolphinemu.NativeLibrary; +import org.dolphinemu.dolphinemu.R; +import org.dolphinemu.dolphinemu.features.settings.model.view.FilePicker; +import org.dolphinemu.dolphinemu.features.settings.model.view.SettingsItem; +import org.dolphinemu.dolphinemu.features.settings.ui.SettingsAdapter; +import org.dolphinemu.dolphinemu.features.settings.utils.SettingsFile; +import org.dolphinemu.dolphinemu.ui.main.MainPresenter; + +public final class FilePickerViewHolder extends SettingViewHolder +{ + private FilePicker mFilePicker; + private SettingsItem mItem; + + private TextView mTextSettingName; + private TextView mTextSettingDescription; + + public FilePickerViewHolder(View itemView, SettingsAdapter adapter) + { + super(itemView, adapter); + } + + @Override + protected void findViews(View root) + { + mTextSettingName = (TextView) root.findViewById(R.id.text_setting_name); + mTextSettingDescription = (TextView) root.findViewById(R.id.text_setting_description); + } + + @Override + public void bind(SettingsItem item) + { + mFilePicker = (FilePicker) item; + mItem = item; + + mTextSettingName.setText(item.getNameId()); + + if (item.getDescriptionId() > 0) + { + mTextSettingDescription.setText(item.getDescriptionId()); + } + else + { + mTextSettingDescription.setText(NativeLibrary + .GetConfig(mFilePicker.getFile(), item.getSection(), item.getKey(), + mFilePicker.getSelectedValue())); + } + } + + @Override + public void onClick(View clicked) + { + if (mFilePicker.getRequestType() == MainPresenter.REQUEST_DIRECTORY) + { + getAdapter().onFilePickerDirectoryClick(mItem); + } + else + { + getAdapter().onFilePickerFileClick(mItem); + } + } +} diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java index 2650efa78898..629dc53be95e 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/features/settings/utils/SettingsFile.java @@ -54,6 +54,12 @@ public final class SettingsFile public static final String KEY_SLOT_A_DEVICE = "SlotA"; public static final String KEY_SLOT_B_DEVICE = "SlotB"; public static final String KEY_ENABLE_SAVE_STATES = "EnableSaveStates"; + public static final String KEY_DEFAULT_ISO = "DefaultISO"; + public static final String KEY_NAND_ROOT_PATH = "NANDRootPath"; + public static final String KEY_DUMP_PATH = "DumpPath"; + public static final String KEY_LOAD_PATH = "LoadPath"; + public static final String KEY_RESOURCE_PACK_PATH = "ResourcePackPath"; + public static final String KEY_WII_SD_CARD_PATH = "WiiSDCardPath"; public static final String KEY_ANALYTICS_ENABLED = "Enabled"; public static final String KEY_ANALYTICS_PERMISSION_ASKED = "PermissionAsked"; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/CustomFilePickerFragment.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/CustomFilePickerFragment.java index 5f20e1032595..5e0e06582cd1 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/CustomFilePickerFragment.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/fragments/CustomFilePickerFragment.java @@ -14,14 +14,23 @@ import com.nononsenseapps.filepicker.FilePickerFragment; import java.io.File; -import java.util.Arrays; import java.util.HashSet; -import java.util.Set; public class CustomFilePickerFragment extends FilePickerFragment { - private static final Set extensions = new HashSet<>(Arrays.asList( - "gcm", "tgc", "iso", "ciso", "gcz", "wbfs", "wad", "dol", "elf", "dff")); + public static final String KEY_EXTENSIONS = "KEY_EXTENSIONS"; + + private HashSet mExtensions; + + public void setExtensions(HashSet extensions) + { + Bundle b = getArguments(); + if (b == null) + b = new Bundle(); + + b.putSerializable(KEY_EXTENSIONS, extensions); + setArguments(b); + } @NonNull @Override @@ -37,6 +46,8 @@ public Uri toUri(@NonNull final File file) { super.onActivityCreated(savedInstanceState); + mExtensions = (HashSet) getArguments().getSerializable(KEY_EXTENSIONS); + if (mode == MODE_DIR) { TextView ok = getActivity().findViewById(R.id.nnf_button_ok); @@ -56,7 +67,7 @@ protected boolean isItemVisible(@NonNull final File file) return (showHiddenItems || !file.isHidden()) && (file.isDirectory() || - extensions.contains(fileExtension(file.getName()).toLowerCase())); + mExtensions.contains(fileExtension(file.getName()).toLowerCase())); } @Override diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java index 87f611cb857f..be1a8a74a2ea 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainActivity.java @@ -145,13 +145,14 @@ public void launchSettingsActivity(MenuTag menuTag) @Override public void launchFileListActivity() { - FileBrowserHelper.openDirectoryPicker(this); + FileBrowserHelper.openDirectoryPicker(this, FileBrowserHelper.GAME_EXTENSIONS); } @Override public void launchOpenFileActivity() { - FileBrowserHelper.openFilePicker(this, MainPresenter.REQUEST_OPEN_FILE, true); + FileBrowserHelper.openFilePicker(this, MainPresenter.REQUEST_GAME_FILE, false, + FileBrowserHelper.GAME_EXTENSIONS); } /** @@ -162,17 +163,18 @@ public void launchOpenFileActivity() @Override protected void onActivityResult(int requestCode, int resultCode, Intent result) { + super.onActivityResult(requestCode, resultCode, result); switch (requestCode) { - case MainPresenter.REQUEST_ADD_DIRECTORY: + case MainPresenter.REQUEST_DIRECTORY: // If the user picked a file, as opposed to just backing out. if (resultCode == MainActivity.RESULT_OK) { - mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result)); + mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedPath(result)); } break; - case MainPresenter.REQUEST_OPEN_FILE: + case MainPresenter.REQUEST_GAME_FILE: // If the user picked a file, as opposed to just backing out. if (resultCode == MainActivity.RESULT_OK) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java index 047e710b7b14..b015df54b43e 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/MainPresenter.java @@ -15,8 +15,9 @@ public final class MainPresenter { - public static final int REQUEST_ADD_DIRECTORY = 1; - public static final int REQUEST_OPEN_FILE = 2; + public static final int REQUEST_DIRECTORY = 1; + public static final int REQUEST_GAME_FILE = 2; + public static final int REQUEST_SD_FILE = 3; private final MainView mView; private final Context mContext; diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java index 2f450ade7a70..1b12b0cb3e27 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/ui/main/TvMainActivity.java @@ -5,7 +5,6 @@ import android.os.Bundle; import androidx.annotation.NonNull; -import androidx.leanback.app.BrowseFragment; import androidx.leanback.app.BrowseSupportFragment; import androidx.leanback.widget.ArrayObjectAdapter; import androidx.leanback.widget.HeaderItem; @@ -141,13 +140,14 @@ public void launchSettingsActivity(MenuTag menuTag) @Override public void launchFileListActivity() { - FileBrowserHelper.openDirectoryPicker(this); + FileBrowserHelper.openDirectoryPicker(this, FileBrowserHelper.GAME_EXTENSIONS); } @Override public void launchOpenFileActivity() { - FileBrowserHelper.openFilePicker(this, MainPresenter.REQUEST_OPEN_FILE, true); + FileBrowserHelper.openFilePicker(this, MainPresenter.REQUEST_GAME_FILE, false, + FileBrowserHelper.GAME_EXTENSIONS); } @Override @@ -169,17 +169,18 @@ public void showGames() @Override protected void onActivityResult(int requestCode, int resultCode, Intent result) { + super.onActivityResult(requestCode, resultCode, result); switch (requestCode) { - case MainPresenter.REQUEST_ADD_DIRECTORY: + case MainPresenter.REQUEST_DIRECTORY: // If the user picked a file, as opposed to just backing out. if (resultCode == MainActivity.RESULT_OK) { - mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedDirectory(result)); + mPresenter.onDirectorySelected(FileBrowserHelper.getSelectedPath(result)); } break; - case MainPresenter.REQUEST_OPEN_FILE: + case MainPresenter.REQUEST_GAME_FILE: // If the user picked a file, as opposed to just backing out. if (resultCode == MainActivity.RESULT_OK) { diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java index 20245deb12e5..ae4a45b8e928 100644 --- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java +++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java @@ -14,11 +14,20 @@ import org.dolphinemu.dolphinemu.ui.main.MainPresenter; import java.io.File; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; import java.util.List; public final class FileBrowserHelper { - public static void openDirectoryPicker(FragmentActivity activity) + public static final HashSet GAME_EXTENSIONS = new HashSet<>(Arrays.asList( + "gcm", "tgc", "iso", "ciso", "gcz", "wbfs", "wad", "dol", "elf", "dff")); + + public static final HashSet RAW_EXTENSION = new HashSet<>(Collections.singletonList( + "raw")); + + public static void openDirectoryPicker(FragmentActivity activity, HashSet extensions) { Intent i = new Intent(activity, CustomFilePickerActivity.class); @@ -27,11 +36,13 @@ public static void openDirectoryPicker(FragmentActivity activity) i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_DIR); i.putExtra(FilePickerActivity.EXTRA_START_PATH, Environment.getExternalStorageDirectory().getPath()); + i.putExtra(CustomFilePickerActivity.EXTRA_EXTENSIONS, extensions); - activity.startActivityForResult(i, MainPresenter.REQUEST_ADD_DIRECTORY); + activity.startActivityForResult(i, MainPresenter.REQUEST_DIRECTORY); } - public static void openFilePicker(FragmentActivity activity, int requestCode, boolean allowMulti) + public static void openFilePicker(FragmentActivity activity, int requestCode, boolean allowMulti, + HashSet extensions) { Intent i = new Intent(activity, CustomFilePickerActivity.class); @@ -40,12 +51,13 @@ public static void openFilePicker(FragmentActivity activity, int requestCode, bo i.putExtra(FilePickerActivity.EXTRA_MODE, FilePickerActivity.MODE_FILE); i.putExtra(FilePickerActivity.EXTRA_START_PATH, Environment.getExternalStorageDirectory().getPath()); + i.putExtra(CustomFilePickerActivity.EXTRA_EXTENSIONS, extensions); activity.startActivityForResult(i, requestCode); } @Nullable - public static String getSelectedDirectory(Intent result) + public static String getSelectedPath(Intent result) { // Use the provided utility method to parse the result List files = Utils.getSelectedFilesFromResult(result); diff --git a/Source/Android/app/src/main/res/values/arrays.xml b/Source/Android/app/src/main/res/values/arrays.xml index fb0200e7534e..b31845642cb2 100644 --- a/Source/Android/app/src/main/res/values/arrays.xml +++ b/Source/Android/app/src/main/res/values/arrays.xml @@ -337,6 +337,7 @@ Details + Set as Default ISO Core Settings GFX Settings GameCube Controller Settings @@ -344,6 +345,7 @@ Details + Set as Default ISO Core Settings GFX Settings GameCube Controller Settings diff --git a/Source/Android/app/src/main/res/values/strings.xml b/Source/Android/app/src/main/res/values/strings.xml index 46883d4ea7db..df006410f172 100644 --- a/Source/Android/app/src/main/res/values/strings.xml +++ b/Source/Android/app/src/main/res/values/strings.xml @@ -162,6 +162,17 @@ Show On-Screen Display Messages Display messages over the emulation screen area. These messages include memory card writes, video backend and CPU information, and JIT cache clearing. + + Paths + Default ISO + Wii NAND Root + Dump Path + Load Path + Resource Pack Path + SD Card Path + Reset Paths to Default Settings + Are you sure you want to reset Paths to default settings? + General Enhancements & Hacks