Use file browser for file/directory settings

The following settings can now be changed using the OI file manager:
* Opening Book Settings -> Book Filename
* Endgame Tablebases -> GTB Directory
* Endgame Tablebases -> Syzygy Directory
This commit is contained in:
Peter Osterlund 2020-03-21 13:40:12 +01:00
parent eaced74b3a
commit f02e7763e4
7 changed files with 283 additions and 58 deletions

View File

@ -2408,17 +2408,25 @@ public class DroidFish extends Activity
items[numFiles] = getString(R.string.internal_book);
items[numFiles + 1] = getString(R.string.eco_book);
items[numFiles + 2] = getString(R.string.no_book);
int defaultItem = numFiles;
if ("eco:".equals(bookOptions.filename))
defaultItem = numFiles + 1;
else if ("nobook:".equals(bookOptions.filename))
defaultItem = numFiles + 2;
String oldName = bookOptions.filename;
File extDir = Environment.getExternalStorageDirectory();
String sep = File.separator;
String defDir = extDir.getAbsolutePath() + sep + bookDir + sep;
if (oldName.startsWith(defDir))
oldName = oldName.substring(defDir.length());
for (int i = 0; i < numFiles; i++) {
if (bookOptions.filename.equals(items[i])) {
if (oldName.equals(items[i])) {
defaultItem = i;
break;
}
}
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle(R.string.select_opening_book_file);
builder.setSingleChoiceItems(items, defaultItem, (dialog, item) -> {

View File

@ -0,0 +1,151 @@
/*
DroidFish - An Android chess program.
Copyright (C) 2020 Peter Österlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.petero.droidfish.activities;
import android.app.Activity;
import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Environment;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
import org.petero.droidfish.FileUtil;
import org.petero.droidfish.R;
import java.io.File;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;
/** A text preference representing a file or directory, with a corresponding browse button. */
public class EditFilePreference extends EditTextPreference {
private boolean pickDirectory = false; // True to pick a directory, false to pick a file
private String defaultPath = ""; // Default path when current value does not define a path
private String ignorePattern = ""; // Regexp for values to be treated as non-paths
private View view;
public EditFilePreference(Context context) {
super(context);
init(null);
}
public EditFilePreference(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public EditFilePreference(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(attrs);
}
private void init(AttributeSet attrs) {
if (attrs != null) {
pickDirectory = attrs.getAttributeBooleanValue(null, "pickDirectory", false);
defaultPath = getStringValue(attrs, "defaultPath");
ignorePattern = getStringValue(attrs, "ignorePattern");
}
}
private static String getStringValue(AttributeSet attrs, String name) {
String val = attrs.getAttributeValue(null, name);
return val == null ? "" : val;
}
@Override
protected void onBindView(View view) {
super.onBindView(view);
this.view = view;
addBrowseButton();
}
private void addBrowseButton() {
if (view == null)
return;
LinearLayout widgetFrameView = view.findViewById(android.R.id.widget_frame);
if (widgetFrameView == null)
return;
widgetFrameView.setVisibility(View.VISIBLE);
int count = widgetFrameView.getChildCount();
if (count > 0)
widgetFrameView.removeViews(0, count);
ImageView button = new ImageView(getContext());
widgetFrameView.addView(button);
widgetFrameView.setMinimumWidth(0);
boolean hasBrowser = FileBrowseUtil.hasBrowser(getContext().getPackageManager(),
pickDirectory);
FileBrowseUtil.setBrowseImage(getContext().getResources(), button, hasBrowser);
button.setOnClickListener(view -> browseFile());
}
private void browseFile() {
String currentPath = getText();
if (matchPattern(currentPath))
currentPath = "";
String sep = File.separator;
if (currentPath.isEmpty() || !currentPath.contains(sep)) {
String extDir = Environment.getExternalStorageDirectory().getAbsolutePath();
String newPath = extDir + sep + defaultPath;
if (!currentPath.isEmpty())
newPath += sep + currentPath;
currentPath = newPath;
}
final String action = FileBrowseUtil.getPickAction(pickDirectory);
final String title = getContext().getString(pickDirectory ? R.string.select_directory
: R.string.select_file);
Intent i = new Intent(action);
i.setData(Uri.fromFile(new File(currentPath)));
i.putExtra("org.openintents.extra.TITLE", title);
try {
Context context = getContext();
if (context instanceof Preferences) {
Preferences prefs = ((Preferences)context);
prefs.runActivity(i, (resultCode, data) -> {
if (resultCode == Activity.RESULT_OK) {
String pathName = FileUtil.getFilePathFromUri(data.getData());
if (pathName != null)
setText(pathName);
}
});
}
} catch (ActivityNotFoundException ignore) {
}
}
private boolean matchPattern(String s) {
if (ignorePattern.isEmpty())
return false;
Pattern p;
try {
p = Pattern.compile(ignorePattern);
return p.matcher(s).find();
} catch (PatternSyntaxException ex) {
return false;
}
}
}

View File

@ -24,34 +24,23 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.drawable.StateListDrawable;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.TypedValue;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemSelectedListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import com.caverock.androidsvg.SVG;
import com.caverock.androidsvg.SVGParseException;
import androidx.databinding.DataBindingUtil;
import org.petero.droidfish.DroidFishApp;
import org.petero.droidfish.FileUtil;
import org.petero.droidfish.R;
import org.petero.droidfish.SVGPictureDrawable;
import org.petero.droidfish.Util;
import org.petero.droidfish.databinding.EditoptionsBinding;
import org.petero.droidfish.databinding.UciOptionButtonBinding;
@ -90,10 +79,8 @@ public class EditOptions extends Activity {
workDir = (String) i.getSerializableExtra("org.petero.droidfish.workDir");
hasBrowser = (Boolean) i.getSerializableExtra("org.petero.droidfish.localEngine");
if (uciOpts != null) {
if (hasBrowser) {
Intent browser = new Intent("org.openintents.action.PICK_FILE");
hasBrowser = browser.resolveActivity(getPackageManager()) != null;
}
if (hasBrowser)
hasBrowser = FileBrowseUtil.hasBrowser(getPackageManager(), false);
initUI();
} else {
setResult(RESULT_CANCELED);
@ -267,10 +254,8 @@ public class EditOptions extends Activity {
});
boolean isFileOption = hasBrowser && (o.name.toLowerCase().contains("file") ||
o.name.toLowerCase().contains("path"));
setBrowseImage(holder.eoBrowse, isFileOption);
holder.eoBrowse.setOnClickListener(view -> {
browseFile(so, holder.eoValue);
});
FileBrowseUtil.setBrowseImage(getResources(), holder.eoBrowse, isFileOption);
holder.eoBrowse.setOnClickListener(view -> browseFile(so, holder.eoValue));
return holder.getRoot();
}
default:
@ -278,42 +263,12 @@ public class EditOptions extends Activity {
}
}
private void setBrowseImage(ImageButton button, boolean visible) {
button.setVisibility(visible ? View.VISIBLE : View.GONE);
Resources r = getResources();
try {
SVG svg = SVG.getFromResource(r, R.raw.open_last_file);
button.setBackgroundDrawable(new SVGPictureDrawable(svg));
} catch (SVGParseException ignore) {
}
try {
SVG touched = SVG.getFromResource(r, R.raw.touch);
StateListDrawable sld = new StateListDrawable();
sld.addState(new int[]{android.R.attr.state_pressed}, new SVGPictureDrawable(touched));
button.setImageDrawable(sld);
} catch (SVGParseException ignore) {
}
int bWidth = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
36, r.getDisplayMetrics()));
int bHeight = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
32, r.getDisplayMetrics()));
ViewGroup.LayoutParams lp = button.getLayoutParams();
lp.width = bWidth;
lp.height = bHeight;
button.setLayoutParams(lp);
button.setPadding(0,0,0,0);
button.setScaleType(ImageView.ScaleType.FIT_XY);
}
private void browseFile(UCIOptions.StringOption so, EditText textField) {
String currentFile = so.getStringValue();
String sep = File.separator;
if (!currentFile.contains(sep))
currentFile = workDir + sep + currentFile;
Intent i = new Intent("org.openintents.action.PICK_FILE");
Intent i = new Intent(FileBrowseUtil.getPickAction(false));
i.setData(Uri.fromFile(new File(currentFile)));
i.putExtra("org.openintents.extra.TITLE", getString(R.string.select_file));
try {

View File

@ -0,0 +1,76 @@
/*
DroidFish - An Android chess program.
Copyright (C) 2020 Peter Österlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.petero.droidfish.activities;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.graphics.drawable.StateListDrawable;
import android.util.TypedValue;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import com.caverock.androidsvg.SVG;
import com.caverock.androidsvg.SVGParseException;
import org.petero.droidfish.R;
import org.petero.droidfish.SVGPictureDrawable;
public class FileBrowseUtil {
public static String getPickAction(boolean pickDirectory) {
return pickDirectory ? "org.openintents.action.PICK_DIRECTORY"
: "org.openintents.action.PICK_FILE";
}
public static boolean hasBrowser(PackageManager pMan, boolean pickDirectory) {
Intent browser = new Intent(getPickAction(pickDirectory));
return browser.resolveActivity(pMan) != null;
}
public static void setBrowseImage(Resources r, ImageView button, boolean visible) {
button.setVisibility(visible ? View.VISIBLE : View.GONE);
try {
SVG svg = SVG.getFromResource(r, R.raw.open_last_file);
button.setBackgroundDrawable(new SVGPictureDrawable(svg));
} catch (SVGParseException ignore) {
}
try {
SVG touched = SVG.getFromResource(r, R.raw.touch);
StateListDrawable sld = new StateListDrawable();
sld.addState(new int[]{android.R.attr.state_pressed}, new SVGPictureDrawable(touched));
button.setImageDrawable(sld);
} catch (SVGParseException ignore) {
}
int bWidth = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
36, r.getDisplayMetrics()));
int bHeight = Math.round(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
32, r.getDisplayMetrics()));
ViewGroup.LayoutParams lp = button.getLayoutParams();
lp.width = bWidth;
lp.height = bHeight;
button.setLayoutParams(lp);
button.setPadding(0,0,0,0);
button.setScaleType(ImageView.ScaleType.FIT_XY);
}
}

View File

@ -1,6 +1,6 @@
/*
DroidFish - An Android chess program.
Copyright (C) 2011 Peter Österlund, peterosterlund2@gmail.com
Copyright (C) 2011,2020 Peter Österlund, peterosterlund2@gmail.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -23,6 +23,7 @@ import org.petero.droidfish.R;
import org.petero.droidfish.Util;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
@ -36,6 +37,9 @@ import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import java.util.HashMap;
import java.util.Map;
public class Preferences extends PreferenceActivity {
private static int currentItem = -1;
private static int initialItem = -1;
@ -100,4 +104,28 @@ public class Preferences extends PreferenceActivity {
editor.putInt("prefsViewInitialItem", currentItem);
editor.apply();
}
public interface ActivityHandler {
void handleResult(int resultCode, Intent data);
}
private int nextRequestCode = 129866295;
private Map<Integer, ActivityHandler> handlers = new HashMap<>();
/** Start an activity and invoke handler when the activity finishes. */
public void runActivity(Intent data, ActivityHandler handler) {
int requestCode = nextRequestCode++;
startActivityForResult(data, requestCode);
handlers.put(requestCode, handler);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
ActivityHandler handler = handlers.get(requestCode);
if (handler != null) {
handlers.remove(requestCode);
handler.handleResult(resultCode, data);
}
}
}

View File

@ -82,6 +82,7 @@ If you are running on battery power, it is recommended that you change settings
<string name="select_pgn_file_save">Save to PGN file</string>
<string name="select_fen_file">Open FEN/EPD file</string>
<string name="select_file">Select file</string>
<string name="select_directory">Select directory</string>
<string name="pgn_load">Load</string>
<string name="pgn_save">Save</string>
<string name="reading_pgn_file">Reading PGN file…</string>

View File

@ -609,12 +609,14 @@
android:defaultValue="500"
android:title="@string/prefs_bookRandom_title">
</org.petero.droidfish.activities.SeekBarPreference>
<EditTextPreference
<org.petero.droidfish.activities.EditFilePreference
android:key="bookFile"
android:title="@string/prefs_bookFile_title"
android:summary="@string/prefs_bookFile_summary"
defaultPath="DroidFish/book/"
ignorePattern=".*:$"
android:defaultValue="">
</EditTextPreference>
</org.petero.droidfish.activities.EditFilePreference>
</PreferenceScreen>
<PreferenceScreen
android:key="pgnSettings"
@ -735,24 +737,28 @@
android:summary="@string/prefs_tbEngineProbe_summary"
android:defaultValue="true">
</CheckBoxPreference>
<EditTextPreference
<org.petero.droidfish.activities.EditFilePreference
android:key="gtbPath"
android:title="@string/prefs_gtbPath_title"
android:summary="@string/prefs_gtbPath_summary"
pickDirectory="true"
defaultPath="DroidFish/gtb"
android:defaultValue="">
</EditTextPreference>
</org.petero.droidfish.activities.EditFilePreference>
<EditTextPreference
android:key="gtbPathNet"
android:title="@string/prefs_gtbPathNet_title"
android:summary="@string/prefs_gtbPathNet_summary"
android:defaultValue="">
</EditTextPreference>
<EditTextPreference
<org.petero.droidfish.activities.EditFilePreference
android:key="rtbPath"
android:title="@string/prefs_rtbPath_title"
android:summary="@string/prefs_rtbPath_summary"
pickDirectory="true"
defaultPath="DroidFish/rtb"
android:defaultValue="">
</EditTextPreference>
</org.petero.droidfish.activities.EditFilePreference>
<EditTextPreference
android:key="rtbPathNet"
android:title="@string/prefs_rtbPathNet_title"