parent
cab9cd63a3
commit
423716aae4
|
|
@ -18,17 +18,20 @@
|
|||
package com.nononsenseapps.filepicker;
|
||||
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.app.FragmentManager;
|
||||
import android.content.ClipData;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.TypedValue;
|
||||
import android.view.Window;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -48,16 +51,26 @@ import java.util.List;
|
|||
*
|
||||
* The result of the user's action is returned in onActivityResult intent, access it using getUri.
|
||||
* In case of multiple choices, these can be accessed with getClipData containing Uri objects.
|
||||
* If running earlier than JellyBean you can access them with
|
||||
* getStringArrayListExtra(EXTRA_PATHS)
|
||||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public abstract class AbstractFilePickerActivity<T> extends Activity implements
|
||||
AbstractFilePickerFragment.OnFilePickedListener {
|
||||
public static final String EXTRA_START_PATH = "start_path";
|
||||
public static final String EXTRA_ONLY_DIRS = "only_dirs";
|
||||
public static final String EXTRA_START_PATH = "nononsense.intent" +
|
||||
".extrastart_path";
|
||||
public static final String EXTRA_ONLY_DIRS = "nononsense.intent.only_dirs";
|
||||
// For compatibility
|
||||
public static final String EXTRA_ALLOW_MULTIPLE = "android.intent.extra" +
|
||||
".ALLOW_MULTIPLE";
|
||||
public static final String EXTRA_PATHS = "nononsense.intent.paths";
|
||||
private static final String TAG = "filepicker_fragment";
|
||||
|
||||
|
||||
private String startPath = null;
|
||||
protected boolean onlyDirs = false;
|
||||
protected boolean allowMultiple = false;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
|
|
@ -68,14 +81,11 @@ public abstract class AbstractFilePickerActivity<T> extends Activity implements
|
|||
|
||||
setContentView(R.layout.activity_filepicker);
|
||||
|
||||
String startPath = null;
|
||||
boolean onlyDirs = false;
|
||||
boolean allowMultiple = false;
|
||||
Intent intent = getIntent();
|
||||
if (intent != null) {
|
||||
startPath = intent.getStringExtra(EXTRA_START_PATH);
|
||||
onlyDirs = intent.getBooleanExtra(EXTRA_ONLY_DIRS, onlyDirs);
|
||||
allowMultiple = intent.getBooleanExtra(Intent.EXTRA_ALLOW_MULTIPLE, allowMultiple);
|
||||
allowMultiple = intent.getBooleanExtra(EXTRA_ALLOW_MULTIPLE, allowMultiple);
|
||||
}
|
||||
|
||||
FragmentManager fm = getFragmentManager();
|
||||
|
|
@ -137,15 +147,30 @@ public abstract class AbstractFilePickerActivity<T> extends Activity implements
|
|||
finish();
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
@Override
|
||||
public void onFilesPicked(final List<Uri> files) {
|
||||
Intent i = new Intent();
|
||||
i.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
ClipData clip = new ClipData("Paths", new String[] {}, null);
|
||||
for (Uri file: files) {
|
||||
clip.addItem(new ClipData.Item(file));
|
||||
i.putExtra(EXTRA_ALLOW_MULTIPLE, true);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
ClipData clip = null;
|
||||
for (Uri file : files) {
|
||||
if (clip == null) {
|
||||
clip = new ClipData("Paths", new String[]{}, new ClipData.Item(file));
|
||||
} else {
|
||||
clip.addItem(new ClipData.Item(file));
|
||||
}
|
||||
}
|
||||
i.setClipData(clip);
|
||||
} else {
|
||||
ArrayList<String> paths = new ArrayList<String>();
|
||||
for (Uri file : files) {
|
||||
paths.add(file.toString());
|
||||
}
|
||||
i.putStringArrayListExtra(EXTRA_PATHS, paths);
|
||||
}
|
||||
i.setClipData(clip);
|
||||
|
||||
setResult(Activity.RESULT_OK, i);
|
||||
finish();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,11 +26,14 @@ import android.os.Bundle;
|
|||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.CheckedTextView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -43,14 +46,13 @@ import java.util.List;
|
|||
public abstract class AbstractFilePickerFragment<T> extends
|
||||
ListFragment implements
|
||||
LoaderManager.LoaderCallbacks<List<T>>,
|
||||
NewFolderFragment.OnNewFolderListener {
|
||||
NewItemFragment.OnNewFolderListener, AdapterView.OnItemLongClickListener {
|
||||
|
||||
public static final String KEY_START_PATH = "KEY_START_PATH";
|
||||
public static final String KEY_ONLY_DIRS = "KEY_ONLY_DIRS";
|
||||
public static final String KEY_ALLOW_MULTIPLE = "KEY_ALLOW_MULTIPLE";
|
||||
private static final String KEY_CURRENT_PATH = "KEY_START_PATH";
|
||||
protected T currentPath = null;
|
||||
protected List<T> currentPaths = null;
|
||||
protected boolean onlyDirs = false;
|
||||
protected boolean allowMultiple = false;
|
||||
protected Comparator<T> comparator = null;
|
||||
|
|
@ -58,11 +60,16 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
private BindableArrayAdapter<T> adapter;
|
||||
private TextView currentDirView;
|
||||
|
||||
private View okButton;
|
||||
|
||||
protected final DefaultHashMap<Integer, Boolean> checkedItems;
|
||||
|
||||
/**
|
||||
* Mandatory empty constructor for the fragment manager to instantiate the
|
||||
* fragment (e.g. upon screen orientation changes).
|
||||
*/
|
||||
public AbstractFilePickerFragment() {
|
||||
checkedItems = new DefaultHashMap<Integer, Boolean>(false);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -100,12 +107,11 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
(KEY_START_PATH)) {
|
||||
currentPath = getPath(getArguments().getString(KEY_START_PATH));
|
||||
}
|
||||
} else {
|
||||
currentPath = getRoot();
|
||||
}
|
||||
|
||||
if (currentPaths == null) {
|
||||
currentPaths = new ArrayList<T>();
|
||||
// If still null
|
||||
if (currentPath == null) {
|
||||
currentPath = getRoot();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -127,6 +133,17 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_filepicker, null);
|
||||
|
||||
ListView lv = (ListView) view.findViewById(android.R.id.list);
|
||||
if (allowMultiple) {
|
||||
lv.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
|
||||
} else if (onlyDirs) {
|
||||
lv.setChoiceMode(ListView.CHOICE_MODE_NONE);
|
||||
} else {
|
||||
lv.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
|
||||
}
|
||||
|
||||
lv.setOnItemLongClickListener(this);
|
||||
|
||||
view.findViewById(R.id.button_cancel).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
|
|
@ -136,17 +153,19 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
}
|
||||
});
|
||||
|
||||
okButton = view.findViewById(R.id.button_ok);
|
||||
if (allowMultiple) {
|
||||
view.findViewById(R.id.button_ok).setOnClickListener(new View.OnClickListener() {
|
||||
okButton.setOnClickListener
|
||||
(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
if (listener != null) {
|
||||
listener.onFilesPicked(toUri(currentPaths));
|
||||
listener.onFilesPicked(toUri(getCheckedItems()));
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
view.findViewById(R.id.button_ok).setOnClickListener(new View.OnClickListener() {
|
||||
okButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
if (listener != null) {
|
||||
|
|
@ -172,7 +191,7 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
AbstractFilePickerFragment.this);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
currentDirView = (TextView) view.findViewById(R.id.current_dir);
|
||||
// Restore state
|
||||
if (currentPath != null) {
|
||||
|
|
@ -184,7 +203,7 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
|
||||
private List<Uri> toUri(List<T> files) {
|
||||
ArrayList<Uri> uris = new ArrayList<Uri>();
|
||||
for (T file: files) {
|
||||
for (T file : files) {
|
||||
uris.add(toUri(file));
|
||||
}
|
||||
return uris;
|
||||
|
|
@ -225,21 +244,70 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
@Override
|
||||
public void onListItemClick(ListView l, View v, int position, long id) {
|
||||
super.onListItemClick(l, v, position, id);
|
||||
currentPath = (T) getListAdapter().getItem(position);
|
||||
if (isDir(currentPath)) {
|
||||
refresh();
|
||||
return;
|
||||
}
|
||||
else if (l.getChoiceMode() != ListView.CHOICE_MODE_NONE) {
|
||||
toggleItemCheck((CheckedTextView) v.findViewById(android.R.id.text1),
|
||||
position);
|
||||
}
|
||||
}
|
||||
|
||||
if (allowMultiple) {
|
||||
// TODO mark multiple
|
||||
T data = (T) getListAdapter().getItem(position);
|
||||
if (!currentPaths.remove(data)) {
|
||||
currentPaths.add(data);
|
||||
}
|
||||
} else {
|
||||
currentPath = (T) getListAdapter().getItem(position);
|
||||
if (isDir(currentPath)) {
|
||||
refresh();
|
||||
} else {
|
||||
// TODO mark file
|
||||
private void toggleItemCheck(final CheckedTextView view,
|
||||
final int position) {
|
||||
final ListView lv = getListView();
|
||||
if (lv.getChoiceMode() == ListView.CHOICE_MODE_NONE) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean oldVal = checkedItems.get(position);
|
||||
|
||||
if (lv.getChoiceMode() == ListView.CHOICE_MODE_SINGLE) {
|
||||
checkedItems.clear();
|
||||
}
|
||||
checkedItems.put(position, !oldVal);
|
||||
// Redraw the items
|
||||
lv.invalidateViews();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @return the selected files. Can be empty.
|
||||
*/
|
||||
protected List<T> getCheckedItems() {
|
||||
final BindableArrayAdapter<T> adapter = (BindableArrayAdapter<T>) getListAdapter();
|
||||
final ArrayList<T> files = new ArrayList<T>();
|
||||
for (int pos: checkedItems.keySet()) {
|
||||
if (checkedItems.get(pos)) {
|
||||
files.add(adapter.getItem(pos));
|
||||
}
|
||||
}
|
||||
return files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback method to be invoked when an item in this view has been
|
||||
* clicked and held.
|
||||
* <p/>
|
||||
* Implementers can call getItemAtPosition(position) if they need to access
|
||||
* the data associated with the selected item.
|
||||
*
|
||||
* @param parent The AbsListView where the click happened
|
||||
* @param view The view within the AbsListView that was clicked
|
||||
* @param position The position of the view in the list
|
||||
* @param id The row id of the item that was clicked
|
||||
* @return true if the callback consumed the long click, false otherwise
|
||||
*/
|
||||
@Override
|
||||
public boolean onItemLongClick(final AdapterView<?> parent, final View view, final int position, final long id) {
|
||||
if (getListView().getChoiceMode() == ListView.CHOICE_MODE_NONE) {
|
||||
return false;
|
||||
}
|
||||
toggleItemCheck((CheckedTextView) view.findViewById(android.R.id.text1),
|
||||
position);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -258,14 +326,12 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
protected abstract T getPath(final String path);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param path
|
||||
* @return the full path to the file
|
||||
*/
|
||||
protected abstract String getFullPath(final T path);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param path
|
||||
* @return the name of this file/folder
|
||||
*/
|
||||
|
|
@ -278,28 +344,56 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
|
||||
/**
|
||||
* Convert the path to a URI for the return intent
|
||||
*
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
protected abstract Uri toUri(final T path);
|
||||
|
||||
/**
|
||||
* @return a comparator that can sort the items alphabetically
|
||||
*/
|
||||
protected abstract Comparator<T> getComparator();
|
||||
|
||||
/**
|
||||
*
|
||||
* @return a ViewBinder to handle list items, or null.
|
||||
*/
|
||||
protected BindableArrayAdapter.ViewBinder<T> getViewBinder() {
|
||||
return new BindableArrayAdapter.ViewBinder<T>() {
|
||||
@Override
|
||||
public void setViewValue(final View view, final T data) {
|
||||
TextView textView = (TextView) view.findViewById(android.R.id.text1);
|
||||
textView.setText(getName(data));
|
||||
class ViewHolder {
|
||||
protected View icon;
|
||||
protected TextView text;
|
||||
protected CheckedTextView checkbox;
|
||||
}
|
||||
|
||||
view.findViewById(R.id.item_icon).setVisibility(isDir(data) ?
|
||||
return new BindableArrayAdapter.ViewBinder<T>() {
|
||||
|
||||
boolean shouldCheck = getListView().getChoiceMode() != ListView
|
||||
.CHOICE_MODE_NONE;
|
||||
|
||||
@Override
|
||||
public void setViewValue(final View view,
|
||||
final int position, final T data) {
|
||||
if (view.getTag() == null) {
|
||||
ViewHolder viewHolder = new ViewHolder();
|
||||
viewHolder.icon = view.findViewById(R.id.item_icon);
|
||||
viewHolder.text = (TextView) view.findViewById(android.R
|
||||
.id.text1);
|
||||
if (shouldCheck) {
|
||||
viewHolder.checkbox = (CheckedTextView) view.findViewById
|
||||
(android.R.id.text1);
|
||||
}
|
||||
view.setTag(viewHolder);
|
||||
}
|
||||
|
||||
((ViewHolder) view.getTag()).text.setText(getName(data));
|
||||
|
||||
((ViewHolder) view.getTag()).icon.setVisibility(isDir(data) ?
|
||||
View.VISIBLE : View.GONE);
|
||||
|
||||
if (((ViewHolder) view.getTag()).checkbox != null) {
|
||||
((ViewHolder) view.getTag()).checkbox.setChecked
|
||||
(checkedItems.get(position));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -366,7 +460,9 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
final List<T> data) {
|
||||
if (adapter == null) {
|
||||
adapter = new BindableArrayAdapter<T>(getActivity(),
|
||||
R.layout.filepicker_listitem_dir);
|
||||
getListView().getChoiceMode() == ListView.CHOICE_MODE_NONE ?
|
||||
R.layout.filepicker_listitem_dir :
|
||||
R.layout.filepicker_listitem_checkable);
|
||||
adapter.setViewBinder(getViewBinder());
|
||||
} else {
|
||||
adapter.clear();
|
||||
|
|
@ -374,6 +470,7 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
if (comparator == null) {
|
||||
comparator = getComparator();
|
||||
}
|
||||
checkedItems.clear();
|
||||
adapter.addAll(data);
|
||||
adapter.sort(comparator);
|
||||
setListAdapter(adapter);
|
||||
|
|
@ -406,8 +503,20 @@ public abstract class AbstractFilePickerFragment<T> extends
|
|||
*/
|
||||
public interface OnFilePickedListener {
|
||||
public void onFilePicked(Uri file);
|
||||
|
||||
public void onFilesPicked(List<Uri> files);
|
||||
|
||||
public void onCancelled();
|
||||
}
|
||||
|
||||
public class DefaultHashMap<K,V> extends HashMap<K,V> {
|
||||
protected final V defaultValue;
|
||||
public DefaultHashMap(final V defaultValue) {
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
@Override
|
||||
public V get(Object k) {
|
||||
return containsKey(k) ? super.get(k) : defaultValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -147,12 +147,13 @@ public class BindableArrayAdapter<T> extends ArrayAdapter<T> {
|
|||
view = convertView;
|
||||
}
|
||||
|
||||
viewBinder.setViewValue(view, getItem(position));
|
||||
viewBinder.setViewValue(view, position, getItem(position));
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ViewBinder<T> {
|
||||
public void setViewValue(final View view, final T data);
|
||||
public void setViewValue(final View view, final int position, final T
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,15 +20,34 @@ package com.nononsenseapps.filepicker;
|
|||
import java.io.File;
|
||||
|
||||
public class FilePickerActivity extends AbstractFilePickerActivity<File> {
|
||||
@Override
|
||||
protected String getWindowTitle() {
|
||||
return getResources().getQuantityString(R.plurals.select_dir, 1);
|
||||
|
||||
public FilePickerActivity() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractFilePickerFragment getFragment(final String startPath) {
|
||||
protected String getWindowTitle() {
|
||||
final int res;
|
||||
if (onlyDirs) {
|
||||
res = R.plurals.select_dir;
|
||||
} else {
|
||||
res = R.plurals.select_dir_or_file;
|
||||
}
|
||||
|
||||
final int count;
|
||||
if (allowMultiple) {
|
||||
count = 99;
|
||||
} else {
|
||||
count = 1;
|
||||
}
|
||||
|
||||
return getResources().getQuantityString(res, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractFilePickerFragment<File> getFragment(final String startPath, final boolean onlyDirs, final boolean allowMultiple) {
|
||||
AbstractFilePickerFragment fragment = new FilePickerFragment();
|
||||
fragment.setStartPath(startPath);
|
||||
fragment.setArgs(startPath, onlyDirs, allowMultiple);
|
||||
return fragment;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,111 +18,25 @@
|
|||
package com.nononsenseapps.filepicker;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.FragmentManager;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
|
||||
public class NewFolderFragment extends DialogFragment {
|
||||
public class NewFolderFragment extends NewItemFragment {
|
||||
|
||||
private static final String TAG = "new_folder_fragment";
|
||||
private String folderName = null;
|
||||
private View okButton = null;
|
||||
private OnNewFolderListener listener = null;
|
||||
|
||||
public NewFolderFragment() {
|
||||
}
|
||||
|
||||
public static void showDialog(final FragmentManager fm, final OnNewFolderListener listener) {
|
||||
NewFolderFragment d = new NewFolderFragment();
|
||||
NewItemFragment d = new NewFolderFragment();
|
||||
d.setListener(listener);
|
||||
d.show(fm, TAG);
|
||||
}
|
||||
|
||||
public void setListener(final OnNewFolderListener listener) {
|
||||
this.listener = listener;
|
||||
@Override
|
||||
protected boolean validateName(final String itemName) {
|
||||
return itemName != null && !itemName.isEmpty()
|
||||
&& !itemName.contains("/");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
setRetainInstance(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
getDialog().setTitle(R.string.new_folder);
|
||||
|
||||
final View view = inflater.inflate(R.layout.dialog_new_folder, null);
|
||||
|
||||
okButton = view.findViewById(R.id.button_ok);
|
||||
okButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
if (listener != null) {
|
||||
listener.onNewFolder(folderName);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
view.findViewById(R.id.button_cancel).setOnClickListener(new View
|
||||
.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
final EditText editText = (EditText) view.findViewById(R.id.edit_text);
|
||||
if (folderName == null) {
|
||||
okButton.setEnabled(false);
|
||||
} else {
|
||||
editText.setText(folderName);
|
||||
validateFolderName();
|
||||
}
|
||||
|
||||
editText.addTextChangedListener
|
||||
(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
folderName = s.toString();
|
||||
validateFolderName();
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void validateFolderName() {
|
||||
if (okButton != null) {
|
||||
okButton.setEnabled(folderName != null && !folderName.isEmpty()
|
||||
&& !folderName.contains("/"));
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnNewFolderListener {
|
||||
/**
|
||||
* Name is validated to be non-null, non-empty and not containing any
|
||||
* slashes.
|
||||
*
|
||||
* @param name The name of the folder the user wishes to create.
|
||||
*/
|
||||
public void onNewFolder(final String name);
|
||||
protected int getDialogTitle() {
|
||||
return R.string.new_folder;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,123 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Jonas Kalderstam
|
||||
*
|
||||
* 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 com.nononsenseapps.filepicker;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.DialogFragment;
|
||||
import android.os.Bundle;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.EditText;
|
||||
|
||||
public abstract class NewItemFragment extends DialogFragment {
|
||||
|
||||
private String itemName = null;
|
||||
private View okButton = null;
|
||||
private OnNewFolderListener listener = null;
|
||||
|
||||
public NewItemFragment() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void setListener(final OnNewFolderListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
setRetainInstance(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
getDialog().setTitle(getDialogTitle());
|
||||
|
||||
final View view = inflater.inflate(R.layout.dialog_new_item, null);
|
||||
|
||||
okButton = view.findViewById(R.id.button_ok);
|
||||
okButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
if (listener != null) {
|
||||
listener.onNewFolder(itemName);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
view.findViewById(R.id.button_cancel).setOnClickListener(new View
|
||||
.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
final EditText editText = (EditText) view.findViewById(R.id.edit_text);
|
||||
if (itemName == null) {
|
||||
okButton.setEnabled(false);
|
||||
} else {
|
||||
editText.setText(itemName);
|
||||
validateItemName();
|
||||
}
|
||||
|
||||
editText.addTextChangedListener
|
||||
(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
itemName = s.toString();
|
||||
validateItemName();
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
private void validateItemName() {
|
||||
if (okButton != null) {
|
||||
okButton.setEnabled(validateName(itemName));
|
||||
}
|
||||
}
|
||||
|
||||
public interface OnNewFolderListener {
|
||||
/**
|
||||
* Name is validated to be non-null, non-empty and not containing any
|
||||
* slashes.
|
||||
*
|
||||
* @param name The name of the folder the user wishes to create.
|
||||
*/
|
||||
public void onNewFolder(final String name);
|
||||
}
|
||||
|
||||
protected abstract boolean validateName(final String itemName);
|
||||
protected abstract int getDialogTitle();
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@
|
|||
android:layout_height="48dp"
|
||||
android:fontFamily="light"
|
||||
android:padding="4dp"
|
||||
android:hint="@string/folder_name"
|
||||
android:hint="@string/name"
|
||||
android:singleLine="true"
|
||||
android:maxLines="1"
|
||||
android:gravity="center_vertical"
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
|
||||
<!--
|
||||
Copyright (c) 2014 Jonas Kalderstam
|
||||
|
||||
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/>.
|
||||
-->
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?android:listPreferredItemHeight"
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:minHeight="?android:listPreferredItemHeight"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/selectable_background_filepickertheme">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/item_icon"
|
||||
android:src="@drawable/ic_collections_collection_light"
|
||||
android:visibility="visible"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
/>
|
||||
|
||||
<CheckedTextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="match_parent"
|
||||
style="?android:textAppearanceLarge"
|
||||
android:checked="false"
|
||||
android:checkMark="?android:attr/listChoiceIndicatorMultiple"
|
||||
android:fontFamily="light"
|
||||
android:padding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:id="@android:id/text1"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"/>
|
||||
</LinearLayout>
|
||||
|
|
@ -24,6 +24,7 @@
|
|||
android:orientation="horizontal"
|
||||
android:background="@drawable/selectable_background_filepickertheme">
|
||||
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/item_icon"
|
||||
android:src="@drawable/ic_collections_collection_light"
|
||||
|
|
@ -41,5 +42,8 @@
|
|||
android:padding="8dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:id="@android:id/text1"/>
|
||||
android:id="@android:id/text1"
|
||||
android:maxLines="1"
|
||||
android:ellipsize="end"
|
||||
android:singleLine="true"/>
|
||||
</LinearLayout>
|
||||
|
|
@ -19,16 +19,18 @@
|
|||
<string name="app_name">NoNonsense File Picker</string>
|
||||
<string name="new_folder">New folder</string>
|
||||
<string name="create_folder_error">Failed to create folder</string>
|
||||
<string name="folder_name">Folder name</string>
|
||||
<string name="name">Name</string>
|
||||
<string name="go_back">Go back</string>
|
||||
|
||||
<plurals
|
||||
name="select_dir">
|
||||
<item quantity="one">Select directory</item>
|
||||
<item quantity="other">Select directories</item>
|
||||
</plurals>
|
||||
|
||||
<plurals
|
||||
name="select_file">
|
||||
<item quantity="one">Select file</item>
|
||||
<item quantity="other">Select files</item>
|
||||
name="select_dir_or_file">
|
||||
<item quantity="one">Select directory or file</item>
|
||||
<item quantity="other">Select directories or files</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
|
|
|||
Loading…
Reference in New Issue