From be1a6205ef69d14a941cd045ca59cb58b04c166c Mon Sep 17 00:00:00 2001 From: Aditya-Sood Date: Mon, 12 Nov 2018 02:25:15 +0530 Subject: [PATCH] Enhancement #779 : Add menu to share ZIM files (#866) * Add issue#779.txt containing enhancement specifications * UI Changes (Long click response - Contextual action bar) * Fix Bug: List item selection bug, Add: Selected item highlighting * Shift delete ZIM file functionality to CAB * Add: Share ZIM file functionality to CAB (Cleanup to be done) * Code clean up & comments * Remove extra file * Remove extra comment * Update due to merge with master and pull request review * Fix Bug: Share ZIM file on removable storage media (SD Card, USB Drive) --- app/src/main/AndroidManifest.xml | 2 +- .../ZimFileSelectFragment.java | 138 +++++++++++++++++- .../main/res/drawable/baseline_share_24.xml | 9 ++ app/src/main/res/drawable/highlight.xml | 6 + app/src/main/res/layout/library_item.xml | 3 +- .../res/menu/menu_zim_files_contextual.xml | 23 +++ app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/provider_paths.xml | 7 +- 8 files changed, 182 insertions(+), 8 deletions(-) create mode 100644 app/src/main/res/drawable/baseline_share_24.xml create mode 100644 app/src/main/res/drawable/highlight.xml create mode 100644 app/src/main/res/menu/menu_zim_files_contextual.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c44a08c6f..021e044e7 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -186,7 +186,7 @@ selectedViewPosition = new ArrayList(); + + @Override + public void onItemCheckedStateChanged(ActionMode mode, int position, long id, boolean checked) { + + if(checked) { // If the item was selected + selectedViewPosition.add(position); + mode.setTitle("" + selectedViewPosition.size()); // Update title of the CAB + } + else { // If the item was deselected + selectedViewPosition.remove(Integer.valueOf(position)); + mode.setTitle("" + selectedViewPosition.size()); // Update title of the CAB + } + + } + + @Override + public boolean onCreateActionMode(ActionMode mode, Menu menu) { + // Inflate and setup the Contextual Action Bar (CAB) + MenuInflater inflater = mode.getMenuInflater(); + inflater.inflate(R.menu.menu_zim_files_contextual, menu); + + return true; + } + + @Override + public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // Leave the default implementation as is + return false; + } + + @Override + public boolean onActionItemClicked(ActionMode mode, MenuItem item) { + + switch(item.getItemId()) { // Determine the action item clicked on in the CAB, and respond accordingly + + // Initiate file deletion functionality for each selected list item (file) + case R.id.zim_file_delete_item : + + for(int i = 0; i < selectedViewPosition.size(); i++) + deleteSpecificZimDialog(selectedViewPosition.get(i)); // Individually confirm & initiate deletion for each selected file + + mode.finish(); // Action performed, so close CAB + return true; + + + // Initiate file sharing functionality for each selected list item (file) + case R.id.zim_file_share_item : + + // Create an implicit intent for sharing multiple selected files + Intent selectedFileShareIntent = new Intent(); + selectedFileShareIntent.setAction(Intent.ACTION_SEND_MULTIPLE); + selectedFileShareIntent.setType("application/octet-stream"); // ZIM files are binary data without an Android-predefined subtype + + ArrayList selectedFileContentURIs = new ArrayList(); // Store Content URIs for all selected files being shared + + for(int i = 0; i < selectedViewPosition.size(); i++) { + + LibraryNetworkEntity.Book data = (LibraryNetworkEntity.Book) mZimFileList.getItemAtPosition(selectedViewPosition.get(i)); + String shareFilePath = data.file.getPath(); //Returns path to file in device storage + + /** + * Using 'file:///' URIs directly is unsafe as it grants the intent receiving application + * the same file system permissions as the intent creating app. + * + * FileProvider instead offers 'content://' URIs for sharing files, which offer temporary + * access permissions to the file being shared (to the intent receiving application), which + * is fundamentally safer. + */ + + File shareFile = new File(shareFilePath); + Uri shareContentUri = FileProvider.getUriForFile(getContext(), BuildConfig.APPLICATION_ID + ".fileprovider", shareFile); + + if(shareContentUri != null) + selectedFileContentURIs.add(shareContentUri); // Populate with the selected file content URIs + } + + selectedFileShareIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, selectedFileContentURIs); // Intent Extra for storing the array list of selected file content URIs + + if(selectedFileContentURIs != null) { // Grant temporary access permission to the intent receiver for the content URIs + selectedFileShareIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); + } + + /** + * Since a different app may be used for sharing everytime (E-mail, Cloud Upload, Wifi Sharing, etc.), + * so force an app chooser dialog every time some selected files are to be shared. + */ + Intent shareChooserIntent = Intent.createChooser(selectedFileShareIntent, getResources().getString(R.string.selected_file_cab_app_chooser_title)); + + if(shareChooserIntent.resolveActivity(getActivity().getPackageManager()) != null) + startActivity(shareChooserIntent); // Open the app chooser dialog + + mode.finish(); // Action performed, so close CAB + return true; + + + default : + return false; + + } + } + + @Override + public void onDestroyActionMode(ActionMode mode) { + // Upon closure of the CAB, empty the array list of selected list item positions + selectedViewPosition.clear(); + } + + }); + + return llLayout; // Return the loaded Layout } @Override @@ -129,8 +257,8 @@ public class ZimFileSelectFragment extends BaseFragment if (mZimFileList == null) return; + // Long click response is the Contextual Action Bar (Selected file deletion & sharing) mZimFileList.setOnItemClickListener(this); - mZimFileList.setOnItemLongClickListener(this); Collections.sort(books, new FileComparator()); mFiles.clear(); mFiles.addAll(books); @@ -267,14 +395,14 @@ public class ZimFileSelectFragment extends BaseFragment @Override public boolean onItemLongClick(AdapterView parent, View view, int position, long id) { - deleteSpecificZimDialog(position); - return true; + return false; } public void deleteSpecificZimDialog(int position) { new AlertDialog.Builder(zimManageActivity, dialogStyle()) - .setMessage(getString(R.string.delete_specific_zim)) + .setMessage(mFiles.get(position).getTitle() + ": " + getString(R.string.delete_specific_zim)) .setPositiveButton(getResources().getString(R.string.delete), (dialog, which) -> { + // Toast messages updated for coherence with the new manner of file deletion (from CAB) if (deleteSpecificZimFile(position)) { Toast.makeText(zimManageActivity, getResources().getString(R.string.delete_specific_zim_toast), Toast.LENGTH_SHORT).show(); } else { diff --git a/app/src/main/res/drawable/baseline_share_24.xml b/app/src/main/res/drawable/baseline_share_24.xml new file mode 100644 index 000000000..9c04fa74e --- /dev/null +++ b/app/src/main/res/drawable/baseline_share_24.xml @@ -0,0 +1,9 @@ + + + diff --git a/app/src/main/res/drawable/highlight.xml b/app/src/main/res/drawable/highlight.xml new file mode 100644 index 000000000..7bde13d8e --- /dev/null +++ b/app/src/main/res/drawable/highlight.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/library_item.xml b/app/src/main/res/layout/library_item.xml index 143886043..2ecdf94e7 100755 --- a/app/src/main/res/layout/library_item.xml +++ b/app/src/main/res/layout/library_item.xml @@ -8,7 +8,8 @@ android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" - android:paddingTop="@dimen/activity_vertical_margin"> + android:paddingTop="@dimen/activity_vertical_margin" + android:background="@drawable/highlight"> + + + + + + + + + \ 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 849694141..6405d4ecc 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -56,6 +56,8 @@ Clear recent searches and tabs history All History Cleared Clear All History + Share + Share ZIM files with: Delete Recent search removed You can swipe left to view the contents of this article diff --git a/app/src/main/res/xml/provider_paths.xml b/app/src/main/res/xml/provider_paths.xml index 4495c28c8..67173eb06 100644 --- a/app/src/main/res/xml/provider_paths.xml +++ b/app/src/main/res/xml/provider_paths.xml @@ -1,4 +1,9 @@ - + + \ No newline at end of file