Update to Material Design
and newer API using RecyclerView. Signed-off-by: Jonas Kalderstam <jonas@kalderstam.se>
|
|
@ -5,7 +5,7 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:0.13.0'
|
||||
classpath 'com.android.tools.build:gradle:1.1.0'
|
||||
classpath "io.codearte.gradle.nexus:gradle-nexus-staging-plugin:0.5.1"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,6 @@ POM_LICENCE_DIST=repo
|
|||
POM_DEVELOPER_ID=neckbeard
|
||||
POM_DEVELOPER_NAME=Jonas Kalderstam
|
||||
|
||||
ANDROID_BUILD_TARGET_SDK_VERSION=19
|
||||
ANDROID_BUILD_TOOLS_VERSION=19.1.0
|
||||
ANDROID_BUILD_SDK_VERSION=19
|
||||
ANDROID_BUILD_TARGET_SDK_VERSION=21
|
||||
ANDROID_BUILD_TOOLS_VERSION=21.1.1
|
||||
ANDROID_BUILD_SDK_VERSION=21
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#Thu Sep 25 18:29:09 CEST 2014
|
||||
#Thu Apr 23 00:07:46 CEST 2015
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
distributionUrl=http\://services.gradle.org/distributions/gradle-2.1-all.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip
|
||||
|
|
|
|||
|
|
@ -17,14 +17,17 @@ android {
|
|||
}
|
||||
buildTypes {
|
||||
release {
|
||||
runProguard false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
//minify false
|
||||
//proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile fileTree(dir: 'libs', include: ['*.jar'])
|
||||
compile 'com.android.support:appcompat-v7:22.1+'
|
||||
compile 'com.android.support:support-v4:22.1+'
|
||||
compile 'com.android.support:recyclerview-v7:+'
|
||||
}
|
||||
|
||||
// apply from: 'https://raw.github.com/chrisbanes/gradle-mvn-push/master/gradle-mvn-push.gradle'
|
||||
|
|
|
|||
|
|
@ -20,16 +20,13 @@ 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 android.support.v4.app.FragmentManager;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
|
@ -62,7 +59,7 @@ import java.util.List;
|
|||
*
|
||||
* @param <T>
|
||||
*/
|
||||
public abstract class AbstractFilePickerActivity<T> extends Activity
|
||||
public abstract class AbstractFilePickerActivity<T> extends AppCompatActivity
|
||||
implements AbstractFilePickerFragment.OnFilePickedListener {
|
||||
public static final String EXTRA_START_PATH =
|
||||
"nononsense.intent" + ".START_PATH";
|
||||
|
|
@ -85,9 +82,6 @@ public abstract class AbstractFilePickerActivity<T> extends Activity
|
|||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
requestWindowFeature(Window.FEATURE_ACTION_BAR);
|
||||
setupFauxDialog();
|
||||
setupActionBar();
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.activity_filepicker);
|
||||
|
|
@ -102,7 +96,7 @@ public abstract class AbstractFilePickerActivity<T> extends Activity
|
|||
intent.getBooleanExtra(EXTRA_ALLOW_MULTIPLE, allowMultiple);
|
||||
}
|
||||
|
||||
FragmentManager fm = getFragmentManager();
|
||||
FragmentManager fm = getSupportFragmentManager();
|
||||
AbstractFilePickerFragment<T> fragment =
|
||||
(AbstractFilePickerFragment<T>) fm.findFragmentByTag(TAG);
|
||||
|
||||
|
|
@ -120,64 +114,10 @@ public abstract class AbstractFilePickerActivity<T> extends Activity
|
|||
setResult(Activity.RESULT_CANCELED);
|
||||
}
|
||||
|
||||
protected void setupFauxDialog() {
|
||||
// Check if this should be a dialog
|
||||
TypedValue tv = new TypedValue();
|
||||
if (!getTheme().resolveAttribute(R.attr.isDialog, tv, true) ||
|
||||
tv.data == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Should be a dialog; set up the window parameters.
|
||||
DisplayMetrics dm = getResources().getDisplayMetrics();
|
||||
|
||||
WindowManager.LayoutParams params = getWindow().getAttributes();
|
||||
params.width = getResources()
|
||||
.getDimensionPixelSize(R.dimen.configure_dialog_width);
|
||||
params.height = Math.min(getResources()
|
||||
.getDimensionPixelSize(R.dimen.configure_dialog_max_height),
|
||||
dm.heightPixels * 3 / 4);
|
||||
params.alpha = 1.0f;
|
||||
params.dimAmount = 0.5f;
|
||||
getWindow().setAttributes(params);
|
||||
}
|
||||
|
||||
protected void setupActionBar() {
|
||||
getActionBar().setTitle(getWindowTitle());
|
||||
}
|
||||
|
||||
protected abstract AbstractFilePickerFragment<T> getFragment(
|
||||
final String startPath, final int mode, final boolean allowMultiple,
|
||||
final boolean allowCreateDir);
|
||||
|
||||
/**
|
||||
* @return the title to apply to the window
|
||||
*/
|
||||
protected String getWindowTitle() {
|
||||
final int res;
|
||||
switch (mode) {
|
||||
case AbstractFilePickerFragment.MODE_DIR:
|
||||
res = R.plurals.select_dir;
|
||||
break;
|
||||
case AbstractFilePickerFragment.MODE_FILE_AND_DIR:
|
||||
res = R.plurals.select_dir_or_file;
|
||||
break;
|
||||
case AbstractFilePickerFragment.MODE_FILE:
|
||||
default:
|
||||
res = R.plurals.select_file;
|
||||
break;
|
||||
}
|
||||
|
||||
final int count;
|
||||
if (allowMultiple) {
|
||||
count = 99;
|
||||
} else {
|
||||
count = 1;
|
||||
}
|
||||
|
||||
return getResources().getQuantityString(res, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle b) {
|
||||
super.onSaveInstanceState(b);
|
||||
|
|
|
|||
|
|
@ -18,23 +18,28 @@
|
|||
package com.nononsenseapps.filepicker;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListFragment;
|
||||
import android.app.LoaderManager;
|
||||
import android.content.Loader;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Fragment;
|
||||
import android.support.v4.app.LoaderManager;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.app.AppCompatActivity;
|
||||
import android.support.v7.util.SortedList;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.Toolbar;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.Menu;
|
||||
import android.view.MenuInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.CheckedTextView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
|
|
@ -45,10 +50,9 @@ import java.util.List;
|
|||
* OnFilePickedListener}
|
||||
* interface.
|
||||
*/
|
||||
public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
||||
implements LoaderManager.LoaderCallbacks<List<T>>,
|
||||
NewItemFragment.OnNewFolderListener,
|
||||
AdapterView.OnItemLongClickListener {
|
||||
public abstract class AbstractFilePickerFragment<T> extends Fragment
|
||||
implements LoaderManager.LoaderCallbacks<SortedList<T>>,
|
||||
NewItemFragment.OnNewFolderListener, LogicHandler<T> {
|
||||
|
||||
// The different preset modes of operation. This impacts the behaviour
|
||||
// and possible actions in the UI.
|
||||
|
|
@ -66,21 +70,34 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
public static final String KEY_ALLOW_MULTIPLE = "KEY_ALLOW_MULTIPLE";
|
||||
// Used for saving state.
|
||||
protected static final String KEY_CURRENT_PATH = "KEY_CURRENT PATH";
|
||||
protected final DefaultHashMap<Integer, Boolean> checkedItems;
|
||||
protected final HashSet<T> checkedItems;
|
||||
protected final HashSet<CheckableViewHolder> checkedVisibleViewHolders;
|
||||
protected T currentPath = null;
|
||||
protected boolean allowCreateDir = false;
|
||||
protected boolean allowMultiple = false;
|
||||
protected Comparator<T> comparator = null;
|
||||
private OnFilePickedListener listener;
|
||||
private BindableArrayAdapter<T> adapter;
|
||||
private FileItemAdapter<T> mAdapter = null;
|
||||
private TextView currentDirView;
|
||||
private Toolbar mToolbar;
|
||||
private RecyclerView mRecyclerView;
|
||||
private LinearLayoutManager mLayoutManager;
|
||||
private SortedList<T> mFiles = null;
|
||||
|
||||
protected FileItemAdapter<T> getAdapter() {
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
protected FileItemAdapter<T> getDummyAdapter() {
|
||||
return new FileItemAdapter<>(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
checkedItems = new HashSet<>();
|
||||
checkedVisibleViewHolders = new HashSet<>();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -92,7 +109,7 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
* @param allowDirCreate
|
||||
*/
|
||||
public void setArgs(final String startPath, final int mode,
|
||||
final boolean allowMultiple, final boolean allowDirCreate) {
|
||||
final boolean allowMultiple, final boolean allowDirCreate) {
|
||||
Bundle b = new Bundle();
|
||||
if (startPath != null) {
|
||||
b.putString(KEY_START_PATH, startPath);
|
||||
|
|
@ -105,12 +122,26 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
Bundle savedInstanceState) {
|
||||
View view = inflater.inflate(R.layout.fragment_filepicker, null);
|
||||
|
||||
ListView lv = (ListView) view.findViewById(android.R.id.list);
|
||||
mToolbar = (Toolbar) view.findViewById(R.id.picker_toolbar);
|
||||
((AppCompatActivity) getActivity()).setSupportActionBar(mToolbar);
|
||||
|
||||
lv.setOnItemLongClickListener(this);
|
||||
|
||||
mRecyclerView = (RecyclerView) view.findViewById(android.R.id.list);
|
||||
// improve performance if you know that changes in content
|
||||
// do not change the size of the RecyclerView
|
||||
mRecyclerView.setHasFixedSize(true);
|
||||
// I want some dividers
|
||||
//mRecyclerView.addItemDecoration(new DividerColor
|
||||
// (getActivity(), DividerColor.VERTICAL_LIST, 0, 1));
|
||||
// use a linear layout manager
|
||||
mLayoutManager = new LinearLayoutManager(getActivity());
|
||||
mRecyclerView.setLayoutManager(mLayoutManager);
|
||||
// Set adapter
|
||||
mAdapter = new FileItemAdapter<>(this);
|
||||
mRecyclerView.setAdapter(mAdapter);
|
||||
|
||||
view.findViewById(R.id.button_cancel)
|
||||
.setOnClickListener(new View.OnClickListener() {
|
||||
|
|
@ -131,13 +162,7 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
}
|
||||
|
||||
// Some invalid cases first
|
||||
if (allowMultiple && checkedItems.isEmpty()) {
|
||||
Toast.makeText(getActivity(),
|
||||
R.string.select_something_first,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
if (mode == MODE_FILE && isDir(currentPath)) {
|
||||
if ((allowMultiple || mode == MODE_FILE) && checkedItems.isEmpty()) {
|
||||
Toast.makeText(getActivity(),
|
||||
R.string.select_something_first,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
|
|
@ -145,37 +170,22 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
}
|
||||
|
||||
if (allowMultiple) {
|
||||
listener.onFilesPicked(toUri(getCheckedItems()));
|
||||
} else {
|
||||
listener.onFilesPicked(toUri(checkedItems));
|
||||
} else if (mode == MODE_FILE) {
|
||||
listener.onFilePicked(toUri(getFirstCheckedItem()));
|
||||
} else if (mode == MODE_DIR) {
|
||||
listener.onFilePicked(toUri(currentPath));
|
||||
} else {
|
||||
// single FILE OR DIR
|
||||
if (checkedItems.isEmpty()) {
|
||||
listener.onFilePicked(toUri(currentPath));
|
||||
} else {
|
||||
listener.onFilePicked(toUri(getFirstCheckedItem()));
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
view.findViewById(R.id.button_go_parent)
|
||||
.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
// Go to parent
|
||||
currentPath = getParent(currentPath);
|
||||
refresh();
|
||||
}
|
||||
});
|
||||
|
||||
final View createDirView = view.findViewById(R.id.button_create_dir);
|
||||
// Only show the create dir button if configured to
|
||||
createDirView.setVisibility((allowCreateDir && (mode == MODE_DIR)) ?
|
||||
View.VISIBLE :
|
||||
View.INVISIBLE);
|
||||
createDirView.setEnabled((allowCreateDir && (mode == MODE_DIR)));
|
||||
createDirView.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
NewFolderFragment.showDialog(getFragmentManager(),
|
||||
AbstractFilePickerFragment.this);
|
||||
}
|
||||
});
|
||||
|
||||
currentDirView = (TextView) view.findViewById(R.id.current_dir);
|
||||
// Restore state
|
||||
if (currentPath != null) {
|
||||
|
|
@ -185,14 +195,14 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the path is a directory and not a file.
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
protected abstract boolean isDir(final T path);
|
||||
public T getFirstCheckedItem() {
|
||||
for (T file : checkedItems) {
|
||||
return file;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected List<Uri> toUri(List<T> files) {
|
||||
protected List<Uri> toUri(Iterable<T> files) {
|
||||
ArrayList<Uri> uris = new ArrayList<Uri>();
|
||||
for (T file : files) {
|
||||
uris.add(toUri(file));
|
||||
|
|
@ -200,61 +210,11 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
return uris;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the path to a URI for the return intent
|
||||
*
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
protected abstract Uri toUri(final T path);
|
||||
|
||||
/**
|
||||
* Return the path to the parent directory. Should return the root if
|
||||
* from is root.
|
||||
*
|
||||
* @param from
|
||||
*/
|
||||
protected abstract T getParent(final T from);
|
||||
|
||||
/**
|
||||
* @param path
|
||||
* @return the full path to the file
|
||||
*/
|
||||
protected abstract String getFullPath(final T path);
|
||||
|
||||
@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();
|
||||
} else if (isCheckable(currentPath)) {
|
||||
toggleItemCheck(
|
||||
(CheckedTextView) v.findViewById(android.R.id.text1),
|
||||
position, currentPath);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isCheckable(final T data) {
|
||||
public boolean isCheckable(final T data) {
|
||||
final boolean checkable;
|
||||
if (isDir(data)) {
|
||||
checkable = ((mode == MODE_DIR && allowMultiple) ||
|
||||
(mode == MODE_FILE_AND_DIR && allowMultiple));
|
||||
(mode == MODE_FILE_AND_DIR && allowMultiple));
|
||||
} else {
|
||||
// File
|
||||
checkable = (mode != MODE_DIR);
|
||||
|
|
@ -262,22 +222,6 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
return checkable;
|
||||
}
|
||||
|
||||
protected void toggleItemCheck(final CheckedTextView view,
|
||||
final int position, final T data) {
|
||||
if (!isCheckable(data)) {
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean oldVal = checkedItems.get(position);
|
||||
|
||||
if (!allowMultiple) {
|
||||
checkedItems.clear();
|
||||
}
|
||||
checkedItems.put(position, !oldVal);
|
||||
// Redraw the items
|
||||
getListView().invalidateViews();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
super.onAttach(activity);
|
||||
|
|
@ -285,7 +229,7 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
listener = (OnFilePickedListener) activity;
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException(activity.toString() +
|
||||
" must implement OnFilePickedListener");
|
||||
" must implement OnFilePickedListener");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -328,6 +272,29 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
setHasOptionsMenu(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
inflater.inflate(R.menu.picker_actions, menu);
|
||||
|
||||
MenuItem item = menu.findItem(R.id.action_createdir);
|
||||
item.setVisible(allowCreateDir && (mode == MODE_DIR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem menuItem) {
|
||||
if (R.id.action_createdir == menuItem.getItemId()) {
|
||||
Activity activity = getActivity();
|
||||
if (activity instanceof AppCompatActivity) {
|
||||
NewFolderFragment.showDialog(((AppCompatActivity) activity).getSupportFragmentManager(),
|
||||
AbstractFilePickerFragment.this);
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onSaveInstanceState(Bundle b) {
|
||||
super.onSaveInstanceState(b);
|
||||
|
|
@ -343,18 +310,6 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
listener = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the path to the type used.
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
protected abstract T getPath(final String path);
|
||||
|
||||
/**
|
||||
* Get the root path (lowest allowed).
|
||||
*/
|
||||
protected abstract T getRoot();
|
||||
|
||||
/**
|
||||
* Refreshes the list. Call this when current path changes.
|
||||
*/
|
||||
|
|
@ -363,36 +318,6 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
.restartLoader(0, null, AbstractFilePickerFragment.this);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
final T data = (T) getListAdapter().getItem(position);
|
||||
if (!isCheckable(data)) {
|
||||
return false;
|
||||
}
|
||||
// Special case for single choice to handle directories
|
||||
if (!allowMultiple) {
|
||||
return false;
|
||||
}
|
||||
|
||||
toggleItemCheck((CheckedTextView) view.findViewById(android.R.id.text1),
|
||||
position, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiate and return a new Loader for the given ID.
|
||||
*
|
||||
|
|
@ -401,16 +326,10 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
* @return Return a new Loader instance that is ready to start loading.
|
||||
*/
|
||||
@Override
|
||||
public Loader<List<T>> onCreateLoader(final int id, final Bundle args) {
|
||||
public Loader<SortedList<T>> onCreateLoader(final int id, final Bundle args) {
|
||||
return getLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a loader that lists the files in the current path,
|
||||
* and monitors changes.
|
||||
*/
|
||||
protected abstract Loader<List<T>> getLoader();
|
||||
|
||||
/**
|
||||
* Called when a previously created loader has finished its load.
|
||||
*
|
||||
|
|
@ -418,125 +337,15 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
* @param data The data generated by the Loader.
|
||||
*/
|
||||
@Override
|
||||
public void onLoadFinished(final Loader<List<T>> loader,
|
||||
final List<T> data) {
|
||||
if (adapter == null) {
|
||||
// View type not really used, overridden in ViewBinder
|
||||
adapter = new BindableArrayAdapter<T>(getActivity(),
|
||||
R.layout.filepicker_listitem_checkable);
|
||||
adapter.setViewBinder(getViewBinder());
|
||||
} else {
|
||||
adapter.clear();
|
||||
}
|
||||
if (comparator == null) {
|
||||
comparator = getComparator();
|
||||
}
|
||||
public void onLoadFinished(final Loader<SortedList<T>> loader,
|
||||
final SortedList<T> data) {
|
||||
checkedItems.clear();
|
||||
adapter.addAll(data);
|
||||
adapter.sort(comparator);
|
||||
setListAdapter(adapter);
|
||||
adapter.notifyDataSetChanged();
|
||||
checkedVisibleViewHolders.clear();
|
||||
mFiles = data;
|
||||
mAdapter.setList(data);
|
||||
currentDirView.setText(getFullPath(currentPath));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a ViewBinder to handle list items, or null.
|
||||
*/
|
||||
protected BindableArrayAdapter.ViewBinder<T> getViewBinder() {
|
||||
class ViewHolder {
|
||||
protected View icon;
|
||||
protected TextView text;
|
||||
protected CheckedTextView checkbox;
|
||||
}
|
||||
|
||||
return new BindableArrayAdapter.ViewBinder<T>() {
|
||||
|
||||
/**
|
||||
* Called if convertView is null. If this returns null,
|
||||
* the specified resource is used. Use this to return multiple views
|
||||
* depending on type.
|
||||
*
|
||||
* @param position
|
||||
* @param defResource
|
||||
* @param inflater
|
||||
* @param parent
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public View inflateView(final int position, final int defResource,
|
||||
final LayoutInflater inflater, final ViewGroup parent) {
|
||||
final boolean checkable =
|
||||
isCheckable((T) getListAdapter().getItem(position));
|
||||
final View view = inflater.inflate(checkable ?
|
||||
R.layout.filepicker_listitem_checkable :
|
||||
R.layout.filepicker_listitem_dir,
|
||||
parent, false);
|
||||
|
||||
ViewHolder viewHolder = new ViewHolder();
|
||||
viewHolder.icon = view.findViewById(R.id.item_icon);
|
||||
viewHolder.text =
|
||||
(TextView) view.findViewById(android.R.id.text1);
|
||||
if (checkable) {
|
||||
viewHolder.checkbox = (CheckedTextView) view
|
||||
.findViewById(android.R.id.text1);
|
||||
} else {
|
||||
viewHolder.checkbox = null;
|
||||
}
|
||||
view.setTag(viewHolder);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
/**
|
||||
* Used to determine the view's type. Returning false will use same
|
||||
* type for all rows.
|
||||
*
|
||||
* @param position
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public boolean isDir(final int position, final T data) {
|
||||
return AbstractFilePickerFragment.this.isDir(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fill the content in the row
|
||||
* @param view
|
||||
* @param position
|
||||
* @param data
|
||||
*/
|
||||
@Override
|
||||
public void setViewValue(final View view, final int position,
|
||||
final T data) {
|
||||
if (view.getTag() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
((ViewHolder) view.getTag()).text.setText(getName(data));
|
||||
|
||||
((ViewHolder) view.getTag()).icon.setVisibility(
|
||||
isDir(position, data) ? View.VISIBLE : View.GONE);
|
||||
|
||||
if (((ViewHolder) view.getTag()).checkbox != null) {
|
||||
((ViewHolder) view.getTag()).checkbox
|
||||
.setChecked(checkedItems.get(position));
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a comparator that can sort the items alphabetically
|
||||
*/
|
||||
protected abstract Comparator<T> getComparator();
|
||||
|
||||
/**
|
||||
* @param path
|
||||
* @return the name of this file/folder
|
||||
*/
|
||||
protected abstract String getName(final T path);
|
||||
|
||||
/**
|
||||
* Called when a previously created loader is being reset, and thus
|
||||
* making its data unavailable. The application should at this point
|
||||
|
|
@ -545,9 +354,9 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
* @param loader The Loader that is being reset.
|
||||
*/
|
||||
@Override
|
||||
public void onLoaderReset(final Loader<List<T>> loader) {
|
||||
setListAdapter(null);
|
||||
adapter = null;
|
||||
public void onLoaderReset(final Loader<SortedList<T>> loader) {
|
||||
mAdapter.setList(null);
|
||||
mFiles = null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -569,16 +378,202 @@ public abstract class AbstractFilePickerFragment<T> extends ListFragment
|
|||
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;
|
||||
/**
|
||||
* @param position 0 - n, where the header has been subtracted
|
||||
* @param data
|
||||
* @return an integer greater than 0
|
||||
*/
|
||||
@Override
|
||||
public int getItemViewType(int position, T data) {
|
||||
if (isCheckable(data)) {
|
||||
return LogicHandler.VIEWTYPE_CHECKABLE;
|
||||
} else {
|
||||
return LogicHandler.VIEWTYPE_DIR;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindHeaderViewHolder(HeaderViewHolder viewHolder) {
|
||||
viewHolder.text.setText("..");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param parent
|
||||
* @param viewType
|
||||
* @return a view holder for a file or directory
|
||||
*/
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View v;
|
||||
switch (viewType) {
|
||||
case LogicHandler.VIEWTYPE_HEADER:
|
||||
v = LayoutInflater.from(getActivity()).inflate(R.layout.filepicker_listitem_dir,
|
||||
parent, false);
|
||||
return new HeaderViewHolder(v);
|
||||
case LogicHandler.VIEWTYPE_CHECKABLE:
|
||||
v = LayoutInflater.from(getActivity()).inflate(R.layout.filepicker_listitem_checkable,
|
||||
parent, false);
|
||||
return new CheckableViewHolder(v);
|
||||
case LogicHandler.VIEWTYPE_DIR:
|
||||
default:
|
||||
v = LayoutInflater.from(getActivity()).inflate(R.layout.filepicker_listitem_dir,
|
||||
parent, false);
|
||||
return new DirViewHolder(v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param vh to bind data from either a file or directory
|
||||
* @param position 0 - n, where the header has been subtracted
|
||||
* @param data
|
||||
*/
|
||||
@Override
|
||||
public void onBindViewHolder(DirViewHolder vh, int position, T data) {
|
||||
vh.file = data;
|
||||
vh.icon.setVisibility(isDir(data) ? View.VISIBLE : View.GONE);
|
||||
vh.text.setText(getName(data));
|
||||
|
||||
if (isCheckable(data)) {
|
||||
if (checkedItems.contains(data)) {
|
||||
checkedVisibleViewHolders.add((CheckableViewHolder) vh);
|
||||
((CheckableViewHolder) vh).checkbox.setChecked(true);
|
||||
} else {
|
||||
checkedVisibleViewHolders.remove(vh);
|
||||
((CheckableViewHolder) vh).checkbox.setChecked(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class HeaderViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||
final TextView text;
|
||||
|
||||
public HeaderViewHolder(View v) {
|
||||
super(v);
|
||||
v.setOnClickListener(this);
|
||||
text = (TextView) v.findViewById(android.R.id.text1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a view has been clicked.
|
||||
*
|
||||
* @param v The view that was clicked.
|
||||
*/
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
currentPath = getParent(currentPath);
|
||||
checkedItems.clear();
|
||||
checkedVisibleViewHolders.clear();
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
public class DirViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener, View.OnLongClickListener {
|
||||
|
||||
public View icon;
|
||||
public TextView text;
|
||||
public T file;
|
||||
|
||||
public DirViewHolder(View v) {
|
||||
super(v);
|
||||
v.setOnClickListener(this);
|
||||
v.setOnLongClickListener(this);
|
||||
icon = v.findViewById(R.id.item_icon);
|
||||
text = (TextView) v.findViewById(android.R.id.text1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a view has been clicked.
|
||||
*
|
||||
* @param v The view that was clicked.
|
||||
*/
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (isDir(file)) {
|
||||
currentPath = file;
|
||||
checkedItems.clear();
|
||||
checkedVisibleViewHolders.clear();
|
||||
refresh();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a view has been clicked and held.
|
||||
*
|
||||
* @param v The view that was clicked and held.
|
||||
* @return true if the callback consumed the long click, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public class CheckableViewHolder extends DirViewHolder {
|
||||
|
||||
public CheckBox checkbox;
|
||||
|
||||
public CheckableViewHolder(View v) {
|
||||
super(v);
|
||||
checkbox = (CheckBox) v.findViewById(R.id.checkbox);
|
||||
checkbox.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
onLongClick(v);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a view has been clicked.
|
||||
*
|
||||
* @param v The view that was clicked.
|
||||
*/
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
if (isDir(file)) {
|
||||
currentPath = file;
|
||||
checkedItems.clear();
|
||||
checkedVisibleViewHolders.clear();
|
||||
refresh();
|
||||
} else {
|
||||
onLongClick(v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a view has been clicked and held.
|
||||
*
|
||||
* @param v The view that was clicked and held.
|
||||
* @return true if the callback consumed the long click, false otherwise.
|
||||
*/
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (checkedItems.contains(file)) {
|
||||
checkbox.setChecked(false);
|
||||
checkedItems.remove(file);
|
||||
checkedVisibleViewHolders.remove(this);
|
||||
} else {
|
||||
if (!allowMultiple) {
|
||||
clearSelections();
|
||||
}
|
||||
checkbox.setChecked(true);
|
||||
checkedItems.add(file);
|
||||
checkedVisibleViewHolders.add(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Animate de-selection of visible views and clear
|
||||
* selected set.
|
||||
*/
|
||||
public void clearSelections() {
|
||||
for (CheckableViewHolder vh : checkedVisibleViewHolders) {
|
||||
vh.checkbox.setChecked(false);
|
||||
}
|
||||
checkedVisibleViewHolders.clear();
|
||||
checkedItems.clear();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,207 +0,0 @@
|
|||
/*
|
||||
* 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.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ArrayAdapter;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class BindableArrayAdapter<T> extends ArrayAdapter<T> {
|
||||
|
||||
private final LayoutInflater mInflater;
|
||||
private final int mResource;
|
||||
private ViewBinder<T> viewBinder = null;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param resource The resource ID for a layout file containing a TextView to use when
|
||||
*/
|
||||
public BindableArrayAdapter(final Context context, final int resource) {
|
||||
super(context, resource);
|
||||
mResource = resource;
|
||||
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param resource The resource ID for a layout file containing a layout to use when
|
||||
* instantiating views.
|
||||
* @param textViewResourceId The id of the TextView within the layout resource to be populated
|
||||
*/
|
||||
public BindableArrayAdapter(final Context context, final int resource, final int textViewResourceId) {
|
||||
super(context, resource, textViewResourceId);
|
||||
mResource = resource;
|
||||
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param resource The resource ID for a layout file containing a TextView to use when
|
||||
* instantiating views.
|
||||
* @param objects The objects to represent in the ListView.
|
||||
*/
|
||||
public BindableArrayAdapter(final Context context, final int resource, final T[] objects) {
|
||||
super(context, resource, objects);
|
||||
mResource = resource;
|
||||
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param resource The resource ID for a layout file containing a layout to use when
|
||||
* instantiating views.
|
||||
* @param textViewResourceId The id of the TextView within the layout resource to be populated
|
||||
* @param objects The objects to represent in the ListView.
|
||||
*/
|
||||
public BindableArrayAdapter(final Context context, final int resource, final int textViewResourceId, final T[] objects) {
|
||||
super(context, resource, textViewResourceId, objects);
|
||||
mResource = resource;
|
||||
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param resource The resource ID for a layout file containing a TextView to use when
|
||||
* instantiating views.
|
||||
* @param objects The objects to represent in the ListView.
|
||||
*/
|
||||
public BindableArrayAdapter(final Context context, final int resource, final List<T> objects) {
|
||||
super(context, resource, objects);
|
||||
mResource = resource;
|
||||
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param context The current context.
|
||||
* @param resource The resource ID for a layout file containing a layout to use when
|
||||
* instantiating views.
|
||||
* @param textViewResourceId The id of the TextView within the layout resource to be populated
|
||||
* @param objects The objects to represent in the ListView.
|
||||
*/
|
||||
public BindableArrayAdapter(final Context context, final int resource, final int textViewResourceId, final List<T> objects) {
|
||||
super(context, resource, textViewResourceId, objects);
|
||||
mResource = resource;
|
||||
mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (viewBinder != null) {
|
||||
if (viewBinder.isDir(position, getItem(position))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewTypeCount() {
|
||||
// Files and dirs, so 2
|
||||
return 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the view binder to use to bind data to the list item views.
|
||||
* @param binder
|
||||
*/
|
||||
public void setViewBinder(ViewBinder binder) {
|
||||
this.viewBinder = binder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle more complex views than standard implementation.
|
||||
*
|
||||
* @param position
|
||||
* @param convertView
|
||||
* @param parent
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (viewBinder == null) {
|
||||
return super.getView(position, convertView, parent);
|
||||
}
|
||||
else {
|
||||
View view;
|
||||
|
||||
if (convertView == null && viewBinder != null) {
|
||||
view = viewBinder.inflateView(position, mResource, mInflater,
|
||||
parent);
|
||||
}
|
||||
else if (convertView == null) {
|
||||
view = mInflater.inflate(mResource, parent, false);
|
||||
} else {
|
||||
view = convertView;
|
||||
}
|
||||
|
||||
viewBinder.setViewValue(view, position, getItem(position));
|
||||
return view;
|
||||
}
|
||||
}
|
||||
|
||||
public interface ViewBinder<T> {
|
||||
/**
|
||||
* Called if convertView is null. If this returns null,
|
||||
* the specified resource is used. Use this to return multiple views
|
||||
* depending on type.
|
||||
* @param position
|
||||
* @param resource
|
||||
* @param inflater
|
||||
* @param parent
|
||||
* @return
|
||||
*/
|
||||
public View inflateView(final int position,
|
||||
final int resource,
|
||||
final LayoutInflater inflater,
|
||||
final ViewGroup parent);
|
||||
|
||||
/**
|
||||
* Used to determine the view's type. Returning false will use same
|
||||
* type for all rows.
|
||||
* @param position
|
||||
* @param data
|
||||
* @return
|
||||
*/
|
||||
public boolean isDir(final int position, final T data);
|
||||
|
||||
/**
|
||||
* Fill the content in the row
|
||||
* @param view
|
||||
* @param position
|
||||
* @param data
|
||||
*/
|
||||
public void setViewValue(final View view, final int position, final T
|
||||
data);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,76 @@
|
|||
/*
|
||||
* Copyright (c) 2015 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.support.v7.util.SortedList;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* A simple adapter which also inserts a header item ".." to handle going up to the parent folder.
|
||||
* @param <T> the type which is used, for example a normal java File object.
|
||||
*/
|
||||
public class FileItemAdapter<T> extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||
|
||||
private final LogicHandler<T> mLogic;
|
||||
private SortedList<T> mList = null;
|
||||
|
||||
public FileItemAdapter(LogicHandler<T> logic) {
|
||||
this.mLogic = logic;
|
||||
}
|
||||
|
||||
public void setList(SortedList<T> list) {
|
||||
mList = list;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return mLogic.onCreateViewHolder(parent, viewType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(RecyclerView.ViewHolder viewHolder, int headerPosition) {
|
||||
if (headerPosition == 0) {
|
||||
mLogic.onBindHeaderViewHolder((AbstractFilePickerFragment<T>.HeaderViewHolder) viewHolder);
|
||||
} else {
|
||||
int pos = headerPosition - 1;
|
||||
mLogic.onBindViewHolder((AbstractFilePickerFragment<T>.DirViewHolder) viewHolder, pos, mList.get(pos));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int headerPosition) {
|
||||
if (0 == headerPosition) {
|
||||
return LogicHandler.VIEWTYPE_HEADER;
|
||||
} else {
|
||||
int pos = headerPosition - 1;
|
||||
return mLogic.getItemViewType(pos, mList.get(pos));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
if (mList == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// header + count
|
||||
return 1 + mList.size();
|
||||
}
|
||||
}
|
||||
|
|
@ -17,21 +17,21 @@
|
|||
|
||||
package com.nononsenseapps.filepicker;
|
||||
|
||||
import android.content.AsyncTaskLoader;
|
||||
import android.content.Loader;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import android.os.FileObserver;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.util.SortedList;
|
||||
import android.support.v7.widget.util.SortedListAdapterCallback;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class FilePickerFragment extends AbstractFilePickerFragment<File> {
|
||||
|
||||
public FilePickerFragment() {}
|
||||
public FilePickerFragment() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if the path is a directory and not a file.
|
||||
|
|
@ -39,10 +39,19 @@ public class FilePickerFragment extends AbstractFilePickerFragment<File> {
|
|||
* @param path
|
||||
*/
|
||||
@Override
|
||||
protected boolean isDir(final File path) {
|
||||
public boolean isDir(final File path) {
|
||||
return path.isDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path
|
||||
* @return filename of path
|
||||
*/
|
||||
@Override
|
||||
public String getName(File path) {
|
||||
return path.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the path to the parent directory. Should return the root if
|
||||
* from is root.
|
||||
|
|
@ -50,7 +59,7 @@ public class FilePickerFragment extends AbstractFilePickerFragment<File> {
|
|||
* @param from
|
||||
*/
|
||||
@Override
|
||||
protected File getParent(final File from) {
|
||||
public File getParent(final File from) {
|
||||
if (from.getParentFile() != null) {
|
||||
if (from.isFile()) {
|
||||
return getParent(from.getParentFile());
|
||||
|
|
@ -68,7 +77,7 @@ public class FilePickerFragment extends AbstractFilePickerFragment<File> {
|
|||
* @param path
|
||||
*/
|
||||
@Override
|
||||
protected File getPath(final String path) {
|
||||
public File getPath(final String path) {
|
||||
return new File(path);
|
||||
}
|
||||
|
||||
|
|
@ -77,72 +86,71 @@ public class FilePickerFragment extends AbstractFilePickerFragment<File> {
|
|||
* @return the full path to the file
|
||||
*/
|
||||
@Override
|
||||
protected String getFullPath(final File path) {
|
||||
public String getFullPath(final File path) {
|
||||
return path.getPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param path
|
||||
* @return the name of this file/folder
|
||||
*/
|
||||
@Override
|
||||
protected String getName(final File path) {
|
||||
return path.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the root path (lowest allowed).
|
||||
*/
|
||||
@Override
|
||||
protected File getRoot() {
|
||||
public File getRoot() {
|
||||
return Environment.getExternalStorageDirectory();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the path to a URI for the return intent
|
||||
*
|
||||
* @param file
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
protected Uri toUri(final File file) {
|
||||
public Uri toUri(final File file) {
|
||||
return Uri.fromFile(file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return a comparator that can sort the items alphabetically
|
||||
*/
|
||||
@Override
|
||||
protected Comparator<File> getComparator() {
|
||||
return new Comparator<File>() {
|
||||
@Override
|
||||
public int compare(final File lhs, final File rhs) {
|
||||
if (lhs.isDirectory() && !rhs.isDirectory()) {
|
||||
return -1;
|
||||
} else if (rhs.isDirectory() && !lhs.isDirectory()) {
|
||||
return 1;
|
||||
} else {
|
||||
return lhs.getName().toLowerCase().compareTo(rhs.getName()
|
||||
.toLowerCase());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a loader that lists the Files in the current path,
|
||||
* and monitors changes.
|
||||
*/
|
||||
@Override
|
||||
protected Loader<List<File>> getLoader() {
|
||||
return new AsyncTaskLoader<List<File>>(getActivity()) {
|
||||
public Loader<SortedList<File>> getLoader() {
|
||||
return new AsyncTaskLoader<SortedList<File>>(getActivity()) {
|
||||
|
||||
FileObserver fileObserver;
|
||||
|
||||
@Override
|
||||
public List<File> loadInBackground() {
|
||||
ArrayList<File> files = new ArrayList<File>();
|
||||
public SortedList<File> loadInBackground() {
|
||||
File[] listFiles = currentPath.listFiles();
|
||||
if(listFiles != null) {
|
||||
final int initCap = listFiles == null ? 0 : listFiles.length;
|
||||
|
||||
SortedList<File> files = new SortedList<>(File.class, new SortedListAdapterCallback<File>(getDummyAdapter()) {
|
||||
@Override
|
||||
public int compare(File lhs, File rhs) {
|
||||
if (lhs.isDirectory() && !rhs.isDirectory()) {
|
||||
return -1;
|
||||
} else if (rhs.isDirectory() && !lhs.isDirectory()) {
|
||||
return 1;
|
||||
} else {
|
||||
return lhs.getName().toLowerCase().compareTo(rhs.getName()
|
||||
.toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(File file, File file2) {
|
||||
return file.getAbsolutePath().equals(file2.getAbsolutePath()) && (file.isFile() == file2.isFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(File file, File file2) {
|
||||
return areContentsTheSame(file, file2);
|
||||
}
|
||||
}, initCap);
|
||||
|
||||
|
||||
files.beginBatchedUpdates();
|
||||
if (listFiles != null) {
|
||||
for (java.io.File f : listFiles) {
|
||||
if ((mode == MODE_FILE || mode == MODE_FILE_AND_DIR)
|
||||
|| f.isDirectory()) {
|
||||
|
|
@ -150,6 +158,9 @@ public class FilePickerFragment extends AbstractFilePickerFragment<File> {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
files.endBatchedUpdates();
|
||||
|
||||
return files;
|
||||
}
|
||||
|
||||
|
|
@ -217,4 +228,6 @@ public class FilePickerFragment extends AbstractFilePickerFragment<File> {
|
|||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
* Copyright (c) 2015 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.net.Uri;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.util.SortedList;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* An interface for the methods required to handle backend-specific stuff.
|
||||
*/
|
||||
public interface LogicHandler<T> {
|
||||
|
||||
/**
|
||||
* Return true if the path is a directory and not a file.
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
public boolean isDir(final T path);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param path
|
||||
* @return filename of path
|
||||
*/
|
||||
public String getName(final T path);
|
||||
|
||||
/**
|
||||
* Convert the path to a URI for the return intent
|
||||
*
|
||||
* @param path
|
||||
* @return
|
||||
*/
|
||||
public Uri toUri(final T path);
|
||||
|
||||
/**
|
||||
* Return the path to the parent directory. Should return the root if
|
||||
* from is root.
|
||||
*
|
||||
* @param from
|
||||
*/
|
||||
public T getParent(final T from);
|
||||
|
||||
/**
|
||||
* @param path
|
||||
* @return the full path to the file
|
||||
*/
|
||||
public String getFullPath(final T path);
|
||||
|
||||
/**
|
||||
* Convert the path to the type used.
|
||||
*
|
||||
* @param path
|
||||
*/
|
||||
public T getPath(final String path);
|
||||
|
||||
/**
|
||||
* Get the root path (lowest allowed).
|
||||
*/
|
||||
public T getRoot();
|
||||
|
||||
/**
|
||||
* Get a loader that lists the files in the current path,
|
||||
* and monitors changes.
|
||||
*/
|
||||
public Loader<SortedList<T>> getLoader();
|
||||
|
||||
/**
|
||||
* @return a comparator that can sort the items alphabetically
|
||||
*/
|
||||
//public Comparator<T> getComparator();
|
||||
|
||||
|
||||
public final static int VIEWTYPE_HEADER = 0;
|
||||
public final static int VIEWTYPE_DIR = 1;
|
||||
public final static int VIEWTYPE_CHECKABLE = 2;
|
||||
|
||||
/**
|
||||
* Bind the header ".." which goes to parent folder.
|
||||
* @param viewHolder
|
||||
*/
|
||||
public void onBindHeaderViewHolder(AbstractFilePickerFragment<T>.HeaderViewHolder viewHolder);
|
||||
|
||||
/**
|
||||
* Header is subtracted from the position
|
||||
*
|
||||
* @param parent
|
||||
* @param viewType
|
||||
* @return a view holder for a file or directory
|
||||
*/
|
||||
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param viewHolder to bind data from either a file or directory
|
||||
* @param position 0 - n, where the header has been subtracted
|
||||
* @param data
|
||||
*/
|
||||
public void onBindViewHolder(AbstractFilePickerFragment<T>.DirViewHolder viewHolder, int position, T data);
|
||||
|
||||
/**
|
||||
*
|
||||
* @param position 0 - n, where the header has been subtracted
|
||||
* @param data
|
||||
* @return an integer greater than 0
|
||||
*/
|
||||
public int getItemViewType(int position, T data);
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Jonas Kalderstam
|
||||
* Copyright (c) 2015 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
|
||||
|
|
@ -18,11 +18,13 @@
|
|||
package com.nononsenseapps.filepicker;
|
||||
|
||||
|
||||
import android.app.FragmentManager;
|
||||
import android.support.v4.app.FragmentManager;
|
||||
import android.text.TextUtils;
|
||||
|
||||
public class NewFolderFragment extends NewItemFragment {
|
||||
|
||||
private static final String TAG = "new_folder_fragment";
|
||||
|
||||
public static void showDialog(final FragmentManager fm, final OnNewFolderListener listener) {
|
||||
NewItemFragment d = new NewFolderFragment();
|
||||
d.setListener(listener);
|
||||
|
|
@ -31,12 +33,9 @@ public class NewFolderFragment extends NewItemFragment {
|
|||
|
||||
@Override
|
||||
protected boolean validateName(final String itemName) {
|
||||
return itemName != null && !itemName.isEmpty()
|
||||
&& !itemName.contains("/");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getDialogTitle() {
|
||||
return R.string.new_folder;
|
||||
return !TextUtils.isEmpty(itemName)
|
||||
&& !itemName.contains("/")
|
||||
&& !itemName.equals(".")
|
||||
&& !itemName.equals("..");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Jonas Kalderstam
|
||||
* Copyright (c) 2015 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
|
||||
|
|
@ -18,21 +18,20 @@
|
|||
package com.nononsenseapps.filepicker;
|
||||
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.app.DialogFragment;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.text.Editable;
|
||||
import android.text.TextWatcher;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.EditText;
|
||||
|
||||
public abstract class NewItemFragment extends DialogFragment {
|
||||
|
||||
private String itemName = null;
|
||||
private View okButton = null;
|
||||
private OnNewFolderListener listener = null;
|
||||
|
||||
public NewItemFragment() {
|
||||
|
|
@ -50,67 +49,70 @@ public abstract class NewItemFragment extends DialogFragment {
|
|||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState) {
|
||||
getDialog().setTitle(getDialogTitle());
|
||||
public Dialog onCreateDialog(Bundle savedInstanceState) {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||
builder.setView(R.layout.dialog_folder_name)
|
||||
.setTitle(R.string.new_folder)
|
||||
.setNegativeButton(android.R.string.cancel,
|
||||
null)
|
||||
.setPositiveButton(android.R.string.ok,
|
||||
null);
|
||||
|
||||
@SuppressLint("InflateParams") final View view =
|
||||
inflater.inflate(R.layout.dialog_new_item, null);
|
||||
final AlertDialog dialog = builder.create();
|
||||
|
||||
okButton = view.findViewById(R.id.button_ok);
|
||||
okButton.setOnClickListener(new View.OnClickListener() {
|
||||
dialog.setOnShowListener(new DialogInterface.OnShowListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
if (listener != null) {
|
||||
listener.onNewFolder(itemName);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
public void onShow(DialogInterface dialog1) {
|
||||
final AlertDialog dialog = (AlertDialog) dialog1;
|
||||
final EditText editText = (EditText) dialog.findViewById(R.id.edit_text);
|
||||
|
||||
Button cancel = dialog.getButton(AlertDialog.BUTTON_NEGATIVE);
|
||||
cancel.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
view.findViewById(R.id.button_cancel)
|
||||
.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
dismiss();
|
||||
public void onClick(View view) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
|
||||
final EditText editText = (EditText) view.findViewById(R.id.edit_text);
|
||||
if (itemName == null) {
|
||||
okButton.setEnabled(false);
|
||||
} else {
|
||||
editText.setText(itemName);
|
||||
validateItemName();
|
||||
}
|
||||
final Button ok = dialog.getButton(AlertDialog.BUTTON_POSITIVE);
|
||||
// Start disabled
|
||||
ok.setEnabled(false);
|
||||
ok.setOnClickListener(new View.OnClickListener() {
|
||||
|
||||
editText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start,
|
||||
final int count, final int after) {
|
||||
}
|
||||
@Override
|
||||
public void onClick(View view) {
|
||||
String itemName = editText.getText().toString();
|
||||
if (validateName(itemName)) {
|
||||
if (listener != null) {
|
||||
listener.onNewFolder(itemName);
|
||||
}
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start,
|
||||
final int before, final int count) {
|
||||
}
|
||||
editText.addTextChangedListener(new TextWatcher() {
|
||||
@Override
|
||||
public void beforeTextChanged(final CharSequence s, final int start,
|
||||
final int count, final int after) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
itemName = s.toString();
|
||||
validateItemName();
|
||||
@Override
|
||||
public void onTextChanged(final CharSequence s, final int start,
|
||||
final int before, final int count) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterTextChanged(final Editable s) {
|
||||
ok.setEnabled(validateName(s.toString()));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
protected abstract int getDialogTitle();
|
||||
|
||||
private void validateItemName() {
|
||||
if (okButton != null) {
|
||||
okButton.setEnabled(validateName(itemName));
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
protected abstract boolean validateName(final String itemName);
|
||||
|
|
|
|||
|
Before Width: | Height: | Size: 200 B |
|
Before Width: | Height: | Size: 862 B |
|
After Width: | Height: | Size: 457 B |
|
Before Width: | Height: | Size: 694 B |
|
Before Width: | Height: | Size: 166 B |
|
Before Width: | Height: | Size: 591 B |
|
After Width: | Height: | Size: 284 B |
|
Before Width: | Height: | Size: 431 B |
|
Before Width: | Height: | Size: 258 B |
|
Before Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 567 B |
|
Before Width: | Height: | Size: 839 B |
|
Before Width: | Height: | Size: 351 B |
|
Before Width: | Height: | Size: 1.9 KiB |
|
After Width: | Height: | Size: 955 B |
|
Before Width: | Height: | Size: 1.6 KiB |
|
|
@ -1,26 +0,0 @@
|
|||
<?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/>.
|
||||
-->
|
||||
|
||||
<selector
|
||||
xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_pressed="true" android:drawable="@color/action_select" />
|
||||
<item android:state_selected="true" android:drawable="@color/action_select" />
|
||||
<item android:state_activated="true" android:drawable="@color/action_select" />
|
||||
<item android:drawable="@android:color/transparent" />
|
||||
</selector>
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (c) 2015 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/>.
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
<EditText
|
||||
android:id="@+id/edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:fontFamily="light"
|
||||
android:padding="4dp"
|
||||
android:layout_marginLeft="16dp"
|
||||
android:layout_marginRight="16dp"
|
||||
android:hint="@string/name"
|
||||
android:singleLine="true"
|
||||
android:maxLines="1"
|
||||
android:gravity="center_vertical"
|
||||
android:imeOptions="actionDone"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:inputType="textAutoComplete|textAutoCorrect"
|
||||
/>
|
||||
</FrameLayout>
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
<?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
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<EditText
|
||||
android:id="@+id/edit_text"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:fontFamily="light"
|
||||
android:padding="4dp"
|
||||
android:hint="@string/name"
|
||||
android:singleLine="true"
|
||||
android:maxLines="1"
|
||||
android:gravity="center_vertical"
|
||||
android:imeOptions="actionDone"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:inputType="textAutoComplete|textAutoCorrect"
|
||||
/>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?android:attr/dividerHorizontal"/>
|
||||
|
||||
<LinearLayout
|
||||
style="?android:attr/buttonBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_cancel"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="light"
|
||||
android:text="@android:string/cancel"/>
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_ok"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="light"
|
||||
android:text="@android:string/ok"/>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
|
@ -28,25 +28,33 @@
|
|||
|
||||
<ImageView
|
||||
android:id="@+id/item_icon"
|
||||
android:src="@drawable/ic_collections_collection_light"
|
||||
android:src="@drawable/ic_file_folder"
|
||||
android:visibility="visible"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
tools:ignore="ContentDescription"/>
|
||||
tools:ignore="ContentDescription"
|
||||
android:tint="?attr/colorAccent"
|
||||
android:adjustViewBounds="true"/>
|
||||
|
||||
<CheckedTextView
|
||||
<TextView
|
||||
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"/>
|
||||
android:singleLine="true"
|
||||
android:text="@string/name"/>
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/checkbox"
|
||||
android:paddingEnd="8dp"
|
||||
android:paddingRight="8dp"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
|
@ -23,28 +23,29 @@
|
|||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:minHeight="?android:listPreferredItemHeight"
|
||||
android:orientation="horizontal"
|
||||
android:background="@drawable/selectable_background_filepickertheme">
|
||||
|
||||
android:background="@drawable/selectable_background_filepickertheme"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/item_icon"
|
||||
android:src="@drawable/ic_collections_collection_light"
|
||||
android:src="@drawable/ic_file_folder"
|
||||
android:visibility="visible"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
tools:ignore="ContentDescription"/>
|
||||
tools:ignore="ContentDescription"
|
||||
android:tint="?attr/colorAccent"
|
||||
android:adjustViewBounds="true"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="0dp"
|
||||
android:layout_weight="1"
|
||||
android:layout_height="match_parent"
|
||||
style="?android:textAppearanceLarge"
|
||||
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"/>
|
||||
android:singleLine="true"
|
||||
android:text="@string/name"/>
|
||||
</LinearLayout>
|
||||
|
|
@ -18,103 +18,60 @@
|
|||
-->
|
||||
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".FilePickerActivity">
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context=".FilePickerActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/action_container"
|
||||
<android.support.v7.widget.Toolbar
|
||||
android:id="@+id/picker_toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:orientation="horizontal"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@color/dark_grey"
|
||||
android:layout_height="?android:listPreferredItemHeight">
|
||||
android:background="?attr/colorPrimary"
|
||||
android:minHeight="?attr/actionBarSize"
|
||||
android:theme="@style/ThemeOverlay.AppCompat.ActionBar">
|
||||
|
||||
<ImageButton
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:src="@drawable/ic_navigation_back"
|
||||
android:background="@drawable/selectable_action"
|
||||
android:clickable="true"
|
||||
android:scaleType="fitCenter"
|
||||
android:contentDescription="@string/go_back"
|
||||
android:id="@+id/button_go_parent"/>
|
||||
|
||||
<ImageButton
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="1"
|
||||
android:background="@drawable/selectable_action"
|
||||
android:id="@+id/button_create_dir"
|
||||
android:src="@drawable/ic_collections_add_collection"
|
||||
android:clickable="true"
|
||||
android:contentDescription="@string/new_folder"
|
||||
android:scaleType="fitCenter"/>
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/current_dir"
|
||||
android:layout_below="@id/action_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/grey"
|
||||
android:fontFamily="light"
|
||||
android:maxLines="1"
|
||||
android:singleLine="true"
|
||||
android:scrollHorizontally="false"
|
||||
android:ellipsize="start"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:padding="4dp"
|
||||
android:gravity="center_vertical"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
/>
|
||||
|
||||
<ListView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/current_dir"
|
||||
android:id="@android:id/list"
|
||||
android:layout_above="@+id/button_container"
|
||||
tools:listitem="@layout/filepicker_listitem_dir"/>
|
||||
|
||||
<LinearLayout android:id="@+id/button_container"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="?android:attr/dividerHorizontal"/>
|
||||
|
||||
<LinearLayout
|
||||
style="?android:attr/buttonBarStyle"
|
||||
<TextView
|
||||
android:id="@+id/current_dir"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal">
|
||||
android:ellipsize="start"
|
||||
android:singleLine="true"
|
||||
android:textColor="@android:color/white"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Widget.ActionBar.Title" />
|
||||
</android.support.v7.widget.Toolbar>
|
||||
|
||||
<android.support.v7.widget.RecyclerView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_above="@+id/button_container"
|
||||
android:layout_below="@+id/picker_toolbar"
|
||||
tools:listitem="@layout/filepicker_listitem_dir" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/button_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_cancel"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
style="?android:attr/borderlessButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="light"
|
||||
android:text="@android:string/cancel"/>
|
||||
android:text="@android:string/cancel" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/button_ok"
|
||||
style="?android:attr/buttonBarButtonStyle"
|
||||
style="?android:attr/borderlessButtonStyle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:layout_weight="1"
|
||||
android:fontFamily="light"
|
||||
android:text="@android:string/ok"/>
|
||||
</LinearLayout>
|
||||
android:text="@android:string/ok" />
|
||||
|
||||
</LinearLayout>
|
||||
</RelativeLayout>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
<item android:id="@+id/action_createdir"
|
||||
android:title="@string/new_folder"
|
||||
app:showAsAction="always"
|
||||
android:orderInCategory="1"
|
||||
android:icon="@drawable/ic_collections_add_collection"
|
||||
/>
|
||||
</menu>
|
||||
|
|
@ -1,22 +0,0 @@
|
|||
<?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/>.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<dimen name="configure_dialog_width">480dp</dimen>
|
||||
<dimen name="configure_dialog_max_height">600dp</dimen>
|
||||
</resources>
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
<?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/>.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<style name="FilePicker.Theme.Base"
|
||||
parent="android:Theme.Holo.Light.Dialog">
|
||||
<item name="isDialog">true</item>
|
||||
<item name="android:windowIsFloating">false</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowSoftInputMode">stateAlwaysHidden</item>
|
||||
<item name="android:windowIsTranslucent">true</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
<?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/>.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
|
||||
<declare-styleable name="FilePickerTheme">
|
||||
<attr name="isDialog" format="boolean" />
|
||||
</declare-styleable>
|
||||
|
||||
</resources>
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
<?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/>.
|
||||
-->
|
||||
|
||||
<resources>
|
||||
<color name="grey">#e6e6e6</color>
|
||||
<color name="dark_grey">#4d4d4d</color>
|
||||
<color name="action_select">#6d6d6d</color>
|
||||
</resources>
|
||||
|
|
@ -20,24 +20,5 @@
|
|||
<string name="new_folder">New folder</string>
|
||||
<string name="create_folder_error">Failed to create folder</string>
|
||||
<string name="name">Name</string>
|
||||
<string name="go_back">Go back</string>
|
||||
<string name="select_something_first">Please select something first</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>
|
||||
</plurals>
|
||||
|
||||
<plurals
|
||||
name="select_dir_or_file">
|
||||
<item quantity="one">Select directory or file</item>
|
||||
<item quantity="other">Select directories or files</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
|
|
|
|||
|
|
@ -1,50 +0,0 @@
|
|||
<!--
|
||||
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/>.
|
||||
-->
|
||||
|
||||
<resources xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<!-- This base is overridden for larger displays -->
|
||||
<style name="FilePicker.Theme.Base" parent="android:Theme.Holo.Light">
|
||||
<item name="isDialog">false</item>
|
||||
</style>
|
||||
|
||||
<style name="FilePicker.Theme" parent="FilePicker.Theme.Base">
|
||||
<item name="android:actionBarStyle">@style/FilePicker.ActionBar</item>
|
||||
<item name="android:actionOverflowButtonStyle">@style/FilePicker.ActionButton.Overflow</item>
|
||||
<item name="android:actionBarItemBackground">@drawable/ab_solid_filepickertheme</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowShowWallpaper">true</item>
|
||||
<!--<item name="android:windowBackground">@android:color
|
||||
/transparent</item>-->
|
||||
<!--<item name="android:actionBarWidgetTheme">@android:style/Theme.Holo</item>-->
|
||||
<item name="android:textAppearance">?android:attr/textAppearanceLarge</item>
|
||||
</style>
|
||||
|
||||
<style name="FilePicker.ActionBar" parent="android:Widget.Holo.Light.ActionBar.Solid.Inverse">
|
||||
<item name="android:background">@drawable/ab_solid_filepickertheme</item>
|
||||
<item name="android:displayOptions">disableHome|showTitle</item>
|
||||
<item name="android:windowContentOverlay">@null</item>
|
||||
<item name="android:windowShowWallpaper">true</item>
|
||||
<item name="android:windowBackground">@android:color/transparent</item>
|
||||
</style>
|
||||
|
||||
<style name="FilePicker.ActionButton.Overflow" parent="android:Widget.Holo.ActionButton.Overflow">
|
||||
<!--<item name="android:src">@drawable/ic_action_overflow</item>-->
|
||||
</style>
|
||||
|
||||
|
||||
</resources>
|
||||
|
|
@ -30,8 +30,8 @@ android {
|
|||
|
||||
buildTypes {
|
||||
release {
|
||||
runProguard false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
//runProguard false
|
||||
//proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,31 +33,44 @@
|
|||
<!-- Sample app -->
|
||||
<activity
|
||||
android:name="com.nononsenseapps.filepicker.sample.NoNonsenseFilePicker"
|
||||
android:label="@string/title_activity_no_nonsense_file_picker"
|
||||
android:theme ="@style/SampleTheme">
|
||||
android:label="@string/title_activity_no_nonsense_file_picker">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- SD-card picker -->
|
||||
<!-- SD-card pickers -->
|
||||
<activity
|
||||
android:name="com.nononsenseapps.filepicker.FilePickerActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/FilePicker.Theme">
|
||||
android:theme="@style/SampleTheme">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.GET_CONTENT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Dropbox picker -->
|
||||
<activity
|
||||
android:name="com.nononsenseapps.filepicker.sample.FilePickerActivity2"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/SampleThemeLight">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.GET_CONTENT" />
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Dropbox pickers -->
|
||||
<activity
|
||||
android:name="com.nononsenseapps.filepicker.sample.dropbox.DropboxFilePickerActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/FilePicker.Theme">
|
||||
android:theme="@style/SampleTheme">
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.nononsenseapps.filepicker.sample.dropbox.DropboxFilePickerActivity2"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/SampleThemeLight">
|
||||
</activity>
|
||||
<!-- Dropbox authenticator -->
|
||||
<activity
|
||||
|
|
@ -66,7 +79,7 @@
|
|||
android:configChanges="orientation|keyboard">
|
||||
<intent-filter>
|
||||
<!-- Change this to be db- followed by your app key -->
|
||||
<data android:scheme="db-YOUR_APP_KEY_HERE" />
|
||||
<data android:scheme="db-sm57t7s6lmgj745" />
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
<category android:name="android.intent.category.BROWSABLE"/>
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright (c) 2015 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.sample;
|
||||
|
||||
|
||||
import com.nononsenseapps.filepicker.FilePickerActivity;
|
||||
|
||||
/**
|
||||
* This is a copy of the included activity for the sole purpose
|
||||
* of being to show you a second example theme
|
||||
*/
|
||||
public class FilePickerActivity2 extends FilePickerActivity {
|
||||
}
|
||||
|
|
@ -17,7 +17,6 @@
|
|||
|
||||
package com.nononsenseapps.filepicker.sample;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.app.Activity;
|
||||
import android.content.ClipData;
|
||||
import android.content.Intent;
|
||||
|
|
@ -36,6 +35,7 @@ import com.dropbox.client2.android.AndroidAuthSession;
|
|||
import com.nononsenseapps.filepicker.AbstractFilePickerFragment;
|
||||
import com.nononsenseapps.filepicker.FilePickerActivity;
|
||||
import com.nononsenseapps.filepicker.sample.dropbox.DropboxFilePickerActivity;
|
||||
import com.nononsenseapps.filepicker.sample.dropbox.DropboxFilePickerActivity2;
|
||||
import com.nononsenseapps.filepicker.sample.dropbox.DropboxSyncHelper;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
|
@ -57,17 +57,26 @@ public class NoNonsenseFilePicker extends Activity {
|
|||
(CheckBox) findViewById(R.id.checkAllowCreateDir);
|
||||
final CheckBox checkAllowMultiple =
|
||||
(CheckBox) findViewById(R.id.checkAllowMultiple);
|
||||
final CheckBox checkLightTheme =
|
||||
(CheckBox) findViewById(R.id.checkLightTheme);
|
||||
final RadioGroup radioGroup =
|
||||
(RadioGroup) findViewById(R.id.radioGroup);
|
||||
textView = (TextView) findViewById(R.id.text);
|
||||
|
||||
findViewById(R.id.button)
|
||||
findViewById(R.id.button_sd)
|
||||
.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(final View v) {
|
||||
//Intent i = new Intent(NoNonsenseFilePicker.this,
|
||||
// FilePickerActivity.class);
|
||||
Intent i = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
Intent i;
|
||||
|
||||
if (checkLightTheme.isChecked()) {
|
||||
i = new Intent(NoNonsenseFilePicker.this,
|
||||
FilePickerActivity2.class);
|
||||
} else {
|
||||
i = new Intent(NoNonsenseFilePicker.this,
|
||||
FilePickerActivity.class);
|
||||
}
|
||||
i.setAction(Intent.ACTION_GET_CONTENT);
|
||||
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE,
|
||||
checkAllowMultiple.isChecked());
|
||||
|
|
@ -113,8 +122,14 @@ public class NoNonsenseFilePicker extends Activity {
|
|||
mDBApi.getSession().startOAuth2Authentication(
|
||||
NoNonsenseFilePicker.this);
|
||||
} else { // User is authorized, open file picker
|
||||
Intent i = new Intent(NoNonsenseFilePicker.this,
|
||||
DropboxFilePickerActivity.class);
|
||||
Intent i;
|
||||
if (checkLightTheme.isChecked()) {
|
||||
i = new Intent(NoNonsenseFilePicker.this,
|
||||
DropboxFilePickerActivity2.class);
|
||||
} else {
|
||||
i = new Intent(NoNonsenseFilePicker.this,
|
||||
DropboxFilePickerActivity.class);
|
||||
}
|
||||
|
||||
i.putExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE,
|
||||
checkAllowMultiple.isChecked());
|
||||
|
|
@ -182,12 +197,11 @@ public class NoNonsenseFilePicker extends Activity {
|
|||
return id == R.id.action_settings || super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode,
|
||||
Intent data) {
|
||||
Intent data) {
|
||||
if ((CODE_SD == requestCode || CODE_DB == requestCode) &&
|
||||
resultCode == Activity.RESULT_OK) {
|
||||
resultCode == Activity.RESULT_OK) {
|
||||
if (data.getBooleanExtra(FilePickerActivity.EXTRA_ALLOW_MULTIPLE,
|
||||
false)) {
|
||||
|
||||
|
|
@ -216,7 +230,6 @@ public class NoNonsenseFilePicker extends Activity {
|
|||
}
|
||||
textView.setText(sb.toString());
|
||||
}
|
||||
|
||||
} else {
|
||||
textView.setText(data.getData().toString());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ import com.nononsenseapps.filepicker.AbstractFilePickerFragment;
|
|||
|
||||
|
||||
public class DropboxFilePickerActivity
|
||||
extends AbstractFilePickerActivity<DropboxAPI.Entry> {
|
||||
extends AbstractFilePickerActivity<DropboxAPI.Entry> {
|
||||
|
||||
// In the class declaration section:
|
||||
private DropboxAPI<AndroidAuthSession> mDBApi;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2015 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.sample.dropbox;
|
||||
|
||||
/**
|
||||
* This is a copy of the included activity for the sole purpose
|
||||
* of being to show you a second example theme
|
||||
*/
|
||||
public class DropboxFilePickerActivity2 extends DropboxFilePickerActivity {
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2014 Jonas Kalderstam
|
||||
* Copyright (c) 2015 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
|
||||
|
|
@ -18,10 +18,13 @@
|
|||
package com.nononsenseapps.filepicker.sample.dropbox;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.AsyncTaskLoader;
|
||||
import android.content.Loader;
|
||||
import android.net.Uri;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.v4.content.AsyncTaskLoader;
|
||||
import android.support.v4.content.Loader;
|
||||
import android.support.v7.util.SortedList;
|
||||
import android.support.v7.widget.util.SortedListAdapterCallback;
|
||||
import android.text.TextUtils;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.dropbox.client2.DropboxAPI;
|
||||
|
|
@ -31,9 +34,6 @@ import com.nononsenseapps.filepicker.AbstractFilePickerFragment;
|
|||
import com.nononsenseapps.filepicker.sample.R;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
@SuppressLint("ValidFragment")
|
||||
public class DropboxFilePickerFragment
|
||||
|
|
@ -54,6 +54,7 @@ public class DropboxFilePickerFragment
|
|||
this.dbApi = api;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNewFolder(final String name) {
|
||||
File folder = new File(currentPath.path, name);
|
||||
|
||||
|
|
@ -64,37 +65,19 @@ public class DropboxFilePickerFragment
|
|||
folderCreator.execute(folder.getPath());
|
||||
}
|
||||
|
||||
private class FolderCreator extends AsyncTask<String, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(final String... paths) {
|
||||
for (String path : paths) {
|
||||
try {
|
||||
dbApi.createFolder(path);
|
||||
currentPath = dbApi.metadata(path, 1, null, false, null);
|
||||
refresh();
|
||||
} catch (DropboxException e) {
|
||||
Toast.makeText(getActivity(), R.string.create_folder_error,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isDir(final DropboxAPI.Entry file) {
|
||||
public boolean isDir(final DropboxAPI.Entry file) {
|
||||
return file.isDir;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DropboxAPI.Entry getParent(final DropboxAPI.Entry from) {
|
||||
public DropboxAPI.Entry getParent(final DropboxAPI.Entry from) {
|
||||
// Take care of a slight limitation in Dropbox code:
|
||||
if (from.path.length() > 1 && from.path.endsWith("/")) {
|
||||
from.path = from.path.substring(0, from.path.length() - 1);
|
||||
}
|
||||
String parent = from.parentPath();
|
||||
if (parent.isEmpty()) {
|
||||
if (TextUtils.isEmpty(parent)) {
|
||||
parent = "/";
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +86,7 @@ public class DropboxFilePickerFragment
|
|||
}
|
||||
|
||||
@Override
|
||||
protected DropboxAPI.Entry getPath(final String path) {
|
||||
public DropboxAPI.Entry getPath(final String path) {
|
||||
final DropboxAPI.Entry entry = new DropboxAPI.Entry();
|
||||
entry.path = path;
|
||||
entry.isDir = true;
|
||||
|
|
@ -112,51 +95,56 @@ public class DropboxFilePickerFragment
|
|||
}
|
||||
|
||||
@Override
|
||||
protected String getFullPath(final DropboxAPI.Entry file) {
|
||||
public String getFullPath(final DropboxAPI.Entry file) {
|
||||
return file.path;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName(final DropboxAPI.Entry file) {
|
||||
public String getName(final DropboxAPI.Entry file) {
|
||||
return file.fileName();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DropboxAPI.Entry getRoot() {
|
||||
public DropboxAPI.Entry getRoot() {
|
||||
return getPath("/");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Uri toUri(final DropboxAPI.Entry file) {
|
||||
return new Uri.Builder().scheme("dropbox").path(file.path).build();
|
||||
public Uri toUri(final DropboxAPI.Entry file) {
|
||||
return new Uri.Builder().scheme("dropbox").authority("").path(file.path).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Comparator<DropboxAPI.Entry> getComparator() {
|
||||
return new Comparator<DropboxAPI.Entry>() {
|
||||
@Override
|
||||
public int compare(final DropboxAPI.Entry lhs,
|
||||
final DropboxAPI.Entry rhs) {
|
||||
if (isDir(lhs) && !isDir(rhs)) {
|
||||
return -1;
|
||||
} else if (isDir(rhs) && !isDir(lhs)) {
|
||||
return 1;
|
||||
} else {
|
||||
return lhs.fileName().toLowerCase()
|
||||
.compareTo(rhs.fileName().toLowerCase());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Loader<List<DropboxAPI.Entry>> getLoader() {
|
||||
return new AsyncTaskLoader<List<DropboxAPI.Entry>>(getActivity()) {
|
||||
public Loader<SortedList<DropboxAPI.Entry>> getLoader() {
|
||||
return new AsyncTaskLoader<SortedList<DropboxAPI.Entry>>(getActivity()) {
|
||||
|
||||
@Override
|
||||
public List<DropboxAPI.Entry> loadInBackground() {
|
||||
ArrayList<DropboxAPI.Entry> files =
|
||||
new ArrayList<DropboxAPI.Entry>();
|
||||
public SortedList<DropboxAPI.Entry> loadInBackground() {
|
||||
SortedList<DropboxAPI.Entry> files = new SortedList<>(DropboxAPI.Entry.class,
|
||||
new SortedListAdapterCallback<DropboxAPI.Entry>(getAdapter()) {
|
||||
@Override
|
||||
public int compare(DropboxAPI.Entry lhs, DropboxAPI.Entry rhs) {
|
||||
if (isDir(lhs) && !isDir(rhs)) {
|
||||
return -1;
|
||||
} else if (isDir(rhs) && !isDir(lhs)) {
|
||||
return 1;
|
||||
} else {
|
||||
return lhs.fileName().toLowerCase()
|
||||
.compareTo(rhs.fileName().toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(DropboxAPI.Entry lhs, DropboxAPI.Entry rhs) {
|
||||
return lhs.fileName().equals(rhs.fileName()) && (lhs.isDir == rhs.isDir);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(DropboxAPI.Entry lhs, DropboxAPI.Entry rhs) {
|
||||
return areContentsTheSame(lhs, rhs);
|
||||
}
|
||||
}, 0);
|
||||
|
||||
try {
|
||||
|
||||
if (!dbApi.metadata(currentPath.path, 1, null, false,
|
||||
|
|
@ -167,13 +155,18 @@ public class DropboxFilePickerFragment
|
|||
DropboxAPI.Entry dirEntry =
|
||||
dbApi.metadata(currentPath.path, 0, null, true,
|
||||
null);
|
||||
|
||||
files.beginBatchedUpdates();
|
||||
|
||||
for (DropboxAPI.Entry entry : dirEntry.contents) {
|
||||
if ((mode == MODE_FILE || mode == MODE_FILE_AND_DIR) ||
|
||||
entry.isDir) {
|
||||
entry.isDir) {
|
||||
files.add(entry);
|
||||
}
|
||||
}
|
||||
} catch (DropboxException e) {
|
||||
|
||||
files.endBatchedUpdates();
|
||||
} catch (DropboxException ignored) {
|
||||
}
|
||||
|
||||
return files;
|
||||
|
|
@ -203,5 +196,21 @@ public class DropboxFilePickerFragment
|
|||
};
|
||||
}
|
||||
|
||||
private class FolderCreator extends AsyncTask<String, Void, Void> {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(final String... paths) {
|
||||
for (String path : paths) {
|
||||
try {
|
||||
dbApi.createFolder(path);
|
||||
currentPath = dbApi.metadata(path, 1, null, false, null);
|
||||
refresh();
|
||||
} catch (DropboxException e) {
|
||||
Toast.makeText(getActivity(), R.string.create_folder_error,
|
||||
Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -37,8 +37,8 @@ import com.dropbox.client2.session.AppKeyPair;
|
|||
*/
|
||||
public class DropboxSyncHelper {
|
||||
// Change these two lines to your app's stuff
|
||||
final static public String APP_KEY = "INSERT_APP_KEY";
|
||||
final static public String APP_SECRET = "INSERT_APP_SECRET";
|
||||
final static public String APP_KEY = "sm57t7s6lmgj745";
|
||||
final static public String APP_SECRET = "eie6mq0lvcw9t7x";
|
||||
|
||||
public static final String PREF_DROPBOX_TOKEN = "dropboxtoken";
|
||||
|
||||
|
|
|
|||
|
|
@ -14,128 +14,136 @@
|
|||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
-->
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/scrollView">
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:orientation="vertical"
|
||||
tools:context="com.nononsenseapps.filepicker.sample.NoNonsenseFilePicker">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:id="@+id/scrollView"
|
||||
android:layout_gravity="center_horizontal">
|
||||
|
||||
</ScrollView>
|
||||
|
||||
<LinearLayout
|
||||
<FrameLayout android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingLeft="@dimen/activity_horizontal_margin"
|
||||
android:paddingRight="@dimen/activity_horizontal_margin"
|
||||
android:paddingTop="@dimen/activity_vertical_margin"
|
||||
android:paddingBottom="@dimen/activity_vertical_margin"
|
||||
android:orientation="vertical"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
tools:context="com.nononsenseapps.filepicker.sample.NoNonsenseFilePicker">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/radioGroup"
|
||||
<LinearLayout
|
||||
android:orientation="vertical"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/radioGroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Select file"
|
||||
android:id="@+id/radioFile"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:checked="true"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="left"/>
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Select directory"
|
||||
android:id="@+id/radioDir"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="left"/>
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Select any"
|
||||
android:id="@+id/radioFilesAndDirs"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="left"/>
|
||||
</RadioGroup>
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:text="Multiple items"
|
||||
android:gravity="center_vertical"
|
||||
android:id="@+id/checkAllowMultiple"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:layout_gravity="left"/>
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:text="Allow creation of directories\n(if selecting directories)"
|
||||
android:id="@+id/checkAllowCreateDir"
|
||||
android:gravity="center_vertical"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:layout_gravity="left"/>
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:text="Use light theme"
|
||||
android:id="@+id/checkLightTheme"
|
||||
android:gravity="center_vertical"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:layout_gravity="left"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:text="Pick SD-card"
|
||||
android:layout_marginTop="16dp"
|
||||
android:id="@+id/button_sd"
|
||||
android:gravity="center"
|
||||
style="?android:attr/borderlessButtonStyle"
|
||||
android:fontFamily="light"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="64dp"
|
||||
android:text="Pick Dropbox"
|
||||
android:layout_marginTop="8dp"
|
||||
android:id="@+id/button_dropbox"
|
||||
android:gravity="center"
|
||||
style="?android:attr/borderlessButtonStyle"
|
||||
android:fontFamily="light"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:padding="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:text="Result will be displayed here"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
>
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Select file"
|
||||
android:id="@+id/radioFile"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:checked="true"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="left"/>
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Select directory"
|
||||
android:id="@+id/radioDir"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="left"/>
|
||||
|
||||
<RadioButton
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Select any"
|
||||
android:id="@+id/radioFilesAndDirs"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:gravity="center_vertical"
|
||||
android:layout_gravity="left"/>
|
||||
</RadioGroup>
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:text="Multiple items"
|
||||
android:gravity="center_vertical"
|
||||
android:id="@+id/checkAllowMultiple"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:layout_gravity="left"/>
|
||||
|
||||
<CheckBox
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:text="Allow creation of directories\n(if selecting directories)"
|
||||
android:id="@+id/checkAllowCreateDir"
|
||||
android:gravity="center_vertical"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:layout_gravity="left"/>
|
||||
|
||||
android:layout_gravity="center_horizontal"/>
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:text="Pick SD-card"
|
||||
android:layout_marginTop="8dp"
|
||||
android:id="@+id/button"
|
||||
android:gravity="center_vertical"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<Button
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:text="Pick Dropbox"
|
||||
android:layout_marginTop="8dp"
|
||||
android:id="@+id/button_dropbox"
|
||||
android:gravity="center_vertical"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:layout_gravity="center"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/text"
|
||||
android:padding="16dp"
|
||||
android:text="Result will be displayed here"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
style="?android:textAppearanceMedium"
|
||||
android:fontFamily="light"
|
||||
android:layout_gravity="center_horizontal"/>
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
||||
</FrameLayout>
|
||||
</ScrollView>
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="primary">#607D8B</color>
|
||||
<color name="primary_dark">#455A64</color>
|
||||
<color name="accent">#536DFE</color>
|
||||
|
||||
|
||||
<color name="primary2">#F44336</color>
|
||||
<color name="primary_dark2">#D32F2F</color>
|
||||
<color name="accent2">#FFAB00</color>
|
||||
</resources>
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
Copyright (c) 2014 Jonas Kalderstam
|
||||
Copyright (c) 2015 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
|
||||
|
|
@ -17,6 +17,40 @@
|
|||
|
||||
<resources>
|
||||
|
||||
<style name="SampleTheme" parent="android:Theme.Holo.Light.DarkActionBar" />
|
||||
<style name="SampleTheme" parent="Theme.AppCompat.DialogWhenLarge">
|
||||
<item name="colorPrimary">@color/primary2</item>
|
||||
<item name="colorPrimaryDark">@color/primary_dark2</item>
|
||||
<item name="colorAccent">@color/accent2</item>
|
||||
|
||||
<item name="alertDialogTheme">@style/SampleAlertDialogTheme</item>
|
||||
|
||||
<!-- These are important. Handled by toolbar -->
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<style name="SampleThemeLight" parent="Theme.AppCompat.Light.DialogWhenLarge">
|
||||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryDark">@color/primary_dark</item>
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
|
||||
<item name="alertDialogTheme">@style/SampleAlertDialogThemeLight</item>
|
||||
|
||||
<!-- These are important. Handled by toolbar -->
|
||||
<item name="windowActionBar">false</item>
|
||||
<item name="windowNoTitle">true</item>
|
||||
</style>
|
||||
|
||||
<style name="SampleAlertDialogTheme" parent="Theme.AppCompat.Dialog.Alert">
|
||||
<item name="colorPrimary">@color/primary2</item>
|
||||
<item name="colorPrimaryDark">@color/primary_dark2</item>
|
||||
<item name="colorAccent">@color/accent2</item>
|
||||
</style>
|
||||
|
||||
<style name="SampleAlertDialogThemeLight" parent="Theme.AppCompat.Light.Dialog.Alert">
|
||||
<item name="colorPrimary">@color/primary</item>
|
||||
<item name="colorPrimaryDark">@color/primary_dark</item>
|
||||
<item name="colorAccent">@color/accent</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
|
|
|||