Android: Add game directory list editor
This commit is contained in:
parent
6a122623fa
commit
59810bf8db
|
@ -14,13 +14,17 @@
|
||||||
android:roundIcon="@mipmap/ic_launcher_round"
|
android:roundIcon="@mipmap/ic_launcher_round"
|
||||||
android:supportsRtl="true"
|
android:supportsRtl="true"
|
||||||
android:theme="@style/AppTheme">
|
android:theme="@style/AppTheme">
|
||||||
|
<activity
|
||||||
|
android:name=".GameDirectoriesActivity"
|
||||||
|
android:label="@string/title_activity_game_directories"
|
||||||
|
android:theme="@style/AppTheme.NoActionBar"></activity>
|
||||||
<activity
|
<activity
|
||||||
android:name=".EmulationActivity"
|
android:name=".EmulationActivity"
|
||||||
android:configChanges="orientation|keyboardHidden|screenSize"
|
android:configChanges="orientation|keyboardHidden|screenSize"
|
||||||
|
android:immersive="true"
|
||||||
android:label="@string/title_activity_emulation"
|
android:label="@string/title_activity_emulation"
|
||||||
android:parentActivityName=".MainActivity"
|
android:parentActivityName=".MainActivity"
|
||||||
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar"
|
android:theme="@style/Theme.AppCompat.DayNight.NoActionBar">
|
||||||
android:immersive="true">
|
|
||||||
<meta-data
|
<meta-data
|
||||||
android:name="android.support.PARENT_ACTIVITY"
|
android:name="android.support.PARENT_ACTIVITY"
|
||||||
android:value="com.github.stenzek.duckstation.MainActivity" />
|
android:value="com.github.stenzek.duckstation.MainActivity" />
|
||||||
|
|
|
@ -677,6 +677,7 @@ public class EmulationActivity extends AppCompatActivity implements SurfaceHolde
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean mSustainedPerformanceModeEnabled = false;
|
private boolean mSustainedPerformanceModeEnabled = false;
|
||||||
|
|
||||||
private void updateSustainedPerformanceMode() {
|
private void updateSustainedPerformanceMode() {
|
||||||
final boolean enabled = getBooleanSetting("Main/SustainedPerformanceMode", false);
|
final boolean enabled = getBooleanSetting("Main/SustainedPerformanceMode", false);
|
||||||
if (mSustainedPerformanceModeEnabled == enabled)
|
if (mSustainedPerformanceModeEnabled == enabled)
|
||||||
|
|
|
@ -0,0 +1,279 @@
|
||||||
|
package com.github.stenzek.duckstation;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.util.Property;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.Menu;
|
||||||
|
import android.view.MenuItem;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.BaseAdapter;
|
||||||
|
import android.widget.EditText;
|
||||||
|
import android.widget.ImageButton;
|
||||||
|
import android.widget.ListAdapter;
|
||||||
|
import android.widget.TextView;
|
||||||
|
import android.widget.Toast;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.Nullable;
|
||||||
|
import androidx.appcompat.app.ActionBar;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.fragment.app.ListFragment;
|
||||||
|
import androidx.preference.PreferenceFragmentCompat;
|
||||||
|
import androidx.preference.PreferenceManager;
|
||||||
|
import androidx.preference.PreferenceScreen;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||||
|
import androidx.viewpager2.widget.ViewPager2;
|
||||||
|
|
||||||
|
import com.google.android.material.tabs.TabLayout;
|
||||||
|
import com.google.android.material.tabs.TabLayoutMediator;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
public class GameDirectoriesActivity extends AppCompatActivity {
|
||||||
|
private static final int REQUEST_ADD_DIRECTORY_TO_GAME_LIST = 1;
|
||||||
|
|
||||||
|
private class DirectoryListAdapter extends RecyclerView.Adapter {
|
||||||
|
private class Entry {
|
||||||
|
private String mPath;
|
||||||
|
private boolean mRecursive;
|
||||||
|
|
||||||
|
public Entry(String path, boolean recursive) {
|
||||||
|
mPath = path;
|
||||||
|
mRecursive = recursive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getPath() {
|
||||||
|
return mPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isRecursive() {
|
||||||
|
return mRecursive;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleRecursive() {
|
||||||
|
mRecursive = !mRecursive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class EntryComparator implements Comparator<Entry> {
|
||||||
|
@Override
|
||||||
|
public int compare(Entry left, Entry right) {
|
||||||
|
return left.getPath().compareTo(right.getPath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Context mContext;
|
||||||
|
private Entry[] mEntries;
|
||||||
|
|
||||||
|
public DirectoryListAdapter(Context context) {
|
||||||
|
mContext = context;
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void reload() {
|
||||||
|
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
|
||||||
|
ArrayList<Entry> entries = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Set<String> paths = prefs.getStringSet("GameList/Paths", null);
|
||||||
|
if (paths != null) {
|
||||||
|
for (String path : paths)
|
||||||
|
entries.add(new Entry(path, false));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Set<String> paths = prefs.getStringSet("GameList/RecursivePaths", null);
|
||||||
|
if (paths != null) {
|
||||||
|
for (String path : paths)
|
||||||
|
entries.add(new Entry(path, true));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
mEntries = new Entry[entries.size()];
|
||||||
|
entries.toArray(mEntries);
|
||||||
|
Arrays.sort(mEntries, new EntryComparator());
|
||||||
|
notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||||
|
private int mPosition;
|
||||||
|
private Entry mEntry;
|
||||||
|
private TextView mPathView;
|
||||||
|
private TextView mRecursiveView;
|
||||||
|
private ImageButton mToggleRecursiveView;
|
||||||
|
private ImageButton mRemoveView;
|
||||||
|
|
||||||
|
public ViewHolder(View rootView) {
|
||||||
|
super(rootView);
|
||||||
|
mPathView = rootView.findViewById(R.id.path);
|
||||||
|
mRecursiveView = rootView.findViewById(R.id.recursive);
|
||||||
|
mToggleRecursiveView = rootView.findViewById(R.id.toggle_recursive);
|
||||||
|
mToggleRecursiveView.setOnClickListener(this);
|
||||||
|
mRemoveView = rootView.findViewById(R.id.remove);
|
||||||
|
mRemoveView.setOnClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void bindData(int position, Entry entry) {
|
||||||
|
mPosition = position;
|
||||||
|
mEntry = entry;
|
||||||
|
updateText();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void updateText() {
|
||||||
|
mPathView.setText(mEntry.getPath());
|
||||||
|
mRecursiveView.setText(getString(mEntry.isRecursive() ? R.string.game_directories_scanning_subdirectories : R.string.game_directories_not_scanning_subdirectories));
|
||||||
|
mToggleRecursiveView.setImageDrawable(getDrawable(mEntry.isRecursive() ? R.drawable.ic_baseline_folder_24 : R.drawable.ic_baseline_folder_open_24));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View v) {
|
||||||
|
if (mToggleRecursiveView == v) {
|
||||||
|
removeSearchDirectory(mContext, mEntry.getPath(), mEntry.isRecursive());
|
||||||
|
mEntry.toggleRecursive();
|
||||||
|
addSearchDirectory(mContext, mEntry.getPath(), mEntry.isRecursive());
|
||||||
|
updateText();
|
||||||
|
} else if (mRemoveView == v) {
|
||||||
|
removeSearchDirectory(mContext, mEntry.getPath(), mEntry.isRecursive());
|
||||||
|
reload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
final View view = LayoutInflater.from(parent.getContext()).inflate(viewType, parent, false);
|
||||||
|
return new ViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||||
|
((ViewHolder) holder).bindData(position, mEntries[position]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return R.layout.layout_game_directory_entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public long getItemId(int position) {
|
||||||
|
return mEntries[position].getPath().hashCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
return mEntries.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DirectoryListAdapter mDirectoryListAdapter;
|
||||||
|
RecyclerView mRecyclerView;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
setContentView(R.layout.activity_game_directories);
|
||||||
|
Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
|
ActionBar actionBar = getSupportActionBar();
|
||||||
|
if (actionBar != null) {
|
||||||
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
mDirectoryListAdapter = new DirectoryListAdapter(this);
|
||||||
|
mRecyclerView = findViewById(R.id.recycler_view);
|
||||||
|
mRecyclerView.setAdapter(mDirectoryListAdapter);
|
||||||
|
mRecyclerView.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
|
||||||
|
findViewById(R.id.fab).setOnClickListener((v) -> startAddGameDirectory());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean onOptionsItemSelected(@NonNull MenuItem item) {
|
||||||
|
if (item.getItemId() == android.R.id.home) {
|
||||||
|
onBackPressed();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return super.onOptionsItemSelected(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getPathFromTreeUri(Context context, Uri treeUri) {
|
||||||
|
String path = FileUtil.getFullPathFromTreeUri(treeUri, context);
|
||||||
|
if (path.length() < 5) {
|
||||||
|
new AlertDialog.Builder(context)
|
||||||
|
.setTitle(R.string.main_activity_error)
|
||||||
|
.setMessage(R.string.main_activity_get_path_from_directory_error)
|
||||||
|
.setPositiveButton(R.string.main_activity_ok, (dialog, button) -> {
|
||||||
|
})
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void addSearchDirectory(Context context, String path, boolean recursive) {
|
||||||
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
final String key = recursive ? "GameList/RecursivePaths" : "GameList/Paths";
|
||||||
|
PreferenceHelpers.addToStringList(prefs, key, path);
|
||||||
|
Log.i("GameDirectoriesActivity", "Added path '" + path + "' to game list search directories");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void removeSearchDirectory(Context context, String path, boolean recursive) {
|
||||||
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
final String key = recursive ? "GameList/RecursivePaths" : "GameList/Paths";
|
||||||
|
PreferenceHelpers.removeFromStringList(prefs, key, path);
|
||||||
|
Log.i("GameDirectoriesActivity", "Removed path '" + path + "' from game list search directories");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void startAddGameDirectory() {
|
||||||
|
Intent i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||||
|
i.addCategory(Intent.CATEGORY_DEFAULT);
|
||||||
|
i.putExtra(Intent.EXTRA_LOCAL_ONLY, true);
|
||||||
|
startActivityForResult(Intent.createChooser(i, getString(R.string.main_activity_choose_directory)),
|
||||||
|
REQUEST_ADD_DIRECTORY_TO_GAME_LIST);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
switch (requestCode) {
|
||||||
|
case REQUEST_ADD_DIRECTORY_TO_GAME_LIST: {
|
||||||
|
if (resultCode != RESULT_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
String path = getPathFromTreeUri(this, data.getData());
|
||||||
|
if (path == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
addSearchDirectory(this, path, true);
|
||||||
|
mDirectoryListAdapter.reload();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,6 +43,7 @@ public class MainActivity extends AppCompatActivity {
|
||||||
private static final int REQUEST_IMPORT_BIOS_IMAGE = 3;
|
private static final int REQUEST_IMPORT_BIOS_IMAGE = 3;
|
||||||
private static final int REQUEST_START_FILE = 4;
|
private static final int REQUEST_START_FILE = 4;
|
||||||
private static final int REQUEST_SETTINGS = 5;
|
private static final int REQUEST_SETTINGS = 5;
|
||||||
|
private static final int REQUEST_EDIT_GAME_DIRECTORIES = 6;
|
||||||
|
|
||||||
private GameList mGameList;
|
private GameList mGameList;
|
||||||
private ListView mGameListView;
|
private ListView mGameListView;
|
||||||
|
@ -209,8 +210,10 @@ public class MainActivity extends AppCompatActivity {
|
||||||
startEmulation(null, false);
|
startEmulation(null, false);
|
||||||
} else if (id == R.id.action_start_file) {
|
} else if (id == R.id.action_start_file) {
|
||||||
startStartFile();
|
startStartFile();
|
||||||
} else if (id == R.id.action_add_game_directory) {
|
} else if (id == R.id.action_edit_game_directories) {
|
||||||
startAddGameDirectory();
|
Intent intent = new Intent(this, GameDirectoriesActivity.class);
|
||||||
|
startActivityForResult(intent, REQUEST_EDIT_GAME_DIRECTORIES);
|
||||||
|
return true;
|
||||||
} else if (id == R.id.action_scan_for_new_games) {
|
} else if (id == R.id.action_scan_for_new_games) {
|
||||||
mGameList.refresh(false, false, this);
|
mGameList.refresh(false, false, this);
|
||||||
} else if (id == R.id.action_rescan_all_games) {
|
} else if (id == R.id.action_rescan_all_games) {
|
||||||
|
@ -255,22 +258,6 @@ public class MainActivity extends AppCompatActivity {
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getPathFromTreeUri(Uri treeUri) {
|
|
||||||
String path = FileUtil.getFullPathFromTreeUri(treeUri, this);
|
|
||||||
if (path.length() < 5) {
|
|
||||||
new AlertDialog.Builder(this)
|
|
||||||
.setTitle(R.string.main_activity_error)
|
|
||||||
.setMessage(R.string.main_activity_get_path_from_directory_error)
|
|
||||||
.setPositiveButton(R.string.main_activity_ok, (dialog, button) -> {
|
|
||||||
})
|
|
||||||
.create()
|
|
||||||
.show();
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
@ -280,20 +267,11 @@ public class MainActivity extends AppCompatActivity {
|
||||||
if (resultCode != RESULT_OK)
|
if (resultCode != RESULT_OK)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
String path = getPathFromTreeUri(data.getData());
|
String path = GameDirectoriesActivity.getPathFromTreeUri(this, data.getData());
|
||||||
if (path == null)
|
if (path == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
|
GameDirectoriesActivity.addSearchDirectory(this, path, true);
|
||||||
Set<String> currentValues = prefs.getStringSet("GameList/RecursivePaths", null);
|
|
||||||
if (currentValues == null)
|
|
||||||
currentValues = new HashSet<String>();
|
|
||||||
|
|
||||||
currentValues.add(path);
|
|
||||||
SharedPreferences.Editor editor = prefs.edit();
|
|
||||||
editor.putStringSet("GameList/RecursivePaths", currentValues);
|
|
||||||
editor.apply();
|
|
||||||
Log.i("MainActivity", "Added path '" + path + "' to game list search directories");
|
|
||||||
mGameList.refresh(false, false, this);
|
mGameList.refresh(false, false, this);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -322,6 +300,11 @@ public class MainActivity extends AppCompatActivity {
|
||||||
loadSettings();
|
loadSettings();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case REQUEST_EDIT_GAME_DIRECTORIES: {
|
||||||
|
mGameList.refresh(false, false, this);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -46,8 +46,14 @@ public class PreferenceHelpers {
|
||||||
|
|
||||||
public static boolean addToStringList(SharedPreferences prefs, String keyName, String valueToAdd) {
|
public static boolean addToStringList(SharedPreferences prefs, String keyName, String valueToAdd) {
|
||||||
Set<String> values = getStringSet(prefs, keyName);
|
Set<String> values = getStringSet(prefs, keyName);
|
||||||
if (values == null)
|
if (values == null) {
|
||||||
values = new ArraySet<>();
|
values = new ArraySet<>();
|
||||||
|
} else {
|
||||||
|
// We need to copy it otherwise the put doesn't save.
|
||||||
|
Set<String> valuesCopy = new ArraySet<>();
|
||||||
|
valuesCopy.addAll(values);
|
||||||
|
values = valuesCopy;
|
||||||
|
}
|
||||||
|
|
||||||
final boolean result = values.add(valueToAdd);
|
final boolean result = values.add(valueToAdd);
|
||||||
prefs.edit().putStringSet(keyName, values).commit();
|
prefs.edit().putStringSet(keyName, values).commit();
|
||||||
|
@ -59,6 +65,11 @@ public class PreferenceHelpers {
|
||||||
if (values == null)
|
if (values == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
// We need to copy it otherwise the put doesn't save.
|
||||||
|
Set<String> valuesCopy = new ArraySet<>();
|
||||||
|
valuesCopy.addAll(values);
|
||||||
|
values = valuesCopy;
|
||||||
|
|
||||||
final boolean result = values.remove(valueToRemove);
|
final boolean result = values.remove(valueToRemove);
|
||||||
prefs.edit().putStringSet(keyName, values).commit();
|
prefs.edit().putStringSet(keyName, values).commit();
|
||||||
return result;
|
return result;
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M6,19c0,1.1 0.9,2 2,2h8c1.1,0 2,-0.9 2,-2V7H6v12zM19,4h-3.5l-1,-1h-5l-1,1H5v2h14V4z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M10,4H4c-1.1,0 -1.99,0.9 -1.99,2L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8c0,-1.1 -0.9,-2 -2,-2h-8l-2,-2z" />
|
||||||
|
</vector>
|
|
@ -0,0 +1,47 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
tools:context=".GameDirectoriesActivity">
|
||||||
|
|
||||||
|
<com.google.android.material.appbar.AppBarLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:theme="@style/AppTheme.AppBarOverlay">
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.Toolbar
|
||||||
|
android:id="@+id/toolbar"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="?attr/actionBarSize"
|
||||||
|
android:background="?attr/colorPrimary"
|
||||||
|
app:popupTheme="@style/AppTheme.PopupOverlay" />
|
||||||
|
|
||||||
|
</com.google.android.material.appbar.AppBarLayout>
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
app:layout_behavior="@string/appbar_scrolling_view_behavior"
|
||||||
|
tools:context=".MainActivity"
|
||||||
|
tools:showIn="@layout/activity_main">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent" />
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||||
|
android:id="@+id/fab"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_gravity="bottom|end"
|
||||||
|
android:layout_margin="@dimen/fab_margin"
|
||||||
|
app:backgroundTint="@color/fab_background"
|
||||||
|
app:srcCompat="@android:drawable/ic_input_add" />
|
||||||
|
|
||||||
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -0,0 +1,51 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/path"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:text="TextView"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/recursive"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginStart="10dp"
|
||||||
|
android:layout_marginTop="4dp"
|
||||||
|
android:layout_marginBottom="4dp"
|
||||||
|
android:layout_below="@id/path"
|
||||||
|
android:layout_alignParentStart="true"
|
||||||
|
android:textAppearance="?android:attr/textAppearanceSmall"
|
||||||
|
android:text="TextView" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/remove"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_alignParentEnd="true"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:background="?android:selectableItemBackground"
|
||||||
|
app:srcCompat="@drawable/ic_baseline_delete_24" />
|
||||||
|
|
||||||
|
<ImageButton
|
||||||
|
android:id="@+id/toggle_recursive"
|
||||||
|
android:layout_width="30dp"
|
||||||
|
android:layout_height="30dp"
|
||||||
|
android:layout_alignParentTop="true"
|
||||||
|
android:layout_marginTop="15dp"
|
||||||
|
android:layout_marginEnd="15dp"
|
||||||
|
android:layout_toStartOf="@id/remove"
|
||||||
|
android:background="?android:selectableItemBackground"
|
||||||
|
app:srcCompat="@drawable/ic_baseline_folder_24" />
|
||||||
|
</RelativeLayout>
|
|
@ -15,8 +15,8 @@
|
||||||
</group>
|
</group>
|
||||||
<group android:id="@+id/game_list">
|
<group android:id="@+id/game_list">
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_add_game_directory"
|
android:id="@+id/action_edit_game_directories"
|
||||||
android:title="@string/menu_main_add_game_directory" />
|
android:title="@string/menu_main_edit_game_directories" />
|
||||||
<item
|
<item
|
||||||
android:id="@+id/action_scan_for_new_games"
|
android:id="@+id/action_scan_for_new_games"
|
||||||
android:title="@string/menu_main_scan_for_new_games" />
|
android:title="@string/menu_main_scan_for_new_games" />
|
||||||
|
|
|
@ -112,7 +112,7 @@
|
||||||
<string name="menu_main_resume_last_session">Resume Last Session</string>
|
<string name="menu_main_resume_last_session">Resume Last Session</string>
|
||||||
<string name="menu_main_start_file">Start File</string>
|
<string name="menu_main_start_file">Start File</string>
|
||||||
<string name="menu_main_start_bios">Start BIOS</string>
|
<string name="menu_main_start_bios">Start BIOS</string>
|
||||||
<string name="menu_main_add_game_directory">Add Game Directory</string>
|
<string name="menu_main_edit_game_directories">Edit Game Directories</string>
|
||||||
<string name="menu_main_scan_for_new_games">Scan For New Games</string>
|
<string name="menu_main_scan_for_new_games">Scan For New Games</string>
|
||||||
<string name="menu_main_rescan_all_games">Rescan All Games</string>
|
<string name="menu_main_rescan_all_games">Rescan All Games</string>
|
||||||
<string name="menu_main_import_bios">Import BIOS</string>
|
<string name="menu_main_import_bios">Import BIOS</string>
|
||||||
|
@ -195,4 +195,9 @@
|
||||||
<string name="settings_summary_general_sync_to_host_refresh_rate">Adjusts the emulation speed so the console\'s refresh rate matches the host\'s refresh rate, when VSync and Audio Resampling is enabled. This results in the smoothest animations possible, at the cost of potentially increasing the emulation speed by less than 1%.</string>
|
<string name="settings_summary_general_sync_to_host_refresh_rate">Adjusts the emulation speed so the console\'s refresh rate matches the host\'s refresh rate, when VSync and Audio Resampling is enabled. This results in the smoothest animations possible, at the cost of potentially increasing the emulation speed by less than 1%.</string>
|
||||||
<string name="settings_sustained_performance_mode">Sustained Performance Mode</string>
|
<string name="settings_sustained_performance_mode">Sustained Performance Mode</string>
|
||||||
<string name="settings_summary_sustained_performance_mode">Enables Android\'s sustained performance mode. May result in more consistent framerates for long sessions on some devices.</string>
|
<string name="settings_summary_sustained_performance_mode">Enables Android\'s sustained performance mode. May result in more consistent framerates for long sessions on some devices.</string>
|
||||||
|
<string name="title_activity_game_directories">Edit Game Directories</string>
|
||||||
|
<string name="settings_game_directories">Game Directories</string>
|
||||||
|
<string name="settings_summary_game_directories">Change the list of directories used to search for games.</string>
|
||||||
|
<string name="game_directories_scanning_subdirectories">Scanning subdirectories.</string>
|
||||||
|
<string name="game_directories_not_scanning_subdirectories">Not scanning subdirectories.</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|
|
@ -14,8 +14,17 @@
|
||||||
~ limitations under the License.
|
~ limitations under the License.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||||
|
<Preference
|
||||||
|
app:title="@string/settings_game_directories"
|
||||||
|
app:summary="@string/settings_summary_game_directories"
|
||||||
|
app:iconSpaceReserved="false">
|
||||||
|
<intent
|
||||||
|
android:action="android.intent.action.VIEW"
|
||||||
|
android:targetClass="com.github.stenzek.duckstation.GameDirectoriesActivity"
|
||||||
|
android:targetPackage="com.github.stenzek.duckstation" />
|
||||||
|
</Preference>
|
||||||
<ListPreference
|
<ListPreference
|
||||||
app:key="Main/EmulationSpeed"
|
app:key="Main/EmulationSpeed"
|
||||||
app:title="@string/settings_emulation_speed"
|
app:title="@string/settings_emulation_speed"
|
||||||
|
|
Loading…
Reference in New Issue