Skip to content

UI/UX: Unify feedback with Material snackbars and retain long errors - #6227

Open
eliotcougar wants to merge 6 commits into
2dust:masterfrom
eliotcougar:feat/snackbar-feedback
Open

eliotcougar wants to merge 6 commits into
2dust:masterfrom
eliotcougar:feat/snackbar-feedback

Conversation

@eliotcougar

@eliotcougar eliotcougar commented Sep 13, 2026

Copy link
Copy Markdown
Contributor

Motivation

Follow-up to the earlier background-feedback extraction, #6204 (currently a draft), and the maintainer's suggestion to use one foreground message mechanism.

This PR chooses Material snackbars for foreground feedback and regular notifications for background feedback. It carries forward and refines #6204's delivery work; #6204 does not need to be merged first.

Fixes #6053.

That report was closed as not planned and describes error messages disappearing before they can be read, with longer text not fully visible. The solution here is a dismissible, scrollable snackbar, not a new modal screen.

User-visible behavior

  • Normal information and short errors use Material's short snackbar duration, including its accessibility-adjusted timeout.
  • Errors exceeding 120 Unicode code points, or containing a line break, remain until dismissed. They have a localized Close action and vertically scrollable text; the action remains outside the scrolling text.
  • Snackbars remain centered at the bottom, with symmetric side clearance for the main screen's start/stop button. The layout respects safe drawing and keyboard insets and bounds long text to half the available height.
  • Unread messages survive rotation and navigation, including feedback emitted just before an editor finishes.
  • When the app backgrounds, unread feedback transfers to permission-aware regular notifications. Routine messages replace the preceding routine message and expire after ten seconds on Android 8+. Long errors have independent notification identities and no automatic expiry.
  • Notification taps open/reuse the main screen. Expanded notification text may still be truncated by Android; there is no separate error-viewer activity.
  • New foreground feedback clears stale routine notification feedback, without deleting undismissed long errors.

Implementation

  • Replace the custom toast-like renderer and platform Toast fallback with Material 3 SnackbarHost/Snackbar. Material owns queue serialization, dismissal, timing and accessibility semantics; there are no custom focus moves or manual accessibility announcements.
  • Use a small shared UserMessage model for the foreground/background dismissal policy. Keep existing toast, toastSuccess and toastError entry-point names to avoid unrelated caller-renaming churn; they no longer create Android Toasts.
  • Give unread presentation work process lifetime through ProcessLifecycleOwner, so activity replacement does not discard messages. Only one resumed host displays the shared queue. Tracked message jobs exist to transfer unread work when the process backgrounds.
  • Deliver terminal service feedback through acknowledged, package-scoped broadcasts. The foreground process acknowledges ownership; state-only observers do not consume presentation responsibility. Unhandled feedback falls back to a notification.
  • Emit successful-stop feedback after the native shutdown callback, not when stopping is requested. A small tested feedback-state helper excludes internal reload shutdowns and failed-start cleanup and preserves a pending stop across reload completion. This is not a redesign of native service lifecycle.
  • Respect notification permissions and existing channel settings, with a localized Other notifications channel title. Update completed-stop wording in all nine maintained locale catalogs.
  • Classify actual failure callers as errors, remove unused toast resource entries and the obsolete ToastCompat license listing, and correct stale comments/log wording. No native library or submodule changes.

Validation

  • Focused message-policy/delivery tests passed; all 96 JVM tests passed with zero failures/errors.
  • :app:compilePlaystoreDebugKotlin and x86_64 :app:assemblePlaystoreDebug passed.
  • API 37 x86_64 emulator: normal/short-error expiry, long-error retention and Close, queueing, rotation, acknowledged terminal feedback, background replacement/expiry, independent retained errors and foreground stale-message clearing passed.
  • Resource/reference checks, ToastCompat dependency inspection and git diff --check passed.

Replace the toast-shaped overlay and Android Toast fallback with standard snackbars and permission-aware background notifications. Retain the existing helper API to avoid unrelated caller churn.

Keep multiline errors and errors over 120 Unicode characters visible until Close is activated. Queue later messages, retain the queue across activity recreation, and allow long text to scroll. Routine feedback keeps the standard accessibility-adjusted timeout.

Use replaceable, expiring notifications for routine background feedback and independently dismissible notifications for long errors. A resumed host acknowledges terminal service feedback; a background state subscriber does not suppress delivery. Localize the channel and completed-stop text in all nine maintained locales.

