Skip to content
This repository has been archived by the owner on Feb 20, 2023. It is now read-only.

For #5295 [A11y] Unable to tap snackbar #6513

Merged
merged 1 commit into from
Nov 15, 2019
Merged
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
65 changes: 49 additions & 16 deletions app/src/main/java/org/mozilla/fenix/utils/Undo.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
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

internal const val UNDO_DELAY = 3000L
Expand Down Expand Up @@ -40,29 +44,58 @@ fun CoroutineScope.allowUndo(
// writing a volatile variable.
val requestedUndo = AtomicBoolean(false)

// Launch an indefinite snackbar.
val snackbar = FenixSnackbar
.make(view, FenixSnackbar.LENGTH_INDEFINITE)
.setText(message)
.setAnchorView(anchorView)
.setAction(undoActionTitle) {
requestedUndo.set(true)
fun showUndoDialog() {
val dialogBuilder = AlertDialog.Builder(view.context)
dialogBuilder.setMessage(message).setCancelable(false)
.setPositiveButton(R.string.a11y_dialog_deleted_confirm) { _, _ ->
launch {
operation.invoke()
}
}.setNegativeButton(R.string.a11y_dialog_deleted_undo) { _, _ ->
launch {
onCancel.invoke()
}
}
val alert = dialogBuilder.create()
alert.show()
}

fun showUndoSnackbar() {
val snackbar = FenixSnackbar
.make(view, FenixSnackbar.LENGTH_INDEFINITE)
.setText(message)
.setAnchorView(anchorView)
.setAction(undoActionTitle) {
requestedUndo.set(true)
launch {
onCancel.invoke()
}
}

// If user engages with the snackbar, it'll get automatically dismissed.
snackbar.show()
snackbar.show()

// Wait a bit, and if user didn't request cancellation, proceed with
// requested operation and hide the snackbar.
launch {
delay(UNDO_DELAY)
// Wait a bit, and if user didn't request cancellation, proceed with
// requested operation and hide the snackbar.
launch {
delay(UNDO_DELAY)

if (!requestedUndo.get()) {
snackbar.dismiss()
operation.invoke()
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
}
4 changes: 4 additions & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,10 @@
<string name="snackbar_private_tabs_deleted">Private tabs deleted</string>
<!-- Text for action to undo deleting a tab or collection shown in snackbar -->
<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
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>
Expand Down