1
0
Fork 0
Kate Glazko 2019-11-07 20:31:21 -08:00
parent 4ae60f2cce
commit e038e0c41d
2 changed files with 53 additions and 16 deletions

View File

@ -10,6 +10,10 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.mozilla.fenix.components.FenixSnackbar import org.mozilla.fenix.components.FenixSnackbar
import android.app.AlertDialog
import org.mozilla.fenix.R
import android.content.Context
import android.view.accessibility.AccessibilityManager
import java.util.concurrent.atomic.AtomicBoolean import java.util.concurrent.atomic.AtomicBoolean
internal const val UNDO_DELAY = 3000L internal const val UNDO_DELAY = 3000L
@ -40,29 +44,58 @@ fun CoroutineScope.allowUndo(
// writing a volatile variable. // writing a volatile variable.
val requestedUndo = AtomicBoolean(false) val requestedUndo = AtomicBoolean(false)
// Launch an indefinite snackbar. fun showUndoDialog() {
val snackbar = FenixSnackbar val dialogBuilder = AlertDialog.Builder(view.context)
.make(view, FenixSnackbar.LENGTH_INDEFINITE) dialogBuilder.setMessage(message).setCancelable(false)
.setText(message) .setPositiveButton(R.string.a11y_dialog_deleted_confirm) { _, _ ->
.setAnchorView(anchorView) launch {
.setAction(undoActionTitle) { operation.invoke()
requestedUndo.set(true) }
}.setNegativeButton(R.string.a11y_dialog_deleted_undo) { _, _ ->
launch { launch {
onCancel.invoke() onCancel.invoke()
} }
} }
val alert = dialogBuilder.create()
alert.show()
}
// If user engages with the snackbar, it'll get automatically dismissed. fun showUndoSnackbar() {
snackbar.show() val snackbar = FenixSnackbar
.make(view, FenixSnackbar.LENGTH_INDEFINITE)
.setText(message)
.setAnchorView(anchorView)
.setAction(undoActionTitle) {
requestedUndo.set(true)
launch {
onCancel.invoke()
}
}
// Wait a bit, and if user didn't request cancellation, proceed with snackbar.show()
// requested operation and hide the snackbar.
launch {
delay(UNDO_DELAY)
if (!requestedUndo.get()) { // Wait a bit, and if user didn't request cancellation, proceed with
snackbar.dismiss() // requested operation and hide the snackbar.
operation.invoke() launch {
delay(UNDO_DELAY)
if (!requestedUndo.get()) {
snackbar.dismiss()
operation.invoke()
}
} }
} }
// It is difficult to use our Snackbars quickly enough with
// Talkback enabled, so in that case we show a dialog instead
if (touchExplorationEnabled(view)) {
showUndoDialog()
} else {
showUndoSnackbar()
}
}
fun touchExplorationEnabled(view: View): Boolean {
val am = view.context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
return am.isTouchExplorationEnabled
} }

View File

@ -653,6 +653,10 @@
<string name="snackbar_private_tabs_deleted">Private tabs deleted</string> <string name="snackbar_private_tabs_deleted">Private tabs deleted</string>
<!-- Text for action to undo deleting a tab or collection shown in snackbar --> <!-- Text for action to undo deleting a tab or collection shown in snackbar -->
<string name="snackbar_deleted_undo">UNDO</string> <string name="snackbar_deleted_undo">UNDO</string>
<!-- Text for action to undo deleting a tab or collection shown in a11y dialog -->
<string name="a11y_dialog_deleted_undo">Undo</string>
<!-- Text for action to confirm deleting a tab or collection shown in a11y dialog -->
<string name="a11y_dialog_deleted_confirm">Confirm</string>
<!-- QR code scanner prompt which appears after scanning a code, but before navigating to it <!-- QR code scanner prompt which appears after scanning a code, but before navigating to it
First parameter is the name of the app, second parameter is the URL or text scanned--> First parameter is the name of the app, second parameter is the URL or text scanned-->
<string name="qr_scanner_confirmation_dialog_message">Allow %1$s to open %2$s</string> <string name="qr_scanner_confirmation_dialog_message">Allow %1$s to open %2$s</string>