Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions changelog/unreleased/4802
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
Enhancement: Show destination folder snackbar for copy/move operations

A snackbar message has been displayed after copy or move operations with an action button that allows users to quickly navigate to the destination folder.

https://github.com/owncloud/android/issues/4379
https://github.com/owncloud/android/pull/4802
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ fun Activity.showMessageInSnackbar(
Snackbar.make(findViewById(layoutId), message, duration).show()
}

fun Activity.showSnackbarWithAction(
message: CharSequence,
actionText: CharSequence,
action: () -> Unit,
duration: Int = Snackbar.LENGTH_LONG,
layoutId: Int = android.R.id.content
) {
Snackbar.make(findViewById(layoutId), message, duration)
.setAction(actionText) { action() }
.show()
}

Comment on lines +93 to +104
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that there are more snackbars with actions in the app (the re-login snackbar), so you could use this method in those cases: FileDetailsFragment.kt and FileActivity.java Up to you! If not, we can address this in a future PR 😄

fun Activity.showErrorInToast(
genericErrorMessageId: Int,
throwable: Throwable?,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,18 @@ fun Fragment.showMessageInSnackbar(
Snackbar.make(requiredView, message, duration).show()
}

fun Fragment.showSnackbarWithAction(
message: CharSequence,
actionText: CharSequence,
action: () -> Unit,
duration: Int = Snackbar.LENGTH_LONG
) {
val requiredView = view ?: return
Snackbar.make(requiredView, message, duration)
.setAction(actionText) { action() }
.show()
}

fun Fragment.showAlertDialog(
title: String,
message: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ import com.owncloud.android.extensions.openOCFile
import com.owncloud.android.extensions.sendDownloadedFilesByShareSheet
import com.owncloud.android.extensions.showErrorInSnackbar
import com.owncloud.android.extensions.showMessageInSnackbar
import com.owncloud.android.extensions.showSnackbarWithAction
import com.owncloud.android.presentation.authentication.ACTION_UPDATE_EXPIRED_TOKEN
import com.owncloud.android.presentation.authentication.EXTRA_ACCOUNT
import com.owncloud.android.presentation.authentication.EXTRA_ACTION
Expand Down Expand Up @@ -163,16 +164,18 @@ class FileDetailsFragment : FileFragment() {
when (uiResult) {
is UIResult.Error -> {
if (uiResult.error is AccountNotFoundException) {
Snackbar.make(view, getString(R.string.sync_fail_ticker_unauthorized), Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.auth_oauth_failure_snackbar_action) {
showSnackbarWithAction(
message = getString(R.string.sync_fail_ticker_unauthorized),
actionText = getString(R.string.auth_oauth_failure_snackbar_action),
action = {
val updateAccountCredentials = Intent(requireActivity(), LoginActivity::class.java)
updateAccountCredentials.apply {
putExtra(EXTRA_ACCOUNT, fileDetailsViewModel.getAccount())
putExtra(EXTRA_ACTION, ACTION_UPDATE_EXPIRED_TOKEN)
addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
}
startActivity(updateAccountCredentials)
}.show()
})
} else {
showErrorInSnackbar(R.string.sync_fail_ticker, uiResult.error)
fileDetailsViewModel.updateActionInDetailsView(NONE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ class FileListAdapter(
params -> params.marginStart = if (isFolderInKw) 0 else
context.resources.getDimensionPixelSize(R.dimen.standard_quarter_margin) }
it.fileListLastMod.text = DisplayUtils.getRelativeTimestamp(context, file.modificationTimestamp)
it.threeDotMenu.isVisible = getCheckedItems().isEmpty()
it.threeDotMenu.isVisible = !isPickerMode && getCheckedItems().isEmpty()
it.threeDotMenu.contentDescription = context.getString(R.string.content_description_file_operations, file.fileName)
if (fileListOption.isAvailableOffline() || (fileListOption.isSharedByLink() && fileWithSyncInfo.space == null)) {
it.spacePathLine.path.apply {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ class ReleaseNotesViewModel(
subtitle = R.string.release_notes_4_8_0_subtitle_spaces_permanent_links,
type = ReleaseNoteType.ENHANCEMENT
),
ReleaseNote(
title = R.string.release_notes_4_8_0_title_action_to_copy_or_move_destination_folder,
subtitle = R.string.release_notes_4_8_0_subtitle_action_to_copy_or_move_destination_folder,
type = ReleaseNoteType.ENHANCEMENT
),
ReleaseNote(
title = R.string.release_notes_bugfixes_title,
subtitle = R.string.release_notes_bugfixes_subtitle,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,11 @@
import com.owncloud.android.ui.dialog.SslUntrustedCertDialog;
import com.owncloud.android.ui.errorhandling.ErrorMessageAdapter;
import com.owncloud.android.ui.helpers.FileOperationsHelper;
import kotlin.Unit;
import timber.log.Timber;

import static com.owncloud.android.extensions.ActivityExtKt.showSnackbarWithAction;

/**
* Activity with common behaviour for activities handling {@link OCFile}s in ownCloud {@link Account}s .
*/
Expand Down Expand Up @@ -278,18 +281,32 @@ protected void showRequestAccountChangeNotice(String errorMessage, boolean mustC
.setCancelable(false)
.show();
} else {
Snackbar.make(findViewById(android.R.id.content), errorMessage, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.auth_oauth_failure_snackbar_action, v ->
requestCredentialsUpdate())
.show();
showSnackbarWithAction(
this,
errorMessage,
getString(R.string.auth_oauth_failure_snackbar_action),
() -> {
requestCredentialsUpdate();
return Unit.INSTANCE;
},
Snackbar.LENGTH_INDEFINITE,
android.R.id.content
);
}
}

protected void showRequestRegainAccess() {
Snackbar.make(findViewById(android.R.id.content), R.string.auth_oauth_failure, Snackbar.LENGTH_INDEFINITE)
.setAction(R.string.auth_oauth_failure_snackbar_action, v ->
requestCredentialsUpdate())
.show();
showSnackbarWithAction(
this,
getString(R.string.auth_oauth_failure),
getString(R.string.auth_oauth_failure_snackbar_action),
() -> {
requestCredentialsUpdate();
return Unit.INSTANCE;
},
Snackbar.LENGTH_INDEFINITE,
android.R.id.content
);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ import com.owncloud.android.extensions.parseError
import com.owncloud.android.extensions.sendDownloadedFilesByShareSheet
import com.owncloud.android.extensions.showErrorInSnackbar
import com.owncloud.android.extensions.showMessageInSnackbar
import com.owncloud.android.extensions.showSnackbarWithAction
import com.owncloud.android.lib.common.accounts.AccountUtils
import com.owncloud.android.lib.common.authentication.OwnCloudBearerCredentials
import com.owncloud.android.lib.common.network.CertificateCombinedException
Expand Down Expand Up @@ -181,6 +182,8 @@ class FileDisplayActivity : FileActivity(),
private var waitingToSend: OCFile? = null
private var waitingToOpen: OCFile? = null

private var copyMoveTargetFolder: OCFile? = null

private var localBroadcastManager: LocalBroadcastManager? = null

private val fileOperationsViewModel: FileOperationsViewModel by viewModel()
Expand Down Expand Up @@ -707,6 +710,7 @@ class FileDisplayActivity : FileActivity(),
private fun requestMoveOperation(data: Intent) {
val folderToMoveAt = data.getParcelableExtra<OCFile>(FolderPickerActivity.EXTRA_FOLDER) ?: return
val files = data.getParcelableArrayListExtra<OCFile>(FolderPickerActivity.EXTRA_FILES) ?: return
copyMoveTargetFolder = folderToMoveAt
val moveOperation = FileOperation.MoveOperation(
listOfFilesToMove = files.toList(),
targetFolder = folderToMoveAt,
Expand All @@ -723,6 +727,7 @@ class FileDisplayActivity : FileActivity(),
private fun requestCopyOperation(data: Intent) {
val folderToCopyAt = data.getParcelableExtra<OCFile>(FolderPickerActivity.EXTRA_FOLDER) ?: return
val files = data.getParcelableArrayListExtra<OCFile>(FolderPickerActivity.EXTRA_FILES) ?: return
copyMoveTargetFolder = folderToCopyAt
val copyOperation = FileOperation.CopyOperation(
listOfFilesToCopy = files.toList(),
targetFolder = folderToCopyAt,
Expand Down Expand Up @@ -1082,6 +1087,9 @@ class FileDisplayActivity : FileActivity(),
// Refresh the spaces and update the quota
spacesListViewModel.refreshSpacesFromServer()
}
if (uiResult.data.isNullOrEmpty()) {
showCopyMoveSuccessSnackbar(isCopy = false)
}
}

is UIResult.Error -> {
Expand Down Expand Up @@ -1130,6 +1138,9 @@ class FileDisplayActivity : FileActivity(),

// Refresh the spaces and update the quota
spacesListViewModel.refreshSpacesFromServer()
if (uiResult.data.isNullOrEmpty()) {
showCopyMoveSuccessSnackbar(isCopy = true)
}
}

is UIResult.Error -> {
Expand All @@ -1148,6 +1159,26 @@ class FileDisplayActivity : FileActivity(),
}
}

private fun showCopyMoveSuccessSnackbar(isCopy: Boolean) {
val message = getString(if (isCopy) R.string.copy_success_msg else R.string.move_success_msg)
val targetFolderId = copyMoveTargetFolder?.id
if (targetFolderId != null) {
showSnackbarWithAction(
message = message,
actionText = getString(R.string.go_to_destination_folder),
action = {
val fileListFragment = mainFileListFragment
?: supportFragmentManager.findFragmentById(R.id.left_fragment_container) as? MainFileListFragment
fileListFragment?.navigateToFolderId(targetFolderId)
},
layoutId = R.id.list_layout
)
} else {
showMessageInSnackbar(R.id.list_layout, message)
}
copyMoveTargetFolder = null
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a question: Is it necessary to set null at the end? Since the copyMoveTargetFolder value is set at the begin of requestMoveOperation and copyMoveOperation methods

}

private fun showConflictDecisionDialog(
uiResult: UIResult.Success<List<OCFile>>,
data: List<OCFile>,
Expand Down
6 changes: 6 additions & 0 deletions owncloudApp/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -543,14 +543,18 @@
<string name="move_file_invalid_into_descendent">It is not possible to move a folder into a descendant.</string>
<string name="move_file_invalid_overwrite">The file exists already in the destination folder.</string>
<string name="move_file_error">An error occurred while trying to move this file or folder.</string>
<string name="move_success_msg">File moved correctly</string>
<string name="forbidden_permissions_move">to move this file</string>

<string name="copy_file_not_found">Unable to copy. Please check whether the file exists.</string>
<string name="copy_file_invalid_into_descendent">It is not possible to copy a folder into a descendant.</string>
<string name="copy_file_invalid_overwrite">The file exists already in the destination folder.</string>
<string name="copy_file_error">An error occurred while trying to copy this file or folder.</string>
<string name="copy_success_msg">File copied correctly</string>
<string name="forbidden_permissions_copy">to copy this file</string>

<string name="go_to_destination_folder">Open Folder</string>

<string name="prefs_category_camera_upload">Camera uploads</string>

<string name="sync_folder_failed_content">Synchronization of %1$s folder could not be completed</string>
Expand Down Expand Up @@ -747,6 +751,8 @@
<string name="release_notes_4_8_0_subtitle_spaces_permanent_links">Infinite Scale users can now get a permanent link for a space and share it with other members</string>
<string name="release_notes_4_8_0_title_space_public_links">Space public links</string>
<string name="release_notes_4_8_0_subtitle_space_public_links">Infinite Scale users can see all public links of a space and manage them with right permissions</string>
<string name="release_notes_4_8_0_title_action_to_copy_or_move_destination_folder">Action to copy/move destination folder</string>
<string name="release_notes_4_8_0_subtitle_action_to_copy_or_move_destination_folder">Added a snackbar action to quickly navigate to the destination folder after copy/move operations.</string>

<!-- Open in web -->
<string name="ic_action_open_in_web">Open in web</string>
Expand Down