Skip to content

fix(feedback): deliver toasts via the Navigator overlay so they show without a Scaffold - #106

Merged
anilcancakir merged 6 commits into
masterfrom
feat/feedback-overlay-toast
Jul 20, 2026
Merged

fix(feedback): deliver toasts via the Navigator overlay so they show without a Scaffold#106
anilcancakir merged 6 commits into
masterfrom
feat/feedback-overlay-toast

Conversation

@anilcancakir

Copy link
Copy Markdown
Contributor

What

Magic.error / Magic.success / MagicFeedback.info routed through ScaffoldMessenger.of(context).showSnackBar, which asserts _scaffolds.isNotEmpty when no Material Scaffold hosts the view. In a Wind-built screen (no Scaffold) that assertion escaped the caller's own try/catch and stalled the flow (e.g. a monitor create's error toast threw before the create could return).

Fix (2 commits)

  1. fix(feedback): the snackbar path degrades to a logged warning when no messenger is available, instead of throwing.
  2. feat(feedback): toast delivery moves off ScaffoldMessenger onto the Navigator overlay, read from navigatorKey.currentState.overlay (NOT Overlay.maybeOf, which sits above that overlay), as a single non-interactive auto-dismissing bottom entry.

The Magic.error/success/toast API surface is unchanged; only the delivery path is. Toasts now show in Wind-only views where they were previously invisible.

Notes

  • Single file: lib/src/ui/magic_feedback.dart.
  • CHANGELOG updated under [Unreleased] > Fixed.
  • Surfaced driving Wind-only uptizm screens via fluttersdk_dusk.

…hosts it

MagicFeedback.showSnackbar called ScaffoldMessenger.of(context).showSnackBar
directly. The whole magic UI layer is Wind-based (WDiv/WText), so a view
registers no Material Scaffold; showSnackBar then trips its
`_scaffolds.isNotEmpty` assertion and throws. Because Magic.error/success run
that path, the throw escaped the caller's own try/catch: e.g. the monitor
AI-analyze step called Magic.error on a failed probe, the toast threw before
analyze could return null, and the create view span forever on "Analyzing..."
with no way back.

Route both snackbar call sites through _showSnackBarSafely, which degrades a
Scaffold-less host to a Log.warning instead of throwing. A snackbar is
best-effort and the condition it reports is already logged by the caller, so it
must never crash the calling flow. Live-verified: with the relay down the
AI-analyze step now falls back to the input step and logs the warning instead
of stalling.
… without a Scaffold

Follow-up to the crash guard: snackbars/toasts were routed through
ScaffoldMessenger, which needs a Material Scaffold the Wind-based magic UI
never registers, so every Magic.error/success/toast was invisible (and used to
crash). Render them into the router's Navigator overlay instead
(navigatorKey.currentState.overlay, read from the state rather than an ancestor
lookup on the navigator context, which sits above that overlay). A single
non-interactive (IgnorePointer) bottom toast fades in, auto-dismisses on a
timer, and is replaced by the next one. Degrades to a logged warning when no
overlay is available. The default snackbar content now carries its own chrome
(padding/rounding/shadow) since the SnackBar wrapper is gone.

Live-verified: Magic.error now shows a visible red bottom toast in a
Scaffold-less Wind view; full magic suite 1252 green.
Copilot AI review requested due to automatic review settings July 17, 2026 23:24

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR updates Magic’s UI feedback delivery so toasts/snackbars can render in Wind-only (Scaffold-less) views by using the Navigator’s overlay instead of relying on ScaffoldMessenger, preventing _scaffolds.isNotEmpty assertion failures and making feedback visible across more UI surfaces.

Changes:

  • Route MagicFeedback.showSnackbar() and MagicFeedback.toast() through a new overlay-based toast renderer (navigatorKey.currentState?.overlay).
  • Add a single-active-toast mechanism with an auto-dismiss timer to mimic prior “replace current snackbar” behavior.
  • Update [Unreleased] changelog notes to document the feedback delivery change.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
lib/src/ui/magic_feedback.dart Replaces SnackBar/ScaffoldMessenger delivery with an overlay-based, auto-dismissing toast entry.
CHANGELOG.md Documents the Scaffold-less toast visibility fix under [Unreleased].

Comment thread lib/src/ui/magic_feedback.dart
Comment thread lib/src/ui/magic_feedback.dart Outdated
Comment thread CHANGELOG.md Outdated
@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 92.00000% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
lib/src/ui/magic_feedback.dart 92.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

Address PR review: guard _dismissToast on OverlayEntry.mounted so a late timer
never calls remove() on a detached entry; add a widget test covering the
Scaffold-less overlay render, replace-previous, and clean auto-dismiss; fix a
docblock typo; correct the CHANGELOG to describe the final overlay-only path.
_dismissToast removed the entry but never disposed it, leaking the
entry OverlayEntry state notifier. Dispose after our own remove (which
clears the overlay link dispose asserts on); the already-detached branch
is left to the overlay teardown that owns it.
@anilcancakir
anilcancakir merged commit aa1d93f into master Jul 20, 2026
4 checks passed
@anilcancakir
anilcancakir deleted the feat/feedback-overlay-toast branch July 20, 2026 09:11
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.

2 participants