From e61530a328903da758f9578c75d5ddebf9315701 Mon Sep 17 00:00:00 2001 From: Doplgangr Date: Wed, 20 May 2015 12:22:57 +0800 Subject: [PATCH 1/7] Create file chooser fragment --- .../secrecy/adapters/FileChooserAdapter.java | 79 ++++++ .../fragments/FileChooserFragment.java | 235 ++++++++++++++++++ .../com/doplgangr/secrecy/utils/Util.java | 19 ++ .../main/res/drawable-hdpi/ic_action_done.png | Bin 0 -> 223 bytes .../res/drawable-hdpi/ic_action_folder.png | Bin 0 -> 148 bytes .../main/res/drawable-mdpi/ic_action_done.png | Bin 0 -> 166 bytes .../res/drawable-mdpi/ic_action_folder.png | Bin 0 -> 127 bytes .../res/drawable-xhdpi/ic_action_done.png | Bin 0 -> 265 bytes .../res/drawable-xhdpi/ic_action_folder.png | Bin 0 -> 199 bytes .../res/drawable-xxhdpi/ic_action_done.png | Bin 0 -> 371 bytes .../res/drawable-xxhdpi/ic_action_folder.png | Bin 0 -> 267 bytes .../res/drawable-xxxhdpi/ic_action_done.png | Bin 0 -> 459 bytes .../res/drawable-xxxhdpi/ic_action_folder.png | Bin 0 -> 359 bytes .../res/layout/fragment_filechooser_grid.xml | 20 ++ .../res/layout/fragment_filechooser_list.xml | 18 ++ .../res/layout/listitem_single_line_text.xml | 24 ++ app/src/main/res/menu/file_chooser.xml | 14 ++ app/src/main/res/values-large/refs.xml | 12 + app/src/main/res/values-sw600dp/refs.xml | 12 + app/src/main/res/values/color.xml | 1 + app/src/main/res/values/refs.xml | 12 + 21 files changed, 446 insertions(+) create mode 100644 app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java create mode 100644 app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java create mode 100644 app/src/main/res/drawable-hdpi/ic_action_done.png create mode 100644 app/src/main/res/drawable-hdpi/ic_action_folder.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_done.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_folder.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_done.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_folder.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_done.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_folder.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_action_done.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_action_folder.png create mode 100644 app/src/main/res/layout/fragment_filechooser_grid.xml create mode 100644 app/src/main/res/layout/fragment_filechooser_list.xml create mode 100644 app/src/main/res/layout/listitem_single_line_text.xml create mode 100644 app/src/main/res/menu/file_chooser.xml create mode 100644 app/src/main/res/values-large/refs.xml create mode 100644 app/src/main/res/values-sw600dp/refs.xml create mode 100644 app/src/main/res/values/refs.xml diff --git a/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java b/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java new file mode 100644 index 0000000..bc4970b --- /dev/null +++ b/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java @@ -0,0 +1,79 @@ +package com.doplgangr.secrecy.adapters; + +import android.content.Context; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.drawable.Drawable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.doplgangr.secrecy.R; +import com.doplgangr.secrecy.filesystem.Storage; +import com.doplgangr.secrecy.fragments.FileChooserFragment; +import com.doplgangr.secrecy.utils.Util; + +import java.io.File; +import java.util.List; + +public class FileChooserAdapter extends ArrayAdapter { + + private Context context; + /** + * File object of the directory to be displayed + */ + private File rootFile; + + public FileChooserAdapter(Context context, + List objects, File rootFile) { + super(context, R.layout.listitem_single_line_text, R.id.text1, objects); + this.context = context; + this.rootFile = rootFile; + } + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View view = super.getView(position, convertView, parent); + File item = getItem(position); + TextView textView =(TextView) view.findViewById(R.id.text1); + ImageView iconView =(ImageView) view.findViewById(R.id.icon1); + Boolean isParent = rootFile.getParentFile()!=null && rootFile.getParentFile().getAbsolutePath().equals(item.getAbsolutePath()); + + // TODO: create a more intuitive way to let user know this is "up" + // If the rootFile has a parent, display as "up" + if (isParent) + textView.setText(".."); + else { + textView.setText(item.getName()); + } + + textView.setEnabled(Util.canReadDir(item)); + iconView.setImageResource(R.drawable.ic_action_folder); + // Highlights the directory if it is the path to the current vault root + if (isSubDirectory(item, Storage.getRoot()) && !isParent) { + textView.setTextColor(context.getResources().getColor(R.color.accent)); + iconView.setColorFilter(context.getResources().getColor(R.color.accent)); + }else{ + iconView.setColorFilter(context.getResources().getColor(R.color.button)); + } + + return view; + } + + /** + * Checks whether a directory is a subdirectory under certain root directory + * @param directory root directory to be checked against + * @param file file suspected of being a subdirectory + * @return true if file is in directory, false if not. + */ + public static boolean isSubDirectory(File directory, File file) { + if (file == null) + return false; + if (file.equals(directory)) + return true; + return isSubDirectory(directory, file.getParentFile()); + } +} diff --git a/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java b/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java new file mode 100644 index 0000000..7ce0c19 --- /dev/null +++ b/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java @@ -0,0 +1,235 @@ +package com.doplgangr.secrecy.fragments; + +import android.app.Activity; +import android.os.Bundle; +import android.app.Fragment; +import android.os.Environment; +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.AbsListView; +import android.widget.AdapterView; +import android.widget.ArrayAdapter; +import android.widget.ListAdapter; +import android.widget.TextView; + +import com.doplgangr.secrecy.R; +import com.doplgangr.secrecy.adapters.FileChooserAdapter; +import com.doplgangr.secrecy.utils.Util; + +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.filefilter.FalseFileFilter; +import org.apache.commons.io.filefilter.TrueFileFilter; + +import java.io.File; +import java.io.FilenameFilter; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +/** + * A fragment to display a file chooser interface + *

+ * Large screen devices (such as tablets) are supported by replacing the ListView + * with a GridView. + *

+ * Activities containing this fragment MUST implement the {@link OnFileChosen} + * interface to catch navigation and file choosing actions + */ +public class FileChooserFragment extends Fragment implements AbsListView.OnItemClickListener { + + /** + * Fragment parameter ROOT + * String, denotes absolute path of the file root to display + */ + private static final String ROOT = "root"; + /** + * Fragment parameter FOLDERS_ONLY + * Boolean, if only folders should be displayed on the interface + */ + private static final String FOLDERS_ONLY = "folders_only"; + + private List ITEMS = new ArrayList<>(); + + private OnFileChosen mListener; + + /** + * The fragment's ListView/GridView. + */ + private AbsListView mListView; + + /** + * The Adapter which will be used to populate the ListView/GridView with + * Views. + */ + private ListAdapter mAdapter; + + /** + * The location of directory where views are displaying. + */ + private File rootFile; + + public static FileChooserFragment newInstance(File root, Boolean foldersOnly) { + FileChooserFragment fragment = new FileChooserFragment(); + Bundle args = new Bundle(); + + // Default implementation: accessing the internal SDcard. + if (root!=null) + args.putString(ROOT, root.getAbsolutePath()); + else + args.putString(ROOT, Environment.getExternalStorageDirectory().getAbsolutePath()); + + // Default implementation: displaying all files and directory + if (foldersOnly!=null) + args.putBoolean(FOLDERS_ONLY, foldersOnly); + else + args.putBoolean(FOLDERS_ONLY, false); + fragment.setArguments(args); + return fragment; + } + + /** + * Mandatory empty constructor for the fragment manager to instantiate the + * fragment (e.g. upon screen orientation changes). + */ + public FileChooserFragment() { + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + final Boolean foldersOnly; + if (getArguments() != null) { + rootFile = new File(getArguments().getString(ROOT)); + foldersOnly = getArguments().getBoolean(FOLDERS_ONLY, false); + }else{ + rootFile = Environment.getExternalStorageDirectory(); + foldersOnly = false; + } + + // If a parent exists, add the parent to the list of children so that users can traverse up. + if (!Environment.getRootDirectory().equals(rootFile.getAbsoluteFile())) + if (rootFile.getParentFile()!=null) + ITEMS.add(rootFile.getParentFile()); + + // Lists all children, optionally display only folders. + File[] filesListed = rootFile.listFiles(new FilenameFilter() { + @Override + public boolean accept(File current, String name) { + return !foldersOnly || new File(current, name).isDirectory(); + } + }); + + // Sort files by name + Arrays.sort(filesListed, new Comparator() { + @Override + public int compare(File file1, File file2) { + return file1.getName().compareTo(file2.getName()); + } + }); + + Collections.addAll(ITEMS,filesListed); + + mAdapter = new FileChooserAdapter(getActivity(), ITEMS, rootFile); + + setHasOptionsMenu(true); + } + + @Override + public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { + inflater.inflate(R.menu.file_chooser,menu); + super.onCreateOptionsMenu(menu, inflater); + } + + // TODO: Add option to create new folder + @Override + public boolean onOptionsItemSelected(MenuItem item) { + switch (item.getItemId()){ + case R.id.action_ok: + mListener.onFileSelected(rootFile,true); + return true; + } + return super.onOptionsItemSelected(item); + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.fragment_filechooser, container, false); + mListView = (AbsListView) view.findViewById(android.R.id.list); + + // Set the adapter + mListView.setAdapter(mAdapter); + + // Set OnItemClickListener so we can be notified on item clicks + mListView.setOnItemClickListener(this); + + // Set the toolbar to have location name + getActivity().setTitle(rootFile.getAbsolutePath()); + + return view; + } + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mListener = (OnFileChosen) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement OnFileChosen"); + } + } + + @Override + public void onDetach() { + super.onDetach(); + mListener = null; + } + + @Override + public void onItemClick(AdapterView parent, View view, int position, long id) { + if (null != mListener) { + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that an item has been selected. + if (Util.canReadDir(ITEMS.get(position))) + mListener.onFileSelected(ITEMS.get(position),false); + } + } + + /** + * The default content for this Fragment has a TextView that is shown when + * the list is empty. If you would like to change the text, call this method + * to supply the text it should use. + */ + public void setEmptyText(CharSequence emptyText) { + View emptyView = mListView.getEmptyView(); + + if (emptyView instanceof TextView) { + ((TextView) emptyView).setText(emptyText); + } + } + + /** + * This interface must be implemented by activities that contain this + * fragment to allow an interaction in this fragment to be communicated + * to the activity and potentially other fragments contained in that + * activity. + *

+ * See the Android Training lesson Communicating with Other Fragments for more information. + */ + public interface OnFileChosen { + void onFileSelected(File path, Boolean confirmed); + } +} diff --git a/app/src/main/java/com/doplgangr/secrecy/utils/Util.java b/app/src/main/java/com/doplgangr/secrecy/utils/Util.java index 144573a..f55feca 100644 --- a/app/src/main/java/com/doplgangr/secrecy/utils/Util.java +++ b/app/src/main/java/com/doplgangr/secrecy/utils/Util.java @@ -209,6 +209,25 @@ public static Boolean canWrite(java.io.File root) { } + /** Checks whether a directory is truly readable. Since File.canRead() + * only checks for file security, it is necessary to try doing a File.listFiles() + * to test for real directory access. + * @param root Directory root to be checked against + * @return True if directory can be read, False if any exception occurs + * e.g. the folder is not readable, devices not mounted etc. + */ + public static Boolean canReadDir(java.io.File root) { + if (root == null) + return false; + if (!root.exists()) + return false; + try { + return root.canRead() && root.listFiles()!=null; + } catch (Exception e) { + return false; + } + } + public static void openURI(String uri) { Intent i = new Intent(Intent.ACTION_VIEW); i.setData(Uri.parse(uri)); diff --git a/app/src/main/res/drawable-hdpi/ic_action_done.png b/app/src/main/res/drawable-hdpi/ic_action_done.png new file mode 100644 index 0000000000000000000000000000000000000000..f073fc137dee48d9976c657087b06ef7e73f0081 GIT binary patch literal 223 zcmV<503iQ~P)^?=TxdSh zU5aA-tC?fV|k0wldT1B8K8w5N+>NX4zUR}J|NDDW^Js1Z=C zJ5tO&zu=~o$$|!*(5Y{9X6AiJYA!s-Qp+f6Qn7OPg!3&cpT{oUw17dh^-oC(U&}=u w&L#!NCYFl}>yE_aYv`AyoKwmDKYyXL{)yZc=2@GBfYva0y85}Sb4q9e0Mu7A6#xJL literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_action_done.png b/app/src/main/res/drawable-mdpi/ic_action_done.png new file mode 100644 index 0000000000000000000000000000000000000000..c37205258c9019066bb6e318421ea420488dd5d1 GIT binary patch literal 166 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iTu&FrkcwN$Kh8TyrARnRm3Uqj z`1}9-f3`=a4O9NB$1!&m9g?~*Mfg&~LYe(+I;RAsBL3v37P4Gwa<|-;kb7WxP0CXX3l;`#tL$~DJm=(r P7BhId`njxgN@xNA^cg%1 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_action_folder.png b/app/src/main/res/drawable-mdpi/ic_action_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..66314e9c5b8a6c7467d13ad7aa5cc289102fb824 GIT binary patch literal 127 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_*1H%}MGkcwN$Kh8TyrAVxiV*0=T zPd|?oN2Wt)UpRM*65F0%@BL@B{dXvzu;StW6>W;^ABqN^idQiCk?gsC#;IENQZZFV aCWgEp$)P0&K8pcOWbkzLb6Mw<&;$T}VJo@- literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_done.png b/app/src/main/res/drawable-xhdpi/ic_action_done.png new file mode 100644 index 0000000000000000000000000000000000000000..446c5362c5ff852ae0cc76e7ede05a52509ec9c6 GIT binary patch literal 265 zcmV+k0rvihP)i;My){fB^;=;H?pt zmcWP^0JQ=>dH6*Ad=ns=uLC6VHGm=x97Hdf+))Sz~P;LJ&y=cnBTtveYb~*b7?;G4YtHln-8C&Fd@pvj_H;-Y4Y)V z@JopEsf)G}lRTfk$txkw=SBr-^Z8jsx;$stktWZZrXV|Q7 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_folder.png b/app/src/main/res/drawable-xhdpi/ic_action_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..c1da4abb7c3f90a2222a07150eb87901dcfef4af GIT binary patch literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^1|ZDA0wn)(8}b0DK2I0NkcwMxuNw+A83?pKoa0t> zM&^X13A;19#>M*)O9d95$YcC`&urzVvrA6icK9$?!QsHhhCXTK|C6E`x%szEzSW@p z+f(-dgPe=4-i;JB;p+|JWtCxv*c*168&opS5v<@AxWJ>}(7?d>`@oyOFVlk;{AW#C y=^ZBNH8pPK`;AwYo_tXFt7>nU1|!qH&y4e1ZWb+9yE~?2W|P(Y@ms&rgCDS z9Y31Di-Kgp34`|h{DewLCY%uHz^_j5RX{T0gh0n$_!z0;n++%Y%1A*nTV>GUkk3jANwQnlpY=_er-7sph*iM>0A>BnU?~%YKnS9O-Z!l0Y2!wC|HZ98LY8 z92{LAB0NW1&ba+002ovPDHLkV1igRoSFat literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_folder.png b/app/src/main/res/drawable-xxhdpi/ic_action_folder.png new file mode 100644 index 0000000000000000000000000000000000000000..c25bb369b898118bc95bc05a137cc08e92936be9 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawE_u2*hE&{od()7w$w8nsQELaY z%tZm4L-WqLC%bx95OX7_-pY?G{dacUDsWQQViSvuT#?mKe zdh;LsX)dzbcH}4P(wG}k&xK1KOt+|CAbdpa>}hQf!T!+bQjtnDyDjJ3#zSHpzh36g zW^zpBy%NEEcWt9UhWmo)K(l}b77IYl1sQ&msrTA7!(5Soy*yTKj8ji9=uxy-9vxk! zCi11x^5^o;A#Se5ytDoXu3MhAbe9Gf*gad!FG%0lsNHa8!s#ra?-)E?{an^LB{Ts5 DZ|7)A literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_done.png b/app/src/main/res/drawable-xxxhdpi/ic_action_done.png new file mode 100644 index 0000000000000000000000000000000000000000..e359a2f0a3a9859799af6ce397e7d06b227351cb GIT binary patch literal 459 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z&Od%#WAGf*4tbEeGfbEv_0fu zc**8-sZiobv>}82_e6%vtLhaLPX5f9|5iBO*x{ag=;X~;Tc___&k8gG9US;=_3`nU z2H|=GN7Ih5DwHYn{Ea+n&=zTwrU)eKjDnliNg z;bI7`vpXca80(9?X;HmY5*V zDKSZ(b+Nk{zrzLsZ4ckv z+N~hc_di%3^(<`!lrHS#S->K%SZ7$yEeB!xW@7q;Ipg}P3 z;9CPbuT|!?rJiyO(R(#s-%`mw5SAY`J%zjC+AkIB19!Wg87f>^>V8-2B-;l)SEVaU z{WXOa>iK?}x^qu2+t;@Zk#dtwr@gf`c%a|@pJO6})>;vn39q*ba4WoB%-nanLH~M# zrj-NGwg{#gW+2s|`G6f{w-4if5S74n0zwIZC=fXCmEpenS6=qJ>en0kQx80l+7Qk5 zrO$rF=6BI-@$TCjmS4O0xcT($`m4)oe^i%T^Vn(g_iXCp?|Z*lSxFq4bL!mY)z$Ou eEg)t=$O1MIZIeqszTJNh;(NOKxvX + + + + + + + diff --git a/app/src/main/res/layout/fragment_filechooser_list.xml b/app/src/main/res/layout/fragment_filechooser_list.xml new file mode 100644 index 0000000..131ce1b --- /dev/null +++ b/app/src/main/res/layout/fragment_filechooser_list.xml @@ -0,0 +1,18 @@ + + + + + + + + diff --git a/app/src/main/res/layout/listitem_single_line_text.xml b/app/src/main/res/layout/listitem_single_line_text.xml new file mode 100644 index 0000000..72cacff --- /dev/null +++ b/app/src/main/res/layout/listitem_single_line_text.xml @@ -0,0 +1,24 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/file_chooser.xml b/app/src/main/res/menu/file_chooser.xml new file mode 100644 index 0000000..eb25463 --- /dev/null +++ b/app/src/main/res/menu/file_chooser.xml @@ -0,0 +1,14 @@ + +

+ + + \ No newline at end of file diff --git a/app/src/main/res/values-large/refs.xml b/app/src/main/res/values-large/refs.xml new file mode 100644 index 0000000..d908a5c --- /dev/null +++ b/app/src/main/res/values-large/refs.xml @@ -0,0 +1,12 @@ + + + + @layout/fragment_filechooser_grid + + \ No newline at end of file diff --git a/app/src/main/res/values-sw600dp/refs.xml b/app/src/main/res/values-sw600dp/refs.xml new file mode 100644 index 0000000..d908a5c --- /dev/null +++ b/app/src/main/res/values-sw600dp/refs.xml @@ -0,0 +1,12 @@ + + + + @layout/fragment_filechooser_grid + + \ No newline at end of file diff --git a/app/src/main/res/values/color.xml b/app/src/main/res/values/color.xml index 9d602aa..653a93f 100644 --- a/app/src/main/res/values/color.xml +++ b/app/src/main/res/values/color.xml @@ -20,6 +20,7 @@ @color/quantum_deeporange_A200 @color/quantum_deeporange_A100 @color/quantum_deeporange_A400 + @color/button_material_light #727272 \ No newline at end of file diff --git a/app/src/main/res/values/refs.xml b/app/src/main/res/values/refs.xml new file mode 100644 index 0000000..8f31101 --- /dev/null +++ b/app/src/main/res/values/refs.xml @@ -0,0 +1,12 @@ + + + + @layout/fragment_filechooser_list + + \ No newline at end of file From c252105bc38e8c25ba696b6dd622922174522cb2 Mon Sep 17 00:00:00 2001 From: Doplgangr Date: Wed, 20 May 2015 21:53:10 +0800 Subject: [PATCH 2/7] Chain file chooser to user interface --- app/src/main/AndroidManifest.xml | 2 +- .../secrecy/activities/ChooseFolder.java | 63 ------------- .../activities/FileChooserActivity.java | 76 ++++++++++++++++ .../secrecy/fragments/SettingsFragment.java | 89 ++++--------------- .../main/res/layout/activity_file_chooser.xml | 18 ++++ 5 files changed, 114 insertions(+), 134 deletions(-) delete mode 100644 app/src/main/java/com/doplgangr/secrecy/activities/ChooseFolder.java create mode 100644 app/src/main/java/com/doplgangr/secrecy/activities/FileChooserActivity.java create mode 100644 app/src/main/res/layout/activity_file_chooser.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4ec482d..588ab1a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -52,7 +52,7 @@ diff --git a/app/src/main/java/com/doplgangr/secrecy/activities/ChooseFolder.java b/app/src/main/java/com/doplgangr/secrecy/activities/ChooseFolder.java deleted file mode 100644 index b7af611..0000000 --- a/app/src/main/java/com/doplgangr/secrecy/activities/ChooseFolder.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -package com.doplgangr.secrecy.activities; - -import android.content.Intent; -import android.os.Bundle; -import android.support.v7.app.ActionBarActivity; -import android.view.MenuItem; - -import com.doplgangr.secrecy.R; -import com.ipaulpro.afilechooser.FileChooserActivity; - -import java.util.ArrayList; - - -public class ChooseFolder extends ActionBarActivity { - private static final int REQUEST_CODE = 6384; // onActivityResult request code - private static final ArrayList INCLUDE_EXTENSIONS_LIST = new ArrayList(); - - static { - INCLUDE_EXTENSIONS_LIST.add("."); - } - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - - Intent intent = new Intent(this, FileChooserActivity.class); - - intent.putStringArrayListExtra( - FileChooserActivity.EXTRA_FILTER_INCLUDE_EXTENSIONS, - INCLUDE_EXTENSIONS_LIST); - intent.putExtra(FileChooserActivity.EXTRA_SELECT_FOLDER, true); - startActivityForResult(intent, REQUEST_CODE); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - return id == R.id.action_settings || super.onOptionsItemSelected(item); - } - -} diff --git a/app/src/main/java/com/doplgangr/secrecy/activities/FileChooserActivity.java b/app/src/main/java/com/doplgangr/secrecy/activities/FileChooserActivity.java new file mode 100644 index 0000000..71cdefc --- /dev/null +++ b/app/src/main/java/com/doplgangr/secrecy/activities/FileChooserActivity.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package com.doplgangr.secrecy.activities; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v7.app.ActionBarActivity; +import android.support.v7.widget.Toolbar; +import android.util.Log; + +import com.doplgangr.secrecy.R; +import com.doplgangr.secrecy.fragments.FileChooserFragment; + +import java.io.File; + + +public class FileChooserActivity extends ActionBarActivity implements FileChooserFragment.OnFileChosen{ + public static final String FOLDERS_ONLY = "FOLDERS_ONLY"; // folders only extra + public static final String FILE_SELECTED = "FILE_SELECTED"; // selected file extra + public static final String ROOT_FOLDER = "ROOT_FOLDER"; // root folder extra + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_file_chooser); + Toolbar mToolbar = (Toolbar) findViewById(R.id.toolbar); + if (mToolbar!=null) + setSupportActionBar(mToolbar); + Intent intent = getIntent(); + File root = null; + Boolean foldersOnly = false; + if (intent!=null) { + String root_folder = intent.getStringExtra(ROOT_FOLDER); + if (root_folder!=null) + root=new File(root_folder); + foldersOnly = intent.getBooleanExtra(FOLDERS_ONLY, false); + } + FileChooserFragment fragment = FileChooserFragment.newInstance(root, foldersOnly); + getFragmentManager().beginTransaction() + .replace(R.id.content_frame, fragment) + .setTransition(android.support.v4.app.FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .commit(); + } + + @Override + public void onFileSelected(File path, Boolean confirmed) { + if (confirmed) { + Intent returnIntent = new Intent(); + returnIntent.putExtra(FILE_SELECTED,path); + setResult(RESULT_OK, returnIntent); + finish(); + }else { + FileChooserFragment fragment = FileChooserFragment.newInstance(path, true); + getFragmentManager().beginTransaction() + .replace(R.id.content_frame, fragment) + .setTransition(android.support.v4.app.FragmentTransaction.TRANSIT_FRAGMENT_OPEN) + .addToBackStack(path.getAbsolutePath()).commit(); + } + } +} diff --git a/app/src/main/java/com/doplgangr/secrecy/fragments/SettingsFragment.java b/app/src/main/java/com/doplgangr/secrecy/fragments/SettingsFragment.java index bf9b5ff..ed788a7 100644 --- a/app/src/main/java/com/doplgangr/secrecy/fragments/SettingsFragment.java +++ b/app/src/main/java/com/doplgangr/secrecy/fragments/SettingsFragment.java @@ -41,7 +41,6 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; @@ -49,20 +48,18 @@ import com.doplgangr.secrecy.Config; import com.doplgangr.secrecy.CustomApp; import com.doplgangr.secrecy.R; +import com.doplgangr.secrecy.activities.FileChooserActivity; import com.doplgangr.secrecy.utils.Util; import com.doplgangr.secrecy.filesystem.Storage; import com.doplgangr.secrecy.premium.PremiumStateHelper; import com.doplgangr.secrecy.premium.StealthMode; import com.doplgangr.secrecy.adapters.VaultsListFragment; -import com.ipaulpro.afilechooser.FileChooserActivity; -import com.ipaulpro.afilechooser.utils.FileUtils; import java.io.File; import java.io.IOException; import java.util.ArrayList; -import java.util.Map; -public class SettingsFragment extends PreferenceFragment { +public class SettingsFragment extends PreferenceFragment{ private static final int REQUEST_CODE_SET_VAULT_ROOT = 6384; private static final int REQUEST_CODE_MOVE_VAULT = 2058; private Context context; @@ -210,18 +207,7 @@ private void preparePreferenceVaultRoot(){ vault_root.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - choosePath(new getFileListener() { - @Override - public void get(File file) { - Intent intent = new Intent(context, FileChooserActivity.class); - intent.putStringArrayListExtra( - FileChooserActivity.EXTRA_FILTER_INCLUDE_EXTENSIONS, - INCLUDE_EXTENSIONS_LIST); - intent.putExtra(FileChooserActivity.PATH, file.getAbsolutePath()); - intent.putExtra(FileChooserActivity.EXTRA_SELECT_FOLDER, true); - startActivityForResult(intent, REQUEST_CODE_SET_VAULT_ROOT); - } - }); + choosePath(); return true; } }); @@ -232,18 +218,7 @@ private void preparePreferenceVaultMove(){ vault_move.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { @Override public boolean onPreferenceClick(Preference preference) { - choosePath(new getFileListener() { - @Override - public void get(File file) { - Intent intent = new Intent(context, FileChooserActivity.class); - intent.putStringArrayListExtra( - FileChooserActivity.EXTRA_FILTER_INCLUDE_EXTENSIONS, - INCLUDE_EXTENSIONS_LIST); - intent.putExtra(FileChooserActivity.PATH, file.getAbsolutePath()); - intent.putExtra(FileChooserActivity.EXTRA_SELECT_FOLDER, true); - startActivityForResult(intent, REQUEST_CODE_MOVE_VAULT); - } - }); + movePath(); return true; } }); @@ -359,12 +334,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { // If the file selection was successful if (resultCode == Activity.RESULT_OK) { if (data != null) { - // Get the URI of the selected file - final Uri uri = data.getData(); + // Get the selected file + final File file = (File) data.getSerializableExtra(FileChooserActivity.FILE_SELECTED); try { - // Get the file path from the URI - final String path = FileUtils.getPath(context, uri); - Storage.setRoot(path); + Storage.setRoot(file.getAbsolutePath()); Preference vault_root = findPreference(Config.VAULT_ROOT); vault_root.setSummary(Storage.getRoot().getAbsolutePath()); } catch (Exception e) { @@ -376,11 +349,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { case REQUEST_CODE_MOVE_VAULT: if (resultCode == Activity.RESULT_OK) { if (data != null) { - // Get the URI of the selected file - final Uri uri = data.getData(); + // Get the selected file + final File file = (File) data.getSerializableExtra(FileChooserActivity.FILE_SELECTED); try { - // Get the file path from the URI - final String path = FileUtils.getPath(context, uri); + final String path = file.getAbsolutePath(); if (path.contains(Storage.getRoot().getAbsolutePath())) { Util.alert(context, getString(R.string.Settings__cannot_move_vault), @@ -450,40 +422,17 @@ void moveStorageRoot(String path, ProgressDialog progressDialog) { progressDialog.dismiss(); } - void choosePath(final getFileListener listener) { - AlertDialog.Builder builderSingle = new AlertDialog.Builder(context); - builderSingle.setTitle(context.getString(R.string.Settings__select_storage_title)); - final ArrayAdapter arrayAdapter = new ArrayAdapter( - context, - R.layout.select_dialog_singlechoice); - final Map storages = Util.getAllStorageLocations(); - for (String key : storages.keySet()) { - arrayAdapter.add(key); - } - builderSingle.setNegativeButton(R.string.CANCEL, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.dismiss(); - } - } - ); - - builderSingle.setAdapter(arrayAdapter, - new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - String strName = arrayAdapter.getItem(which); - File file = storages.get(strName); - listener.get(file); - } - } - ); - builderSingle.show(); + void choosePath() { + Intent intent = new Intent(getActivity(), FileChooserActivity.class); + intent.putExtra(FileChooserActivity.FOLDERS_ONLY, true); + startActivityForResult(intent, REQUEST_CODE_SET_VAULT_ROOT); } - public interface getFileListener { - void get(File file); + void movePath() { + Intent intent = new Intent(getActivity(), FileChooserActivity.class); + intent.putExtra(FileChooserActivity.FOLDERS_ONLY, true); + startActivityForResult(intent, REQUEST_CODE_MOVE_VAULT); } + } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_file_chooser.xml b/app/src/main/res/layout/activity_file_chooser.xml new file mode 100644 index 0000000..05a2c0a --- /dev/null +++ b/app/src/main/res/layout/activity_file_chooser.xml @@ -0,0 +1,18 @@ + + + + + \ No newline at end of file From 5df7bd71bd9699d9e94b644f6cc3ae5312b02a29 Mon Sep 17 00:00:00 2001 From: Doplgangr Date: Thu, 21 May 2015 13:43:22 +0800 Subject: [PATCH 3/7] Update build tools and AppCompat library to make use of new AppCompat.Dialog.Alert. --- .travis.yml | 4 ++-- android_commons.gradle | 6 +++--- app/build.gradle | 4 ++-- app/src/main/res/values/styles.xml | 2 ++ app/src/main/res/values/themes.xml | 3 ++- 5 files changed, 11 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1fe5dcb..b3ece8d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,10 @@ android: # - tools # The BuildTools version used by your project - - build-tools-19.1.0 + - build-tools-22.0.1 # The SDK version used to compile your project - - android-19 + - android-22 # Additional components - extra-google-m2repository diff --git a/android_commons.gradle b/android_commons.gradle index bab67bd..bb3c81f 100644 --- a/android_commons.gradle +++ b/android_commons.gradle @@ -5,12 +5,12 @@ repositories { android { - compileSdkVersion 21 - buildToolsVersion '21.1.2' + compileSdkVersion 22 + buildToolsVersion '22.0.1' defaultConfig { minSdkVersion 14 - targetSdkVersion 21 + targetSdkVersion 22 } lintOptions { diff --git a/app/build.gradle b/app/build.gradle index 3f7ce20..e9b166f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,9 +15,9 @@ dependencies { compile 'commons-io:commons-io:2.4' - compile 'com.android.support:appcompat-v7:21.0.3' + compile 'com.android.support:appcompat-v7:22.1.1' compile 'com.android.support:recyclerview-v7:21.0.3' - compile 'com.android.support:support-v4:21.0.3' + compile 'com.android.support:support-v4:22.1.1' compile 'com.github.chrisbanes.photoview:library:1.2.3' compile 'com.path:android-priority-jobqueue:1.1.2' compile 'de.greenrobot:eventbus:2.2.0' diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index 403f4b1..ee8a4da 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -11,6 +11,8 @@ @style/ButtonBarButton + \ No newline at end of file From 1df47407d0a2a89490df160f7379f22e54e57dac Mon Sep 17 00:00:00 2001 From: Doplgangr Date: Thu, 21 May 2015 13:54:22 +0800 Subject: [PATCH 4/7] Add add new folder option --- .../fragments/FileChooserFragment.java | 30 ++++++++++++------ .../drawable-hdpi/ic_action_folder_add.png | Bin 0 -> 290 bytes .../drawable-mdpi/ic_action_folder_add.png | Bin 0 -> 282 bytes .../drawable-xhdpi/ic_action_folder_add.png | Bin 0 -> 314 bytes .../drawable-xxhdpi/ic_action_folder_add.png | Bin 0 -> 421 bytes .../drawable-xxxhdpi/ic_action_folder_add.png | Bin 0 -> 517 bytes .../res/layout/dialog_single_edit_text.xml | 16 ++++++++++ app/src/main/res/menu/file_chooser.xml | 8 ++++- app/src/main/res/values/dimens.xml | 6 ++++ app/src/main/res/values/strings.xml | 1 + .../main/res/values/strings_file_handling.xml | 1 + 11 files changed, 52 insertions(+), 10 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_action_folder_add.png create mode 100644 app/src/main/res/drawable-mdpi/ic_action_folder_add.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_action_folder_add.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_action_folder_add.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_action_folder_add.png create mode 100644 app/src/main/res/layout/dialog_single_edit_text.xml diff --git a/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java b/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java index 7ce0c19..68e2012 100644 --- a/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java +++ b/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java @@ -1,10 +1,11 @@ package com.doplgangr.secrecy.fragments; import android.app.Activity; +import android.support.v7.app.AlertDialog; +import android.content.DialogInterface; import android.os.Bundle; import android.app.Fragment; import android.os.Environment; -import android.support.v7.widget.Toolbar; import android.view.LayoutInflater; import android.view.Menu; import android.view.MenuInflater; @@ -13,7 +14,7 @@ import android.view.ViewGroup; import android.widget.AbsListView; import android.widget.AdapterView; -import android.widget.ArrayAdapter; +import android.widget.EditText; import android.widget.ListAdapter; import android.widget.TextView; @@ -21,16 +22,10 @@ import com.doplgangr.secrecy.adapters.FileChooserAdapter; import com.doplgangr.secrecy.utils.Util; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.filefilter.FalseFileFilter; -import org.apache.commons.io.filefilter.TrueFileFilter; - import java.io.File; import java.io.FilenameFilter; -import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.List; @@ -150,13 +145,30 @@ public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { super.onCreateOptionsMenu(menu, inflater); } - // TODO: Add option to create new folder @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.action_ok: mListener.onFileSelected(rootFile,true); return true; + case R.id.action_add_folder: + final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity(),R.style.AppCompatAlertDialog); + View view = getActivity().getLayoutInflater().inflate(R.layout.dialog_single_edit_text,null); + final EditText editText = (EditText) view.findViewById(R.id.editText1); + editText.setHint(R.string.Chooser__new_folder_name_hint); + builder.setTitle(R.string.Chooser__add_folder); + builder.setView(view); + builder.setCancelable(true); + builder.setPositiveButton(R.string.OK, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + File subDirectory = new File(rootFile,editText.getText().toString()); + if (subDirectory.mkdir()) + mListener.onFileSelected(subDirectory,false); + } + }); + builder.create().show(); + return true; } return super.onOptionsItemSelected(item); } diff --git a/app/src/main/res/drawable-hdpi/ic_action_folder_add.png b/app/src/main/res/drawable-hdpi/ic_action_folder_add.png new file mode 100644 index 0000000000000000000000000000000000000000..601f883d626253a10efd84957a5af029f67798fd GIT binary patch literal 290 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k1|%Oc%$NbBBuiW)N`mv#O3D+9QW+dm@{>{( zJaZG%Q-e|yQz{EjrrH1%9r1K=45_%4lpw*nI6>rs;Gh5h;~6@>|5ukgvwUl_MZx=Klh{$MAW3CR8F?q2l=Za&A=1R{khZ*PpdpPs0<32axDuy$u{0oZM9K0Aj z&o#(R)waq|SjuWR>vY?e=8VwW_6^f(dw+iSV22WQ%mvv4FO#nbIYs3Hm literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_action_folder_add.png b/app/src/main/res/drawable-mdpi/ic_action_folder_add.png new file mode 100644 index 0000000000000000000000000000000000000000..f6d42f667fe7a7a3c16e6cc1d4fb825479171fb2 GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjk|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*D5X_ISEDhE&{2N|0b>=9QRe`Tzfae}*6~iz{^rDJgRtw)rX? z{x8h-+0%47Yv)>rmZ}NLEDc{=nO?~;)b3`u%ar8EAR^2q$TmUM$D}8|pd%p5QCUF$ z!14wq?gqyT3`@i=onZFeh-{6{4;BHh^zeQ;lP@ZiifeWr^H`DESE~7HdpoSy>nz b8W}G*7}}J9{$TKQ^>bP0l+XkKMV?%` literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_action_folder_add.png b/app/src/main/res/drawable-xhdpi/ic_action_folder_add.png new file mode 100644 index 0000000000000000000000000000000000000000..fd23e9439e104944657f67c573ecbdc1b5f24a5e GIT binary patch literal 314 zcmV-A0mc4_P)j?7>pn`ARvvBOyQYK#&DYwP%JnIz0R#~E z-6|BjIyEVSaipXMG6>j`uT^3M`ho@GVoSVU&%rB}P5}S_csvCd051L0DVza?TL1t6 M07*qoM6N<$g5u73XaE2J literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_action_folder_add.png b/app/src/main/res/drawable-xxhdpi/ic_action_folder_add.png new file mode 100644 index 0000000000000000000000000000000000000000..c9b3d4ef19684eeca77bf4b8bd807bee196256f6 GIT binary patch literal 421 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY1|&n@ZgvM!k|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+7~MTx978H@y_xlvx5+@jVPzr1-3Gw~X33+TJ(CY`daJA@t;zxSF7UoOj)AS^o8lO=9Hjx7F~bkK(Cmm{3``g#HV&HQEz%P>C!%* zTNk<9**m!I3SLonz5@-@=QE(7wQhTwtrZVDf zb%YG_&Z(1Q@@&>@IwH`rVC%;3sY=Tx@QHq^KEC7I+#(|blft>zSHP7~HQ&El=hh+&y3EflirP142~xr@Jf;$PhS z{9Dn_Sb@7{Wo;j0xS#8-Ir4t0T?brDpUn%pEtv@kfQYu~49pB~lwuqdejm03iFvyE KxvXC literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_action_folder_add.png b/app/src/main/res/drawable-xxxhdpi/ic_action_folder_add.png new file mode 100644 index 0000000000000000000000000000000000000000..a8cce8e257f9efee034ec5154c98db58584f7e30 GIT binary patch literal 517 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD1|%QND7OGok|nMYCBgY=CFO}lsSJ)O`AMk? zp1FzXsX?iUDV2pMQ*9U+7?*pxIEGZ*dUNNY?;!^Xwg+;F3}zPu6PV{5FlgM+Ih#S) zf+{NEh%b=imh z%st1Argh0bPS?r4`JBOQqx7`ezvtdh+Rc?X;p3d=eX^hb%yZ(9lohb9db3*K&?0`> z3!&u~Ik(?ojNR;;Ja<=-YQv_o%rij(@=O}(^N*>hw=_n@9@XgGUOm5McV5hVXU+v{ z#ETtXrlu`op3|Yoz^K5$DDqjPZ^f+F7EBiyIUE=eXu6hlmBIh{3WjZs$-wa6s#?NsjXife{C{e_s_SYIwy9%+_LKx$<~k0 zpqN-={^sO!nfW^w8EKU!{PX^Fi?vMmgiHeiO9MlmdBa+x*qqyL4B4f7Zk)W;IwyQ( zeq_x2Gb^4)zUpO|yzN;-BX tt{gh@=XuNS71>jwYZyRaf&4xe2?psEtHnQRueS$@c)I$ztaD0e0ss<5+4}$h literal 0 HcmV?d00001 diff --git a/app/src/main/res/layout/dialog_single_edit_text.xml b/app/src/main/res/layout/dialog_single_edit_text.xml new file mode 100644 index 0000000..9de0ec2 --- /dev/null +++ b/app/src/main/res/layout/dialog_single_edit_text.xml @@ -0,0 +1,16 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/file_chooser.xml b/app/src/main/res/menu/file_chooser.xml index eb25463..6067c94 100644 --- a/app/src/main/res/menu/file_chooser.xml +++ b/app/src/main/res/menu/file_chooser.xml @@ -10,5 +10,11 @@ android:icon="@drawable/ic_action_done" android:orderInCategory="1" android:title="@string/abc_action_mode_done" - app:showAsAction="always" /> + app:showAsAction="ifRoom" /> + \ No newline at end of file diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 8036a75..601ad42 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -26,6 +26,12 @@ 20sp 56dp + + 24dp + + 48dp + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 3ed477e..583e0d7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -75,6 +75,7 @@ Maximal image size Performance Sort files by + New Folder Name Small Medium diff --git a/app/src/main/res/values/strings_file_handling.xml b/app/src/main/res/values/strings_file_handling.xml index 2a40cd4..217f7a8 100644 --- a/app/src/main/res/values/strings_file_handling.xml +++ b/app/src/main/res/values/strings_file_handling.xml @@ -54,4 +54,5 @@ Restore in Progress Restore Finished. %s has been restored. New File Name + Add Folder \ No newline at end of file From 1d67a3c041da2527cc28025be10defc567f271ed Mon Sep 17 00:00:00 2001 From: Doplgangr Date: Thu, 21 May 2015 15:59:08 +0800 Subject: [PATCH 5/7] Add file viewing option, implemented in restore option. --- .../activities/FileChooserActivity.java | 13 ++++-- .../secrecy/adapters/FileChooserAdapter.java | 10 ++++- .../secrecy/adapters/VaultsListFragment.java | 21 +++++---- .../fragments/FileChooserFragment.java | 42 +++++++++++++++--- app/src/main/res/drawable-hdpi/ic_file.png | Bin 0 -> 165 bytes app/src/main/res/drawable-mdpi/ic_file.png | Bin 0 -> 139 bytes app/src/main/res/drawable-xhdpi/ic_file.png | Bin 0 -> 220 bytes app/src/main/res/drawable-xxhdpi/ic_file.png | Bin 0 -> 302 bytes app/src/main/res/drawable-xxxhdpi/ic_file.png | Bin 0 -> 399 bytes 9 files changed, 64 insertions(+), 22 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_file.png create mode 100644 app/src/main/res/drawable-mdpi/ic_file.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_file.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_file.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_file.png diff --git a/app/src/main/java/com/doplgangr/secrecy/activities/FileChooserActivity.java b/app/src/main/java/com/doplgangr/secrecy/activities/FileChooserActivity.java index 71cdefc..1378b53 100644 --- a/app/src/main/java/com/doplgangr/secrecy/activities/FileChooserActivity.java +++ b/app/src/main/java/com/doplgangr/secrecy/activities/FileChooserActivity.java @@ -29,12 +29,18 @@ import com.doplgangr.secrecy.fragments.FileChooserFragment; import java.io.File; +import java.lang.reflect.Array; +import java.util.ArrayList; public class FileChooserActivity extends ActionBarActivity implements FileChooserFragment.OnFileChosen{ public static final String FOLDERS_ONLY = "FOLDERS_ONLY"; // folders only extra public static final String FILE_SELECTED = "FILE_SELECTED"; // selected file extra public static final String ROOT_FOLDER = "ROOT_FOLDER"; // root folder extra + public static final String FILE_EXTENSIONS = "FILE_EXTENSIONS"; // file extensions to show + private File root = null; + private Boolean foldersOnly = false; + private ArrayList fileExtensions = new ArrayList<>(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -43,15 +49,14 @@ protected void onCreate(Bundle savedInstanceState) { if (mToolbar!=null) setSupportActionBar(mToolbar); Intent intent = getIntent(); - File root = null; - Boolean foldersOnly = false; if (intent!=null) { String root_folder = intent.getStringExtra(ROOT_FOLDER); if (root_folder!=null) root=new File(root_folder); foldersOnly = intent.getBooleanExtra(FOLDERS_ONLY, false); + fileExtensions = intent.getStringArrayListExtra(FILE_EXTENSIONS); } - FileChooserFragment fragment = FileChooserFragment.newInstance(root, foldersOnly); + FileChooserFragment fragment = FileChooserFragment.newInstance(root, foldersOnly, fileExtensions); getFragmentManager().beginTransaction() .replace(R.id.content_frame, fragment) .setTransition(android.support.v4.app.FragmentTransaction.TRANSIT_FRAGMENT_OPEN) @@ -66,7 +71,7 @@ public void onFileSelected(File path, Boolean confirmed) { setResult(RESULT_OK, returnIntent); finish(); }else { - FileChooserFragment fragment = FileChooserFragment.newInstance(path, true); + FileChooserFragment fragment = FileChooserFragment.newInstance(path, foldersOnly, fileExtensions); getFragmentManager().beginTransaction() .replace(R.id.content_frame, fragment) .setTransition(android.support.v4.app.FragmentTransaction.TRANSIT_FRAGMENT_OPEN) diff --git a/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java b/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java index bc4970b..4afa4c8 100644 --- a/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java +++ b/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java @@ -41,6 +41,8 @@ public View getView(int position, View convertView, ViewGroup parent) { TextView textView =(TextView) view.findViewById(R.id.text1); ImageView iconView =(ImageView) view.findViewById(R.id.icon1); Boolean isParent = rootFile.getParentFile()!=null && rootFile.getParentFile().getAbsolutePath().equals(item.getAbsolutePath()); + Boolean isFile = item.isFile(); + Boolean isReadableDir = Util.canReadDir(item); // TODO: create a more intuitive way to let user know this is "up" // If the rootFile has a parent, display as "up" @@ -50,8 +52,12 @@ public View getView(int position, View convertView, ViewGroup parent) { textView.setText(item.getName()); } - textView.setEnabled(Util.canReadDir(item)); - iconView.setImageResource(R.drawable.ic_action_folder); + textView.setEnabled(isFile || isReadableDir); + if (isFile) + iconView.setImageResource(R.drawable.ic_file); + if (isReadableDir) + iconView.setImageResource(R.drawable.ic_action_folder); + // Highlights the directory if it is the path to the current vault root if (isSubDirectory(item, Storage.getRoot()) && !isParent) { textView.setTextColor(context.getResources().getColor(R.color.accent)); diff --git a/app/src/main/java/com/doplgangr/secrecy/adapters/VaultsListFragment.java b/app/src/main/java/com/doplgangr/secrecy/adapters/VaultsListFragment.java index 2bbf6d9..7292efd 100644 --- a/app/src/main/java/com/doplgangr/secrecy/adapters/VaultsListFragment.java +++ b/app/src/main/java/com/doplgangr/secrecy/adapters/VaultsListFragment.java @@ -50,6 +50,7 @@ import com.doplgangr.secrecy.CustomApp; import com.doplgangr.secrecy.R; +import com.doplgangr.secrecy.activities.FileChooserActivity; import com.doplgangr.secrecy.utils.Util; import com.doplgangr.secrecy.activities.FilesActivity; import com.doplgangr.secrecy.events.RestoreDoneEvent; @@ -59,12 +60,14 @@ import com.doplgangr.secrecy.filesystem.encryption.VaultHolder; import com.doplgangr.secrecy.jobs.RestoreJob; import com.doplgangr.secrecy.fragments.SettingsFragment; -import com.ipaulpro.afilechooser.FileChooserActivity; import com.ipaulpro.afilechooser.utils.FileUtils; +import org.apache.commons.io.FilenameUtils; + import java.io.File; import java.io.IOException; import java.util.ArrayList; +import java.util.zip.ZipFile; import de.greenrobot.event.EventBus; @@ -294,15 +297,12 @@ public void onClick(DialogInterface dialog, int whichButton) { } void restore() { - ArrayList INCLUDE_EXTENSIONS_LIST = new ArrayList(); - INCLUDE_EXTENSIONS_LIST.add(".zip"); - + ArrayList fileExtensions = new ArrayList<>(); + fileExtensions.add("zip"); Intent intent = new Intent(context, FileChooserActivity.class); + intent.putExtra(FileChooserActivity.ROOT_FOLDER, Storage.getRoot().getAbsolutePath()); + intent.putExtra(FileChooserActivity.FILE_EXTENSIONS, fileExtensions); - intent.putStringArrayListExtra( - FileChooserActivity.EXTRA_FILTER_INCLUDE_EXTENSIONS, - INCLUDE_EXTENSIONS_LIST); - intent.putExtra(FileChooserActivity.PATH, Storage.getRoot().getAbsolutePath()); startActivityForResult(intent, REQUESTCODE); } @@ -382,8 +382,7 @@ public void run() { new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { - final Uri uri = data.getData(); - final String path = FileUtils.getPath(context, uri); + final File file = (File) data.getSerializableExtra(FileChooserActivity.FILE_SELECTED); mNotifyManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); mBuilder = new NotificationCompat.Builder(context); mBuilder.setContentTitle(CustomApp.context.getString(R.string.Restore__title)) @@ -392,7 +391,7 @@ public void onClick(DialogInterface dialog, int which) { .setOngoing(true); mBuilder.setProgress(0, 0, true); mNotifyManager.notify(REQUESTCODE, mBuilder.build()); - CustomApp.jobManager.addJobInBackground(new RestoreJob(context, new File(path))); + CustomApp.jobManager.addJobInBackground(new RestoreJob(context, file)); } }, diff --git a/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java b/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java index 68e2012..5b57fa1 100644 --- a/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java +++ b/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java @@ -19,9 +19,13 @@ import android.widget.TextView; import com.doplgangr.secrecy.R; +import com.doplgangr.secrecy.activities.FileChooserActivity; import com.doplgangr.secrecy.adapters.FileChooserAdapter; import com.doplgangr.secrecy.utils.Util; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.FilenameUtils; + import java.io.File; import java.io.FilenameFilter; import java.util.ArrayList; @@ -72,7 +76,20 @@ public class FileChooserFragment extends Fragment implements AbsListView.OnItemC */ private File rootFile; - public static FileChooserFragment newInstance(File root, Boolean foldersOnly) { + /** + * If only folders should be displayed. Additional menu icon "OK" + * Will be displayed to allow confirming. Additional add folder icon + * will also be added. + */ + private Boolean foldersOnly; + + + /** + * The extensions that will be displayed. + */ + private ArrayList fileExtensions; + + public static FileChooserFragment newInstance(File root, Boolean foldersOnly, ArrayList fileExtensions) { FileChooserFragment fragment = new FileChooserFragment(); Bundle args = new Bundle(); @@ -87,6 +104,8 @@ public static FileChooserFragment newInstance(File root, Boolean foldersOnly) { args.putBoolean(FOLDERS_ONLY, foldersOnly); else args.putBoolean(FOLDERS_ONLY, false); + + args.putStringArrayList(FileChooserActivity.FILE_EXTENSIONS, fileExtensions); fragment.setArguments(args); return fragment; } @@ -102,13 +121,14 @@ public FileChooserFragment() { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); - final Boolean foldersOnly; if (getArguments() != null) { rootFile = new File(getArguments().getString(ROOT)); foldersOnly = getArguments().getBoolean(FOLDERS_ONLY, false); + fileExtensions = getArguments().getStringArrayList(FileChooserActivity.FILE_EXTENSIONS); }else{ rootFile = Environment.getExternalStorageDirectory(); foldersOnly = false; + fileExtensions = null; } // If a parent exists, add the parent to the list of children so that users can traverse up. @@ -120,14 +140,23 @@ public void onCreate(Bundle savedInstanceState) { File[] filesListed = rootFile.listFiles(new FilenameFilter() { @Override public boolean accept(File current, String name) { - return !foldersOnly || new File(current, name).isDirectory(); + File file = new File(current, name); + if (foldersOnly) + return file.isDirectory(); + if (fileExtensions!=null && file.isFile()) + return fileExtensions.contains(FilenameUtils.getExtension(name)); + return true; } }); - // Sort files by name + // Sort files by name, folder has priority Arrays.sort(filesListed, new Comparator() { @Override public int compare(File file1, File file2) { + if (file1.isDirectory() && !file2.isDirectory()) + return -1; + if (!file1.isDirectory() && file2.isDirectory()) + return 1; return file1.getName().compareTo(file2.getName()); } }); @@ -141,7 +170,8 @@ public int compare(File file1, File file2) { @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.file_chooser,menu); + if (foldersOnly) + inflater.inflate(R.menu.file_chooser,menu); super.onCreateOptionsMenu(menu, inflater); } @@ -215,6 +245,8 @@ public void onItemClick(AdapterView parent, View view, int position, long id) // fragment is attached to one) that an item has been selected. if (Util.canReadDir(ITEMS.get(position))) mListener.onFileSelected(ITEMS.get(position),false); + else + mListener.onFileSelected(ITEMS.get(position),true); } } diff --git a/app/src/main/res/drawable-hdpi/ic_file.png b/app/src/main/res/drawable-hdpi/ic_file.png new file mode 100644 index 0000000000000000000000000000000000000000..410be4958cff5206747b9b072c92e4dd15feb84e GIT binary patch literal 165 zcmeAS@N?(olHy`uVBq!ia0vp^Dj>|k0wldT1B8K8j;D)bNX4zU*SxtJ3|F3- zVpZhAuRK{X;#LQ*@M}z7({>=b|KPiow#>aJK1>qHVDq-(Upr-CNNpaAk)Ni(Qj?AV zttUZNPXcTMCckQy3bB2ELFmGI1s0J2hx<)pohR)~7IK{VaAof+ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_file.png b/app/src/main/res/drawable-mdpi/ic_file.png new file mode 100644 index 0000000000000000000000000000000000000000..15aa03744ece8597ee0a6bd3d18ac6e19f5b8a01 GIT binary patch literal 139 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM0wlfaz7_+iAWs*^kcwN$Kh8Tyr6|NZKlnfW z|3yb;JKhed>8S3@Sbtt4bwgs(FArq zhXaBPEF1y~4hQTRl2_DiXf$KFlcVtX<+}INL?=Zg8_V^zOHI3N{>#fk`2*t=*_7~O Tn-hSpWnl1h^>bP0l+XkKLI_Vo literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxhdpi/ic_file.png b/app/src/main/res/drawable-xxhdpi/ic_file.png new file mode 100644 index 0000000000000000000000000000000000000000..8b20e7cb7c49661abb274cc4fda40fa214de2b57 GIT binary patch literal 302 zcmeAS@N?(olHy`uVBq!ia0vp^9w5xY0wn)GsXhawzIwVihE&{od&`jPkb?m0g|*Y> zC@NIgdp_p;R?^fs;}~-Vi(>%y*V$pt2WH-kWd2!yDpT&v6nlj;*-VZsy4)fc6Z*NA zc-k$HvfbkO(@~H;Vp37F*#@eCa{KwHLh;u?m2%Cz+RHk0fqzl@{FJ_xCUr=8uaKcBu zL!pU7=|#E#hZ2|tBc`$L+Fi7+DBw9)*3$)RwO34R){?nvVY_IV$A%)MuPe5Oc4t|{ ov_~Hc&udS1-IfeAV*Y0~+e?bqWum1xfC0eZ>FVdQ&MBb@0Nvzr6#xJL literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_file.png b/app/src/main/res/drawable-xxxhdpi/ic_file.png new file mode 100644 index 0000000000000000000000000000000000000000..445ad416a9deb368fe671a14a608a7f1a20ae5df GIT binary patch literal 399 zcmeAS@N?(olHy`uVBq!ia0vp^2_VeD0wg^q?%&M7z!>J~;uunK>+Nk@KW0aswuf&! zibPvl9yArRPT>&X3U6!^4p3-~zL5JPa`F~|%!KFC)nUKu@?w8X+!MUk`t`C{S)fr2 z3?CTh-0scIO<(FM*wA|SX2L3!`~!#Nd}lx5-eFcdN&Z2|4jWO9pVPEgPkq8%F|9Yc zbwYlnFyk((mKtw;<`Bgv(Pd5!tWD+)ejnI7I0YFr71dSJ0o;=@A@3%3~(56lyb8s@j8F-&~` zbk~Wi>LBMa%rJex4Q8B?G62&Jk<2_`29&t?zqijjp09$Jb}8N%@)nijVDYbiR@($^8EA^yYu3fBd&RzV}Z3x#)KHt@roatp4+^_#!XZ bIKHpEN4HIM7V+z=2k|{!{an^LB{Ts5F+Pz~ literal 0 HcmV?d00001 From 2af52d4b90ce68e03705fd6e858a25d74762c52c Mon Sep 17 00:00:00 2001 From: Doplgangr Date: Thu, 21 May 2015 16:57:19 +0800 Subject: [PATCH 6/7] Update "add file to vault" action to use internal chooser --- app/src/main/AndroidManifest.xml | 7 ++----- .../secrecy/fragments/FilesListFragment.java | 12 ++++++------ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 588ab1a..a685066 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -28,9 +28,9 @@ android:resource="@xml/file_path" /> - + - diff --git a/app/src/main/java/com/doplgangr/secrecy/fragments/FilesListFragment.java b/app/src/main/java/com/doplgangr/secrecy/fragments/FilesListFragment.java index b7eb6d9..0b0d51b 100644 --- a/app/src/main/java/com/doplgangr/secrecy/fragments/FilesListFragment.java +++ b/app/src/main/java/com/doplgangr/secrecy/fragments/FilesListFragment.java @@ -27,6 +27,7 @@ import android.content.Context; import android.content.DialogInterface; import android.content.Intent; +import android.net.Uri; import android.os.Bundle; import android.os.Environment; import android.support.v4.app.NotificationCompat; @@ -51,6 +52,7 @@ import com.doplgangr.secrecy.Config; import com.doplgangr.secrecy.CustomApp; +import com.doplgangr.secrecy.activities.FileChooserActivity; import com.doplgangr.secrecy.activities.FilePhotoActivity; import com.doplgangr.secrecy.activities.FilesActivity; import com.doplgangr.secrecy.events.AddingFileDoneEvent; @@ -67,7 +69,6 @@ import com.doplgangr.secrecy.R; import com.doplgangr.secrecy.utils.Util; import com.doplgangr.secrecy.adapters.FilesListAdapter; -import com.ipaulpro.afilechooser.FileChooserActivity; import java.io.File; import java.io.FileNotFoundException; @@ -534,10 +535,6 @@ void addFile() { FilesActivity.onPauseDecision.startActivity(); } catch (ActivityNotFoundException e) { intent = new Intent(context, FileChooserActivity.class); - intent.putStringArrayListExtra( - FileChooserActivity.EXTRA_FILTER_INCLUDE_EXTENSIONS, - INCLUDE_EXTENSIONS_LIST); - intent.putExtra(FileChooserActivity.EXTRA_SELECT_FOLDER, false); startActivityForResult(intent, REQUEST_CODE); FilesActivity.onPauseDecision.startActivity(); } @@ -622,7 +619,10 @@ public void onActivityResult(int requestCode, int resultCode, Intent data) { .setOngoing(true); mBuilder.setProgress(0, 0, true); mNotifyManager.notify(NotificationID, mBuilder.build()); - + //if the result is from our internal file chooser + Object fileFromChooser = data.getSerializableExtra(com.doplgangr.secrecy.activities.FileChooserActivity.FILE_SELECTED); + if (fileFromChooser !=null) + addFileInBackground(secret, Uri.fromFile((File) fileFromChooser)); addFileInBackground(secret, data.getData()); super.onActivityResult(requestCode, resultCode, data); } else { From 1e8406003b3d804df951c0d37cf1456a91384715 Mon Sep 17 00:00:00 2001 From: Doplgangr Date: Sun, 24 May 2015 00:24:05 +0800 Subject: [PATCH 7/7] Change listview/gridview combination to recyclerview --- .../secrecy/adapters/FileChooserAdapter.java | 113 ++++++++++++------ .../fragments/FileChooserFragment.java | 61 +++------- .../main/res/layout/fragment_filechooser.xml | 8 ++ .../res/layout/fragment_filechooser_grid.xml | 20 ---- .../res/layout/fragment_filechooser_list.xml | 18 --- app/src/main/res/values-large/refs.xml | 12 -- app/src/main/res/values-sw600dp/refs.xml | 12 -- app/src/main/res/values/color.xml | 1 + app/src/main/res/values/refs.xml | 12 -- 9 files changed, 103 insertions(+), 154 deletions(-) create mode 100644 app/src/main/res/layout/fragment_filechooser.xml delete mode 100644 app/src/main/res/layout/fragment_filechooser_grid.xml delete mode 100644 app/src/main/res/layout/fragment_filechooser_list.xml delete mode 100644 app/src/main/res/values-large/refs.xml delete mode 100644 app/src/main/res/values-sw600dp/refs.xml delete mode 100644 app/src/main/res/values/refs.xml diff --git a/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java b/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java index 4afa4c8..926cc8e 100644 --- a/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java +++ b/app/src/main/java/com/doplgangr/secrecy/adapters/FileChooserAdapter.java @@ -1,14 +1,11 @@ package com.doplgangr.secrecy.adapters; +import android.app.Activity; import android.content.Context; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.drawable.Drawable; +import android.support.v7.widget.RecyclerView; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.ImageView; import android.widget.TextView; @@ -20,53 +17,91 @@ import java.io.File; import java.util.List; -public class FileChooserAdapter extends ArrayAdapter { +public class FileChooserAdapter extends RecyclerView.Adapter { private Context context; + /** + * Inflater of the context; + */ + private LayoutInflater inflater; /** * File object of the directory to be displayed */ private File rootFile; + /** + * File object of the children to the directory to be displayed + */ + private List files; + + private FileChooserFragment.OnFileChosen mListener; - public FileChooserAdapter(Context context, - List objects, File rootFile) { - super(context, R.layout.listitem_single_line_text, R.id.text1, objects); + + public FileChooserAdapter(Activity context, + List files, File rootFile, FileChooserFragment.OnFileChosen mListener) { this.context = context; + this.inflater = context.getLayoutInflater(); + this.files = files; this.rootFile = rootFile; + this.mListener = mListener; + } + + @Override + public FileChooserViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { + return new FileChooserViewHolder(inflater.inflate(R.layout.listitem_single_line_text, parent, false)); } + @Override - public View getView(int position, View convertView, ViewGroup parent) { - View view = super.getView(position, convertView, parent); - File item = getItem(position); - TextView textView =(TextView) view.findViewById(R.id.text1); - ImageView iconView =(ImageView) view.findViewById(R.id.icon1); + public void onBindViewHolder(FileChooserViewHolder holder, int position) { + + final File item = files.get(position); Boolean isParent = rootFile.getParentFile()!=null && rootFile.getParentFile().getAbsolutePath().equals(item.getAbsolutePath()); Boolean isFile = item.isFile(); Boolean isReadableDir = Util.canReadDir(item); - // TODO: create a more intuitive way to let user know this is "up" - // If the rootFile has a parent, display as "up" - if (isParent) - textView.setText(".."); - else { - textView.setText(item.getName()); + if (holder.textView!=null){ + // TODO: create a more intuitive way to let user know this is "up" + // If the rootFile has a parent, display as "up" + if (isParent) + holder.textView.setText(".."); + else { + holder.textView.setText(item.getName()); + } + holder.textView.setEnabled(isFile || isReadableDir); + if (isSubDirectory(item, Storage.getRoot()) && !isParent) + holder.textView.setTextColor(context.getResources().getColor(R.color.accent)); + else + holder.textView.setTextColor(context.getResources().getColor(R.color.text_primary)); } - - textView.setEnabled(isFile || isReadableDir); - if (isFile) - iconView.setImageResource(R.drawable.ic_file); - if (isReadableDir) - iconView.setImageResource(R.drawable.ic_action_folder); - - // Highlights the directory if it is the path to the current vault root - if (isSubDirectory(item, Storage.getRoot()) && !isParent) { - textView.setTextColor(context.getResources().getColor(R.color.accent)); - iconView.setColorFilter(context.getResources().getColor(R.color.accent)); - }else{ - iconView.setColorFilter(context.getResources().getColor(R.color.button)); + if (holder.iconView!=null){ + if (isFile) + holder.iconView.setImageResource(R.drawable.ic_file); + if (isReadableDir) + holder.iconView.setImageResource(R.drawable.ic_action_folder); + if (isSubDirectory(item, Storage.getRoot()) && !isParent) + holder.iconView.setColorFilter(context.getResources().getColor(R.color.accent)); + else + holder.iconView.setColorFilter(context.getResources().getColor(R.color.button)); } + holder.itemView.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (null != mListener) { + // Notify the active callbacks interface (the activity, if the + // fragment is attached to one) that an item has been selected. + if (Util.canReadDir(item)) + mListener.onFileSelected(item, false); + else + mListener.onFileSelected(item, true); + } + } + }); + } - return view; + @Override + public int getItemCount() { + if (files!=null) + return files.size(); + return 0; } /** @@ -82,4 +117,14 @@ public static boolean isSubDirectory(File directory, File file) { return true; return isSubDirectory(directory, file.getParentFile()); } + + public class FileChooserViewHolder extends RecyclerView.ViewHolder{ + TextView textView; + ImageView iconView; + public FileChooserViewHolder(View itemView) { + super(itemView); + textView =(TextView) itemView.findViewById(R.id.text1); + iconView =(ImageView) itemView.findViewById(R.id.icon1); + } + } } diff --git a/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java b/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java index 5b57fa1..2b58cd0 100644 --- a/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java +++ b/app/src/main/java/com/doplgangr/secrecy/fragments/FileChooserFragment.java @@ -6,24 +6,20 @@ import android.os.Bundle; import android.app.Fragment; import android.os.Environment; +import android.support.v7.widget.LinearLayoutManager; +import android.support.v7.widget.RecyclerView; 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.AbsListView; -import android.widget.AdapterView; import android.widget.EditText; -import android.widget.ListAdapter; -import android.widget.TextView; import com.doplgangr.secrecy.R; import com.doplgangr.secrecy.activities.FileChooserActivity; import com.doplgangr.secrecy.adapters.FileChooserAdapter; -import com.doplgangr.secrecy.utils.Util; -import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import java.io.File; @@ -36,14 +32,8 @@ /** * A fragment to display a file chooser interface - *

- * Large screen devices (such as tablets) are supported by replacing the ListView - * with a GridView. - *

- * Activities containing this fragment MUST implement the {@link OnFileChosen} - * interface to catch navigation and file choosing actions */ -public class FileChooserFragment extends Fragment implements AbsListView.OnItemClickListener { +public class FileChooserFragment extends Fragment { /** * Fragment parameter ROOT @@ -63,13 +53,13 @@ public class FileChooserFragment extends Fragment implements AbsListView.OnItemC /** * The fragment's ListView/GridView. */ - private AbsListView mListView; + private RecyclerView mRecyclerView; /** * The Adapter which will be used to populate the ListView/GridView with * Views. */ - private ListAdapter mAdapter; + private FileChooserAdapter mAdapter; /** * The location of directory where views are displaying. @@ -163,7 +153,7 @@ public int compare(File file1, File file2) { Collections.addAll(ITEMS,filesListed); - mAdapter = new FileChooserAdapter(getActivity(), ITEMS, rootFile); + mAdapter = new FileChooserAdapter(getActivity(), ITEMS, rootFile, mListener); setHasOptionsMenu(true); } @@ -207,13 +197,17 @@ public void onClick(DialogInterface dialogInterface, int i) { public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.fragment_filechooser, container, false); - mListView = (AbsListView) view.findViewById(android.R.id.list); + mRecyclerView = (RecyclerView) view.findViewById(R.id.file_chooser_recyclerView); - // Set the adapter - mListView.setAdapter(mAdapter); + mRecyclerView.setLayoutManager + (new LinearLayoutManager( + container.getContext(), + LinearLayoutManager.VERTICAL, + false)); + mRecyclerView.setHasFixedSize(true); - // Set OnItemClickListener so we can be notified on item clicks - mListView.setOnItemClickListener(this); + // Set the adapter + mRecyclerView.setAdapter(mAdapter); // Set the toolbar to have location name getActivity().setTitle(rootFile.getAbsolutePath()); @@ -238,31 +232,6 @@ public void onDetach() { mListener = null; } - @Override - public void onItemClick(AdapterView parent, View view, int position, long id) { - if (null != mListener) { - // Notify the active callbacks interface (the activity, if the - // fragment is attached to one) that an item has been selected. - if (Util.canReadDir(ITEMS.get(position))) - mListener.onFileSelected(ITEMS.get(position),false); - else - mListener.onFileSelected(ITEMS.get(position),true); - } - } - - /** - * The default content for this Fragment has a TextView that is shown when - * the list is empty. If you would like to change the text, call this method - * to supply the text it should use. - */ - public void setEmptyText(CharSequence emptyText) { - View emptyView = mListView.getEmptyView(); - - if (emptyView instanceof TextView) { - ((TextView) emptyView).setText(emptyText); - } - } - /** * This interface must be implemented by activities that contain this * fragment to allow an interaction in this fragment to be communicated diff --git a/app/src/main/res/layout/fragment_filechooser.xml b/app/src/main/res/layout/fragment_filechooser.xml new file mode 100644 index 0000000..a01aa3a --- /dev/null +++ b/app/src/main/res/layout/fragment_filechooser.xml @@ -0,0 +1,8 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_filechooser_grid.xml b/app/src/main/res/layout/fragment_filechooser_grid.xml deleted file mode 100644 index 67c9c22..0000000 --- a/app/src/main/res/layout/fragment_filechooser_grid.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/layout/fragment_filechooser_list.xml b/app/src/main/res/layout/fragment_filechooser_list.xml deleted file mode 100644 index 131ce1b..0000000 --- a/app/src/main/res/layout/fragment_filechooser_list.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - diff --git a/app/src/main/res/values-large/refs.xml b/app/src/main/res/values-large/refs.xml deleted file mode 100644 index d908a5c..0000000 --- a/app/src/main/res/values-large/refs.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - @layout/fragment_filechooser_grid - - \ No newline at end of file diff --git a/app/src/main/res/values-sw600dp/refs.xml b/app/src/main/res/values-sw600dp/refs.xml deleted file mode 100644 index d908a5c..0000000 --- a/app/src/main/res/values-sw600dp/refs.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - @layout/fragment_filechooser_grid - - \ No newline at end of file diff --git a/app/src/main/res/values/color.xml b/app/src/main/res/values/color.xml index 653a93f..4fdd3d2 100644 --- a/app/src/main/res/values/color.xml +++ b/app/src/main/res/values/color.xml @@ -22,5 +22,6 @@ @color/quantum_deeporange_A400 @color/button_material_light + @color/primary_text_default_material_light #727272 \ No newline at end of file diff --git a/app/src/main/res/values/refs.xml b/app/src/main/res/values/refs.xml deleted file mode 100644 index 8f31101..0000000 --- a/app/src/main/res/values/refs.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - @layout/fragment_filechooser_list - - \ No newline at end of file