diff --git a/build.gradle b/build.gradle index b488131..8e50b18 100644 --- a/build.gradle +++ b/build.gradle @@ -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" } } diff --git a/gradle.properties b/gradle.properties index 50eeac7..60bb1d9 100644 --- a/gradle.properties +++ b/gradle.properties @@ -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 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index f82ff71..4d98bfb 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -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 diff --git a/library/build.gradle b/library/build.gradle index 7b8e6a7..38e0cd6 100644 --- a/library/build.gradle +++ b/library/build.gradle @@ -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' diff --git a/library/src/main/java/com/nononsenseapps/filepicker/AbstractFilePickerActivity.java b/library/src/main/java/com/nononsenseapps/filepicker/AbstractFilePickerActivity.java index 1b8ee88..c6ca9ed 100644 --- a/library/src/main/java/com/nononsenseapps/filepicker/AbstractFilePickerActivity.java +++ b/library/src/main/java/com/nononsenseapps/filepicker/AbstractFilePickerActivity.java @@ -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 */ -public abstract class AbstractFilePickerActivity extends Activity +public abstract class AbstractFilePickerActivity extends AppCompatActivity implements AbstractFilePickerFragment.OnFilePickedListener { public static final String EXTRA_START_PATH = "nononsense.intent" + ".START_PATH"; @@ -85,9 +82,6 @@ public abstract class AbstractFilePickerActivity 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 extends Activity intent.getBooleanExtra(EXTRA_ALLOW_MULTIPLE, allowMultiple); } - FragmentManager fm = getFragmentManager(); + FragmentManager fm = getSupportFragmentManager(); AbstractFilePickerFragment fragment = (AbstractFilePickerFragment) fm.findFragmentByTag(TAG); @@ -120,64 +114,10 @@ public abstract class AbstractFilePickerActivity 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 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); diff --git a/library/src/main/java/com/nononsenseapps/filepicker/AbstractFilePickerFragment.java b/library/src/main/java/com/nononsenseapps/filepicker/AbstractFilePickerFragment.java index d5c1436..b3805cc 100644 --- a/library/src/main/java/com/nononsenseapps/filepicker/AbstractFilePickerFragment.java +++ b/library/src/main/java/com/nononsenseapps/filepicker/AbstractFilePickerFragment.java @@ -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 extends ListFragment - implements LoaderManager.LoaderCallbacks>, - NewItemFragment.OnNewFolderListener, - AdapterView.OnItemLongClickListener { +public abstract class AbstractFilePickerFragment extends Fragment + implements LoaderManager.LoaderCallbacks>, + NewItemFragment.OnNewFolderListener, LogicHandler { // The different preset modes of operation. This impacts the behaviour // and possible actions in the UI. @@ -66,21 +70,34 @@ public abstract class AbstractFilePickerFragment 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 checkedItems; + protected final HashSet checkedItems; + protected final HashSet checkedVisibleViewHolders; protected T currentPath = null; protected boolean allowCreateDir = false; protected boolean allowMultiple = false; - protected Comparator comparator = null; private OnFilePickedListener listener; - private BindableArrayAdapter adapter; + private FileItemAdapter mAdapter = null; private TextView currentDirView; + private Toolbar mToolbar; + private RecyclerView mRecyclerView; + private LinearLayoutManager mLayoutManager; + private SortedList mFiles = null; + + protected FileItemAdapter getAdapter() { + return mAdapter; + } + + protected FileItemAdapter 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(false); + checkedItems = new HashSet<>(); + checkedVisibleViewHolders = new HashSet<>(); } /** @@ -92,7 +109,7 @@ public abstract class AbstractFilePickerFragment 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 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 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 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 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 toUri(List files) { + protected List toUri(Iterable files) { ArrayList uris = new ArrayList(); for (T file : files) { uris.add(toUri(file)); @@ -200,61 +210,11 @@ public abstract class AbstractFilePickerFragment extends ListFragment return uris; } - /** - * @return the selected files. Can be empty. - */ - protected List getCheckedItems() { - final BindableArrayAdapter adapter = - (BindableArrayAdapter) getListAdapter(); - final ArrayList files = new ArrayList(); - 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 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 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 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 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 extends ListFragment .restartLoader(0, null, AbstractFilePickerFragment.this); } - /** - * Callback method to be invoked when an item in this view has been - * clicked and held. - *

