mirror of
https://github.com/kiwix/kiwix-android.git
synced 2025-08-03 18:56:44 -04:00
* 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)
This commit is contained in:
parent
e053f5bf71
commit
be1a6205ef
@ -186,7 +186,7 @@
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:authorities="${applicationId}.provider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:exported="false"
|
||||
android:grantUriPermissions="true">
|
||||
<meta-data
|
||||
|
@ -17,21 +17,33 @@
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Fragment for list of downloaded ZIM files
|
||||
*/
|
||||
|
||||
package org.kiwix.kiwixmobile.zim_manager.fileselect_view;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v4.content.ContextCompat;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.support.v4.widget.SwipeRefreshLayout;
|
||||
import android.support.v7.app.AlertDialog;
|
||||
import android.util.Log;
|
||||
import android.view.ActionMode;
|
||||
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.AdapterView.OnItemClickListener;
|
||||
import android.widget.ArrayAdapter;
|
||||
@ -41,6 +53,7 @@ import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import org.kiwix.kiwixmobile.BuildConfig;
|
||||
import org.kiwix.kiwixmobile.KiwixApplication;
|
||||
import org.kiwix.kiwixmobile.R;
|
||||
import org.kiwix.kiwixmobile.base.BaseFragment;
|
||||
@ -113,7 +126,122 @@ public class ZimFileSelectFragment extends BaseFragment
|
||||
|
||||
// Allow temporary use of ZimContentProvider to query books
|
||||
ZimContentProvider.canIterate = true;
|
||||
return llLayout; // We must return the loaded Layout
|
||||
|
||||
// Setting up Contextual Action Mode in response to selection of ZIM files in the ListView
|
||||
mZimFileList.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE_MODAL);
|
||||
mZimFileList.setMultiChoiceModeListener(new AbsListView.MultiChoiceModeListener() {
|
||||
|
||||
// Holds positions corresponding to every selected list item in the ListView
|
||||
private ArrayList<Integer> selectedViewPosition = new ArrayList<Integer>();
|
||||
|
||||
@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<Uri> selectedFileContentURIs = new ArrayList<Uri>(); // 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 {
|
||||
|
9
app/src/main/res/drawable/baseline_share_24.xml
Normal file
9
app/src/main/res/drawable/baseline_share_24.xml
Normal file
@ -0,0 +1,9 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z"/>
|
||||
</vector>
|
6
app/src/main/res/drawable/highlight.xml
Normal file
6
app/src/main/res/drawable/highlight.xml
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item
|
||||
android:state_activated="true"
|
||||
android:drawable="@color/greyed_out_selected"/>
|
||||
</selector>
|
@ -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">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/favicon"
|
||||
|
23
app/src/main/res/menu/menu_zim_files_contextual.xml
Normal file
23
app/src/main/res/menu/menu_zim_files_contextual.xml
Normal file
@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<menu xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<item
|
||||
android:id="@+id/zim_file_delete_item"
|
||||
android:icon="@drawable/ic_delete_white_24dp"
|
||||
android:title="@string/delete"
|
||||
android:visible="true"
|
||||
app:iconifiedByDefault="true"
|
||||
app:showAsAction="always" />
|
||||
|
||||
<item
|
||||
android:id="@+id/zim_file_share_item"
|
||||
android:icon="@drawable/baseline_share_24"
|
||||
android:title="@string/share"
|
||||
android:visible="true"
|
||||
app:iconifiedByDefault="true"
|
||||
app:showAsAction="always"/>
|
||||
|
||||
</menu>
|
||||
|
||||
<!-- Menu layout for Contextual Action Bar in response to file selection in the library (ZimFileSelectFragment.java) -->
|
@ -56,6 +56,8 @@
|
||||
<string name="pref_clear_all_history_summary">Clear recent searches and tabs history</string>
|
||||
<string name="all_history_cleared_toast">All History Cleared</string>
|
||||
<string name="clear_all_history_dialog_title">Clear All History</string>
|
||||
<string name="share">Share</string>
|
||||
<string name="selected_file_cab_app_chooser_title">Share ZIM files with:</string>
|
||||
<string name="delete">Delete</string>
|
||||
<string name="delete_specific_search_toast">Recent search removed</string>
|
||||
<string name="hint_contents_drawer_message">You can swipe left to view the contents of this article</string>
|
||||
|
@ -1,4 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<paths>
|
||||
<external-path name="external_files" path="."/>
|
||||
<external-path
|
||||
name="external_files"
|
||||
path="." />
|
||||
<root-path
|
||||
name="external_files"
|
||||
path="/storage/" />
|
||||
</paths>
|
Loading…
x
Reference in New Issue
Block a user