Validation: 87 JVM tests passed; Play Store debug x86_64 assembled. Emulator checks cover timing, dismissal, rotation, foreground/background delivery, permission denial, and real lab proxy-only start/restart/stop. Lint retains four pre-existing NewApi errors outside the changed files.
Reserve the main bottom bar button width and edge inset symmetrically, retaining the existing safe-area centering and maximum snackbar width. This leaves the service control unobstructed without moving it or changing message behavior.

Validation: 87 Play Store debug unit tests, Kotlin compilation and x86_64 debug assembly passed. Emulator checks confirmed centering and non-overlap in portrait and landscape, plus Close activation across light/dark themes, dynamic colors and both column layouts.
Own the Material snackbar queue at process lifetime. Only the resumed host renders it; activity replacement preserves unread messages, and actual backgrounding transfers them to permission-aware notifications. All foreground delivery paths now use the same coordinator instead of an activity ViewModel and separate teardown fallback.

Give persistent error notifications distinct immutable intents to a private, scrollable full-text destination. Preserve the complete message through SavedStateHandle and provide Close and normal back navigation without introducing new translation keys.

Emit Service stopped from the existing native completion callback, not when asynchronous shutdown is requested. Keep internal reloads and failed-start cleanup silent through a small daemon-side feedback state. Remove the now-unused reload parameter without changing native shutdown or connection-test cancellation ownership.

Validation: focused and complete JVM tests, Kotlin compilation and x86_64 debug assembly passed. Emulator reproductions now pass for editor completion, background queue delivery, rotation, persistent errors and distinct notification targets. Real lab-profile proxy and VPN start/stop feedback also passed. Full lint retains four pre-existing NewApi errors outside these changes.
Open retained error notifications in an isolated notification-only task, using direct immutable PendingIntents instead of rebuilding the main activity stack. Routine notifications reuse Main; error identities, full-text restoration and explicit dismissal remain intact.

Classify malformed custom-config diagnostics and invalid proxy-chain member lists as errors so long messages require dismissal while short messages retain their timeout. Simplify nullable-tag posting, compute immutable dismissal policy once, and avoid redundant blank checks and unused Close-label lookups.

Make successful startup or reload arm feedback only from the empty state, preserving an outstanding stop request. Add focused regressions for stop/reload interleaving and recovery after a failed reload without expanding the service lifecycle model.

Validation: 96 JVM tests, Kotlin compilation and x86_64 debug assembly passed. Emulator checks cover unsaved-editor preservation, distinct error targets, normal Main reuse, real validation callers, rotation/scrolling/dismissal, message handoff, background policy, and normal VPN/proxy-only start-stop feedback. Full lint retains four pre-existing NewApi errors outside this patch; native handover/stop race injection and root-mode runtime were not run.
Route all feedback notification taps to MainActivity. Remove UserMessageActivity, its ViewModel and manifest registration, and the per-error navigation payload and task setup. Notification text may be truncated by Android, as requested.

Keep expanded notification text, independent retained-error identities, existing expiry and permission policy, and foreground snackbar behavior unchanged.

Validation: all 96 JVM tests, Kotlin compilation and x86_64 debug assembly passed. Emulator checks confirmed the activity is absent, retained error and routine notification taps reuse Main, and tapped notifications dismiss correctly. Native inputs were unchanged; no Android test directory was introduced.
Replace stale toast comments and parser-log wording, and remove the commented-out stop message without changing completed-stop delivery. Remove the obsolete ToastCompat license listing after confirming no resolved runtime dependency remains; retain the shared Apache license text.

Delete seven unreferenced resource keys from all nine locale catalogs, leaving every surviving resource unchanged. Route nine permission, file-picker, QR-decoding, certificate-fetch, asset-download and subscription-import failure sites through toastError. Preserve informational prompts, progress, summaries and the existing compatibility API.

Validation: focused message/delivery tests and all 96 JVM tests passed, along with Kotlin compilation and x86_64 debug assembly. Foreground/background emulator smoke checks passed for timeout, dismissal, rotation, queued feedback, notification retention and terminal delivery. Catalog/reference checks passed; no native inputs or Android test sources changed. Individual operation-failure scenarios and TalkBack speech were not rerun.
@eliotcougar

Copy link
Copy Markdown
Contributor Author

I didn't rename toast, toastError, and toastSuccess.
toast and toastSuccess are currently identical and don't have a distinct style.

These issues can be addressed if you want.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

错误提示显示时间过短且无法完全显示,可能无法达到预期效果

1 participant