@@ -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<SettingViewHolder>
implements DialogInterface.OnClickListener, SeekBar.OnSeekBarChangeListener
{
private SettingsFragmentView mView;
private static SettingsFragmentView sView;
private Context mContext;
private ArrayList<SettingsItem> mSettings;

@@ -57,9 +66,14 @@ public final class SettingsAdapter extends RecyclerView.Adapter<SettingViewHolde
private AlertDialog mDialog;
private TextView mTextSliderValue;

// TODO: Properly restore these two on activity recreation
private static FilePicker sFilePicker;
private static SettingsItem sItem;

public SettingsAdapter(SettingsFragmentView view, Context context)
{
mView = view;
sView = view;
mContext = context;
mClickedPosition = -1;
}
@@ -102,6 +116,14 @@ public SettingViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new RumbleBindingViewHolder(view, this, mContext);

case SettingsItem.TYPE_FILE_PICKER:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new FilePickerViewHolder(view, this);

case SettingsItem.TYPE_CONFIRM_RUNNABLE:
view = inflater.inflate(R.layout.list_item_setting, parent, false);
return new ConfirmRunnableViewHolder(view, this, mContext, mView);

default:
Log.error("[SettingsAdapter] Invalid view type: " + viewType);
return null;
@@ -274,6 +296,72 @@ public void onInputBindingClick(final InputBindingSetting item, final int positi
dialog.show();
}

public void onFilePickerDirectoryClick(SettingsItem item)
{
sFilePicker = (FilePicker) item;
sItem = item;

FileBrowserHelper.openDirectoryPicker(mView.getActivity(), FileBrowserHelper.GAME_EXTENSIONS);
}

public void onFilePickerFileClick(SettingsItem item)
{
sFilePicker = (FilePicker) item;
sItem = item;

HashSet<String> 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)
{
@@ -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);
}

}
@@ -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<SettingsItem> 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<SettingsItem> sl)
onScreenDisplayMessages));
}

private void addPathsSettings(ArrayList<SettingsItem> 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<SettingsItem> 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";
}
}
@@ -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();
}
}
@@ -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);
}
}
}
@@ -54,6 +54,12 @@
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";
@@ -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<String> 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<String> mExtensions;

public void setExtensions(HashSet<String> 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<String>) 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
@@ -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)
{
@@ -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;
@@ -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)
{
@@ -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<String> GAME_EXTENSIONS = new HashSet<>(Arrays.asList(
"gcm", "tgc", "iso", "ciso", "gcz", "wbfs", "wad", "dol", "elf", "dff"));

public static final HashSet<String> RAW_EXTENSION = new HashSet<>(Collections.singletonList(
"raw"));

public static void openDirectoryPicker(FragmentActivity activity, HashSet<String> 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<String> 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<Uri> files = Utils.getSelectedFilesFromResult(result);
@@ -337,13 +337,15 @@

<string-array name="gameSettingsMenusGC">
<item>Details</item>
<item>Set as Default ISO</item>
<item>Core Settings</item>
<item>GFX Settings</item>
<item>GameCube Controller Settings</item>
<item>Clear Game Settings</item>
</string-array>
<string-array name="gameSettingsMenusWii">
<item>Details</item>
<item>Set as Default ISO</item>
<item>Core Settings</item>
<item>GFX Settings</item>
<item>GameCube Controller Settings</item>
@@ -162,6 +162,17 @@
<string name="osd_messages">Show On-Screen Display Messages</string>
<string name="osd_messages_description">Display messages over the emulation screen area. These messages include memory card writes, video backend and CPU information, and JIT cache clearing.</string>

<!-- Path Settings -->
<string name="paths_submenu">Paths</string>
<string name="default_ISO">Default ISO</string>
<string name="wii_NAND_root">Wii NAND Root</string>
<string name="dump_path">Dump Path</string>
<string name="load_path">Load Path</string>
<string name="resource_pack_path">Resource Pack Path</string>
<string name="SD_card_path">SD Card Path</string>
<string name="reset_paths">Reset Paths to Default Settings</string>
<string name="reset_paths_confirmation">Are you sure you want to reset Paths to default settings?</string>

<!-- Graphics Settings -->
<string name="graphics_general">General</string>
<string name="graphics_enhancements_and_hacks">Enhancements &amp; Hacks</string>