- * 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 extends ListFragment * @return Return a new Loader instance that is ready to start loading. */ @Override - public Loader> onCreateLoader(final int id, final Bundle args) { + public Loader> 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> getLoader(); - /** * Called when a previously created loader has finished its load. * @@ -418,125 +337,15 @@ public abstract class AbstractFilePickerFragment extends ListFragment * @param data The data generated by the Loader. */ @Override - public void onLoadFinished(final Loader> loader, - final List data) { - if (adapter == null) { - // View type not really used, overridden in ViewBinder - adapter = new BindableArrayAdapter(getActivity(), - R.layout.filepicker_listitem_checkable); - adapter.setViewBinder(getViewBinder()); - } else { - adapter.clear(); - } - if (comparator == null) { - comparator = getComparator(); - } + public void onLoadFinished(final Loader> loader, + final SortedList 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 getViewBinder() { - class ViewHolder { - protected View icon; - protected TextView text; - protected CheckedTextView checkbox; - } - - return new BindableArrayAdapter.ViewBinder() { - - /** - * 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 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 extends ListFragment * @param loader The Loader that is being reset. */ @Override - public void onLoaderReset(final Loader> loader) { - setListAdapter(null); - adapter = null; + public void onLoaderReset(final Loader> loader) { + mAdapter.setList(null); + mFiles = null; } /** @@ -569,16 +378,202 @@ public abstract class AbstractFilePickerFragment extends ListFragment public void onCancelled(); } - public class DefaultHashMap extends HashMap { - 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(); + } + } diff --git a/library/src/main/java/com/nononsenseapps/filepicker/BindableArrayAdapter.java b/library/src/main/java/com/nononsenseapps/filepicker/BindableArrayAdapter.java deleted file mode 100644 index f270f0e..0000000 --- a/library/src/main/java/com/nononsenseapps/filepicker/BindableArrayAdapter.java +++ /dev/null @@ -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 . - */ - -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 extends ArrayAdapter { - - private final LayoutInflater mInflater; - private final int mResource; - private ViewBinder 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 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 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 { - /** - * 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); - } -} diff --git a/library/src/main/java/com/nononsenseapps/filepicker/FileItemAdapter.java b/library/src/main/java/com/nononsenseapps/filepicker/FileItemAdapter.java new file mode 100644 index 0000000..0cfa309 --- /dev/null +++ b/library/src/main/java/com/nononsenseapps/filepicker/FileItemAdapter.java @@ -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 . + */ + +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 the type which is used, for example a normal java File object. + */ +public class FileItemAdapter extends RecyclerView.Adapter { + + private final LogicHandler mLogic; + private SortedList mList = null; + + public FileItemAdapter(LogicHandler logic) { + this.mLogic = logic; + } + + public void setList(SortedList 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.HeaderViewHolder) viewHolder); + } else { + int pos = headerPosition - 1; + mLogic.onBindViewHolder((AbstractFilePickerFragment.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(); + } +} diff --git a/library/src/main/java/com/nononsenseapps/filepicker/FilePickerFragment.java b/library/src/main/java/com/nononsenseapps/filepicker/FilePickerFragment.java index b154dfe..7f6ff74 100644 --- a/library/src/main/java/com/nononsenseapps/filepicker/FilePickerFragment.java +++ b/library/src/main/java/com/nononsenseapps/filepicker/FilePickerFragment.java @@ -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 { - 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 { * @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 { * @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 { * @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 { * @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 getComparator() { - return new Comparator() { - @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> getLoader() { - return new AsyncTaskLoader>(getActivity()) { + public Loader> getLoader() { + return new AsyncTaskLoader>(getActivity()) { FileObserver fileObserver; @Override - public List loadInBackground() { - ArrayList files = new ArrayList(); + public SortedList loadInBackground() { File[] listFiles = currentPath.listFiles(); - if(listFiles != null) { + final int initCap = listFiles == null ? 0 : listFiles.length; + + SortedList files = new SortedList<>(File.class, new SortedListAdapterCallback(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 { } } } + + files.endBatchedUpdates(); + return files; } @@ -217,4 +228,6 @@ public class FilePickerFragment extends AbstractFilePickerFragment { Toast.LENGTH_SHORT).show(); } } + + } diff --git a/library/src/main/java/com/nononsenseapps/filepicker/LogicHandler.java b/library/src/main/java/com/nononsenseapps/filepicker/LogicHandler.java new file mode 100644 index 0000000..c06eda9 --- /dev/null +++ b/library/src/main/java/com/nononsenseapps/filepicker/LogicHandler.java @@ -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 . + */ + +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 { + + /** + * 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> getLoader(); + + /** + * @return a comparator that can sort the items alphabetically + */ + //public Comparator 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.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.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); +} diff --git a/library/src/main/java/com/nononsenseapps/filepicker/NewFolderFragment.java b/library/src/main/java/com/nononsenseapps/filepicker/NewFolderFragment.java index 5673aa9..3bc73ad 100644 --- a/library/src/main/java/com/nononsenseapps/filepicker/NewFolderFragment.java +++ b/library/src/main/java/com/nononsenseapps/filepicker/NewFolderFragment.java @@ -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(".."); } } diff --git a/library/src/main/java/com/nononsenseapps/filepicker/NewItemFragment.java b/library/src/main/java/com/nononsenseapps/filepicker/NewItemFragment.java index 39d6b16..acb9b13 100644 --- a/library/src/main/java/com/nononsenseapps/filepicker/NewItemFragment.java +++ b/library/src/main/java/com/nononsenseapps/filepicker/NewItemFragment.java @@ -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); diff --git a/library/src/main/res/drawable-hdpi/ab_solid_filepickertheme.9.png b/library/src/main/res/drawable-hdpi/ab_solid_filepickertheme.9.png deleted file mode 100644 index d431708..0000000 Binary files a/library/src/main/res/drawable-hdpi/ab_solid_filepickertheme.9.png and /dev/null differ diff --git a/library/src/main/res/drawable-hdpi/ic_collections_collection_light.png b/library/src/main/res/drawable-hdpi/ic_collections_collection_light.png deleted file mode 100644 index 82ef938..0000000 Binary files a/library/src/main/res/drawable-hdpi/ic_collections_collection_light.png and /dev/null differ diff --git a/library/src/main/res/drawable-hdpi/ic_file_folder.png b/library/src/main/res/drawable-hdpi/ic_file_folder.png new file mode 100644 index 0000000..eeeee8c Binary files /dev/null and b/library/src/main/res/drawable-hdpi/ic_file_folder.png differ diff --git a/library/src/main/res/drawable-hdpi/ic_navigation_back.png b/library/src/main/res/drawable-hdpi/ic_navigation_back.png deleted file mode 100644 index 265c499..0000000 Binary files a/library/src/main/res/drawable-hdpi/ic_navigation_back.png and /dev/null differ diff --git a/library/src/main/res/drawable-mdpi/ab_solid_filepickertheme.9.png b/library/src/main/res/drawable-mdpi/ab_solid_filepickertheme.9.png deleted file mode 100644 index a5826a2..0000000 Binary files a/library/src/main/res/drawable-mdpi/ab_solid_filepickertheme.9.png and /dev/null differ diff --git a/library/src/main/res/drawable-mdpi/ic_collections_collection_light.png b/library/src/main/res/drawable-mdpi/ic_collections_collection_light.png deleted file mode 100644 index d309856..0000000 Binary files a/library/src/main/res/drawable-mdpi/ic_collections_collection_light.png and /dev/null differ diff --git a/library/src/main/res/drawable-mdpi/ic_file_folder.png b/library/src/main/res/drawable-mdpi/ic_file_folder.png new file mode 100644 index 0000000..22fe6fc Binary files /dev/null and b/library/src/main/res/drawable-mdpi/ic_file_folder.png differ diff --git a/library/src/main/res/drawable-mdpi/ic_navigation_back.png b/library/src/main/res/drawable-mdpi/ic_navigation_back.png deleted file mode 100644 index c36e021..0000000 Binary files a/library/src/main/res/drawable-mdpi/ic_navigation_back.png and /dev/null differ diff --git a/library/src/main/res/drawable-xhdpi/ab_solid_filepickertheme.9.png b/library/src/main/res/drawable-xhdpi/ab_solid_filepickertheme.9.png deleted file mode 100644 index fb40717..0000000 Binary files a/library/src/main/res/drawable-xhdpi/ab_solid_filepickertheme.9.png and /dev/null differ diff --git a/library/src/main/res/drawable-xhdpi/ic_collections_collection_light.png b/library/src/main/res/drawable-xhdpi/ic_collections_collection_light.png deleted file mode 100644 index 342718a..0000000 Binary files a/library/src/main/res/drawable-xhdpi/ic_collections_collection_light.png and /dev/null differ diff --git a/library/src/main/res/drawable-xhdpi/ic_file_folder.png b/library/src/main/res/drawable-xhdpi/ic_file_folder.png new file mode 100644 index 0000000..ec59761 Binary files /dev/null and b/library/src/main/res/drawable-xhdpi/ic_file_folder.png differ diff --git a/library/src/main/res/drawable-xhdpi/ic_navigation_back.png b/library/src/main/res/drawable-xhdpi/ic_navigation_back.png deleted file mode 100644 index fe8a4e4..0000000 Binary files a/library/src/main/res/drawable-xhdpi/ic_navigation_back.png and /dev/null differ diff --git a/library/src/main/res/drawable-xxhdpi/ab_solid_filepickertheme.9.png b/library/src/main/res/drawable-xxhdpi/ab_solid_filepickertheme.9.png deleted file mode 100644 index 354813d..0000000 Binary files a/library/src/main/res/drawable-xxhdpi/ab_solid_filepickertheme.9.png and /dev/null differ diff --git a/library/src/main/res/drawable-xxhdpi/ic_collections_collection_light.png b/library/src/main/res/drawable-xxhdpi/ic_collections_collection_light.png deleted file mode 100644 index e6bbbcc..0000000 Binary files a/library/src/main/res/drawable-xxhdpi/ic_collections_collection_light.png and /dev/null differ diff --git a/library/src/main/res/drawable-xxhdpi/ic_file_folder.png b/library/src/main/res/drawable-xxhdpi/ic_file_folder.png new file mode 100644 index 0000000..05f6a9c Binary files /dev/null and b/library/src/main/res/drawable-xxhdpi/ic_file_folder.png differ diff --git a/library/src/main/res/drawable-xxhdpi/ic_navigation_back.png b/library/src/main/res/drawable-xxhdpi/ic_navigation_back.png deleted file mode 100644 index 62b086e..0000000 Binary files a/library/src/main/res/drawable-xxhdpi/ic_navigation_back.png and /dev/null differ diff --git a/library/src/main/res/drawable/selectable_action.xml b/library/src/main/res/drawable/selectable_action.xml deleted file mode 100644 index cd12f00..0000000 --- a/library/src/main/res/drawable/selectable_action.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - \ No newline at end of file diff --git a/library/src/main/res/layout/dialog_folder_name.xml b/library/src/main/res/layout/dialog_folder_name.xml new file mode 100644 index 0000000..e06a59c --- /dev/null +++ b/library/src/main/res/layout/dialog_folder_name.xml @@ -0,0 +1,38 @@ + + + + + + \ No newline at end of file diff --git a/library/src/main/res/layout/dialog_new_item.xml b/library/src/main/res/layout/dialog_new_item.xml deleted file mode 100644 index cc26f4a..0000000 --- a/library/src/main/res/layout/dialog_new_item.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - -