Skip to content

Commit 46e9f20

Browse files
authored
Merge pull request #3638 from owncloud/feature/multi_send
[FEATURE] Enable "Send" functionality for file multiselect
2 parents 18450b5 + 3184f36 commit 46e9f20

5 files changed

Lines changed: 123 additions & 42 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ Summary
2525
* Enhancement - New option to show or not hidden files: [#2578](https://github.com/owncloud/android/issues/2578)
2626
* Enhancement - Option to allow screenshots or not in Android Enterprise: [#3625](https://github.com/owncloud/android/issues/3625)
2727
* Enhancement - Full name is shown in shares: [#1106](https://github.com/owncloud/android/issues/1106)
28+
* Enhancement - Send for file multiselect: [#3491](https://github.com/owncloud/android/issues/3491)
2829
* Enhancement - Support for SVG files added: [#1033](https://github.com/owncloud/android/issues/1033)
2930
* Enhancement - Improved copy/move dialog: [#1414](https://github.com/owncloud/android/issues/1414)
3031
* Enhancement - Thumbnail click action in file detail: [#3653](https://github.com/owncloud/android/pull/3653)
@@ -164,6 +165,13 @@ Details
164165
https://github.com/owncloud/android/issues/1106
165166
https://github.com/owncloud/android/pull/3636
166167

168+
* Enhancement - Send for file multiselect: [#3491](https://github.com/owncloud/android/issues/3491)
169+
170+
Send multiple files at once if they are downloaded.
171+
172+
https://github.com/owncloud/android/issues/3491
173+
https://github.com/owncloud/android/pull/3638
174+
167175
* Enhancement - Support for SVG files added: [#1033](https://github.com/owncloud/android/issues/1033)
168176

169177
SVG files are supported and can be downloaded and viewed.

changelog/unreleased/3638

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
Enhancement: Send for file multiselect
2+
3+
Send multiple files at once if they are downloaded.
4+
5+
https://github.com/owncloud/android/issues/3491
6+
https://github.com/owncloud/android/pull/3638

owncloudApp/src/main/java/com/owncloud/android/files/FileMenuFilter.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
* @author Christian Schabesberger
66
* @author Abel García de Prada
77
* @author Shashvat Kedia
8-
* Copyright (C) 2020 ownCloud GmbH.
8+
* @author David Crespo Rios
9+
* Copyright (C) 2022 ownCloud GmbH.
910
* <p>
1011
* This program is free software: you can redistribute it and/or modify
1112
* it under the terms of the GNU General Public License version 2,
@@ -248,7 +249,7 @@ private void filter(List<Integer> toShow, List<Integer> toHide, boolean displayS
248249
// SEND
249250
boolean sendAllowed = (mContext != null &&
250251
mContext.getString(R.string.send_files_to_other_apps).equalsIgnoreCase("on"));
251-
if (!isSingleFile() || !sendAllowed || synchronizing || videoStreaming || onlyAvailableOffline) {
252+
if (containsFolder() || (!areDownloaded() && !isSingleFile()) || !sendAllowed || synchronizing || videoStreaming || onlyAvailableOffline) {
252253
toHide.add(R.id.action_send_file);
253254
} else {
254255
toShow.add(R.id.action_send_file);
@@ -337,6 +338,15 @@ private boolean isSingleFile() {
337338
return isSingleSelection() && !mFiles.get(0).isFolder();
338339
}
339340

341+
private boolean areDownloaded() {
342+
for (OCFile file : mFiles) {
343+
if (!file.isDown()) {
344+
return false;
345+
}
346+
}
347+
return true;
348+
}
349+
340350
private boolean containsFolder() {
341351
for (OCFile file : mFiles) {
342352
if (file.isFolder()) {

owncloudApp/src/main/java/com/owncloud/android/ui/fragment/OCFileListFragment.java

Lines changed: 51 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,9 @@
88
* @author David González Verdugo
99
* @author Shashvat Kedia
1010
* @author Abel García de Prada
11+
* @author David Crespo Rios
1112
* Copyright (C) 2011 Bartek Przybylski
12-
* Copyright (C) 2020 ownCloud GmbH.
13+
* Copyright (C) 2022 ownCloud GmbH.
1314
* <p>
1415
* This program is free software: you can redistribute it and/or modify
1516
* it under the terms of the GNU General Public License version 2,
@@ -350,42 +351,39 @@ private void registerFabListeners() {
350351
* on the Upload mini FAB for the linked action an {@link Snackbar} showing the underlying action.
351352
*/
352353
private void registerFabUploadListeners() {
353-
getFabUpload().setOnClickListener(new View.OnClickListener() {
354-
@Override
355-
public void onClick(View v) {
356-
final View uploadBottomSheet = getLayoutInflater().inflate(R.layout.upload_bottom_sheet_fragment, null);
357-
final BottomSheetDialog dialog = new BottomSheetDialog(requireContext());
358-
dialog.setContentView(uploadBottomSheet);
359-
final BottomSheetFragmentItemView uploadFromFilesItemView = uploadBottomSheet.findViewById(R.id.upload_from_files_item_view);
360-
BottomSheetFragmentItemView uploadFromCameraItemView =
361-
uploadBottomSheet.findViewById(R.id.upload_from_camera_item_view);
362-
TextView uploadToTextView = uploadBottomSheet.findViewById(R.id.upload_to_text_view);
363-
uploadFromFilesItemView.setOnTouchListener((v13, event) -> {
364-
Intent action = new Intent(Intent.ACTION_GET_CONTENT);
365-
action = action.setType(ALL_FILES_SAF_REGEX).addCategory(Intent.CATEGORY_OPENABLE);
366-
action.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
367-
getActivity().startActivityForResult(
368-
Intent.createChooser(action, getString(R.string.upload_chooser_title)),
369-
FileDisplayActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS
370-
);
371-
dialog.hide();
372-
return false;
373-
});
374-
uploadFromCameraItemView.setOnTouchListener((v12, event) -> {
375-
((FileDisplayActivity) getActivity()).getFilesUploadHelper().uploadFromCamera(FileDisplayActivity.REQUEST_CODE__UPLOAD_FROM_CAMERA);
376-
dialog.hide();
377-
return false;
378-
});
379-
uploadToTextView.setText(String.format(getResources().getString(R.string.upload_to),
380-
getResources().getString(R.string.app_name)));
381-
final BottomSheetBehavior uploadBottomSheetBehavior =
382-
BottomSheetBehavior.from((View) uploadBottomSheet.getParent());
383-
dialog.setOnShowListener(dialog1 ->
384-
uploadBottomSheetBehavior.setPeekHeight(uploadBottomSheet.getMeasuredHeight()));
385-
dialog.show();
386-
getFabMain().collapse();
387-
recordMiniFabClick();
388-
}
354+
getFabUpload().setOnClickListener(v -> {
355+
final View uploadBottomSheet = getLayoutInflater().inflate(R.layout.upload_bottom_sheet_fragment, null);
356+
final BottomSheetDialog dialog = new BottomSheetDialog(requireContext());
357+
dialog.setContentView(uploadBottomSheet);
358+
final BottomSheetFragmentItemView uploadFromFilesItemView = uploadBottomSheet.findViewById(R.id.upload_from_files_item_view);
359+
BottomSheetFragmentItemView uploadFromCameraItemView =
360+
uploadBottomSheet.findViewById(R.id.upload_from_camera_item_view);
361+
TextView uploadToTextView = uploadBottomSheet.findViewById(R.id.upload_to_text_view);
362+
uploadFromFilesItemView.setOnTouchListener((v13, event) -> {
363+
Intent action = new Intent(Intent.ACTION_GET_CONTENT);
364+
action = action.setType(ALL_FILES_SAF_REGEX).addCategory(Intent.CATEGORY_OPENABLE);
365+
action.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
366+
getActivity().startActivityForResult(
367+
Intent.createChooser(action, getString(R.string.upload_chooser_title)),
368+
FileDisplayActivity.REQUEST_CODE__SELECT_CONTENT_FROM_APPS
369+
);
370+
dialog.hide();
371+
return false;
372+
});
373+
uploadFromCameraItemView.setOnTouchListener((v12, event) -> {
374+
((FileDisplayActivity) getActivity()).getFilesUploadHelper().uploadFromCamera(FileDisplayActivity.REQUEST_CODE__UPLOAD_FROM_CAMERA);
375+
dialog.hide();
376+
return false;
377+
});
378+
uploadToTextView.setText(String.format(getResources().getString(R.string.upload_to),
379+
getResources().getString(R.string.app_name)));
380+
final BottomSheetBehavior uploadBottomSheetBehavior =
381+
BottomSheetBehavior.from((View) uploadBottomSheet.getParent());
382+
dialog.setOnShowListener(dialog1 ->
383+
uploadBottomSheetBehavior.setPeekHeight(uploadBottomSheet.getMeasuredHeight()));
384+
dialog.show();
385+
getFabMain().collapse();
386+
recordMiniFabClick();
389387
});
390388

391389
getFabUpload().setOnLongClickListener(v -> {
@@ -943,9 +941,7 @@ private boolean onFileActionChosen(int menuId) {
943941
case R.id.action_send_file: {
944942
// Obtain the file
945943
if (!singleFile.isDown()) { // Download the file
946-
Timber.d("%s : File must be downloaded", singleFile.getRemotePath());
947944
((FileDisplayActivity) mContainerActivity).startDownloadForSending(singleFile);
948-
949945
} else {
950946
mContainerActivity.getFileOperationsHelper().sendDownloadedFile(singleFile);
951947
}
@@ -970,6 +966,12 @@ private boolean onFileActionChosen(int menuId) {
970966
}
971967
return true;
972968
}
969+
case R.id.action_send_file: {
970+
if (checkedFiles.size() > 1 && filesAreDown(checkedFiles)) {
971+
mContainerActivity.getFileOperationsHelper().sendDownloadedFiles(checkedFiles);
972+
}
973+
return true;
974+
}
973975
case R.id.action_remove_file: {
974976
RemoveFilesDialogFragment dialog = RemoveFilesDialogFragment.newInstance(checkedFiles);
975977
dialog.show(getFragmentManager(), ConfirmationDialogFragment.FTAG_CONFIRMATION);
@@ -1081,6 +1083,16 @@ public void listDirectory(OCFile directory) {
10811083
}
10821084
}
10831085

1086+
private boolean filesAreDown(ArrayList<OCFile> checkedFiles) {
1087+
for (int i = 0; i < checkedFiles.size(); i++) {
1088+
if (!checkedFiles.get(i).isDown()) {
1089+
Timber.d("%s : File must be downloaded", checkedFiles.get(i).getRemotePath());
1090+
return false;
1091+
}
1092+
}
1093+
return true;
1094+
}
1095+
10841096
private void updateLayout() {
10851097
if (!isShowingJustFolders()) {
10861098
int filesCount = 0, foldersCount = 0;

owncloudApp/src/main/java/com/owncloud/android/ui/helpers/FileOperationsHelper.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66
* @author Juan Carlos González Cabrero
77
* @author David González Verdugo
88
* @author Shashvat Kedia
9-
* Copyright (C) 2020 ownCloud GmbH.
9+
* @author David Crespo Rios
10+
* Copyright (C) 2022 ownCloud GmbH.
1011
* <p>
1112
* This program is free software: you can redistribute it and/or modify
1213
* it under the terms of the GNU General Public License version 2,
@@ -45,7 +46,9 @@
4546
import com.owncloud.android.ui.dialog.ShareLinkToDialog;
4647
import timber.log.Timber;
4748

49+
import java.util.ArrayList;
4850
import java.util.Collection;
51+
import java.util.List;
4952

5053
import static com.owncloud.android.services.OperationsService.EXTRA_SYNC_REGULAR_FILES;
5154

@@ -183,6 +186,24 @@ private Intent makeActionSendIntent(OCFile oCfile) {
183186
return sendIntent;
184187
}
185188

189+
private Intent makeActionSendIntent(List<OCFile> oCfiles) {
190+
Intent sendIntent = new Intent();
191+
192+
ArrayList<Uri> fileUris = new ArrayList<>();
193+
for (int i = 0; i < oCfiles.size(); i++) {
194+
fileUris.add(oCfiles.get(i).getExposedFileUri(mFileActivity));
195+
}
196+
197+
// set Type (All)
198+
sendIntent.setType("*/*");
199+
sendIntent.putParcelableArrayListExtra(
200+
Intent.EXTRA_STREAM,
201+
fileUris
202+
);
203+
sendIntent.setAction(Intent.ACTION_SEND_MULTIPLE);// Send Action
204+
return sendIntent;
205+
}
206+
186207
public void sendDownloadedFile(OCFile ocFile) {
187208
if (ocFile != null) {
188209
Intent sendIntent = makeActionSendIntent(ocFile);
@@ -207,6 +228,30 @@ public void sendDownloadedFile(OCFile ocFile) {
207228
}
208229
}
209230

231+
public void sendDownloadedFiles(List<OCFile> ocFiles) {
232+
if (!ocFiles.isEmpty()) {
233+
Intent sendIntent = makeActionSendIntent(ocFiles);
234+
// Show dialog, without the own app
235+
String[] packagesToExclude = new String[]{mFileActivity.getPackageName()};
236+
237+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
238+
Intent shareSheetIntent = new ShareSheetHelper().getShareSheetIntent(
239+
sendIntent,
240+
mFileActivity.getApplicationContext(),
241+
R.string.activity_chooser_send_file_title,
242+
packagesToExclude
243+
);
244+
245+
mFileActivity.startActivity(shareSheetIntent);
246+
} else {
247+
DialogFragment chooserDialog = ShareLinkToDialog.newInstance(sendIntent, packagesToExclude);
248+
chooserDialog.show(mFileActivity.getSupportFragmentManager(), FTAG_CHOOSER_DIALOG);
249+
}
250+
} else {
251+
Timber.e("Trying to send a NULL OCFile");
252+
}
253+
}
254+
210255
public void syncFiles(Collection<OCFile> files) {
211256
for (OCFile file : files) {
212257
syncFile(file);

0 commit comments

Comments
 (0)