Skip to content

Restructure into a monorepo: standalone LiquidToasts Swift package + Flutter plugin - #9

Merged
rehmatsg merged 13 commits into
mainfrom
claude/liquid-toasts-monorepo-plan-mk3yud
Sep 1, 2026
Merged

Restructure into a monorepo: standalone LiquidToasts Swift package + Flutter plugin#9
rehmatsg merged 13 commits into
mainfrom
claude/liquid-toasts-monorepo-plan-mk3yud

Conversation

@rehmatsg

@rehmatsg rehmatsg commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

Restructures the repo so the SwiftUI renderer is a standalone Swift package installable straight from GitHub in any iOS app, with the Flutter plugin living beside it and consuming it by relative path. The wire protocol is unchanged (protocolVersion stays 1); the Dart API is unchanged except for two deliberate removals listed under breaking changes. Executed per the approved plan in docs/monorepo-plan.md.

Layout

├── Package.swift                  # root manifest — SwiftPM needs it at the repo root for git-URL installs
├── liquid-toasts-swift/
│   └── Sources/LiquidToasts/      # the Flutter-free core (manager, views, scheduler, models, native facade)
└── liquid_toasts/                 # the Flutter plugin (basename doubles as its SwiftPM identity —
    ├── lib/ test/ android/ example/       the old checkout-rename caveat is gone)
    └── ios/liquid_toasts/         # bridge only: channel plugin + wire decoding, depends on the core via path

What changed, phase by phase (one commit each)

  1. Decouple the core from Flutter — wire decoding moved out of Models.swift into bridge-side WireModels.swift; the models gained plain memberwise initializers whose defaults mirror the wire defaults exactly. Flutter is imported only by the plugin and the wire decoders.
  2. Public Swift API — typed dismiss reasons and events (raw values are the wire strings), multi-listener event fanout on ToastManager, a curated public surface, and the native LiquidToast facade: show/semantic variants/loading, live handles with patch updates and dismissal callbacks/await, an async promise that returns the value and rethrows, native id minting that coexists with Dart-minted ids on one stack, and a SemanticDefaults table kept in lockstep with lib/src/semantic_defaults.dart (cross-reference comments in both files). Event dictionaries reaching Dart were verified key-for-key identical.
  3. The restructure — 163 git renames (history follows), the two manifests, podspec deleted (SwiftPM-only per the plan's decisions), URLs moved to SimplifyJobs, new umbrella/native READMEs, CLAUDE.md rewritten.
  4. CI + releasesci.yml (Dart analyze/test, iOS-simulator build of the root package, example app in SwiftPM mode, Android unit tests) and release.yml (fires on v* tags, reuses ci.yml, guards tag == pubspec version, publishes a GitHub Release from the CHANGELOG section). Version bumped to 0.8.0 with a CHANGELOG entry.

Follow-up commits on this branch: fixes from the first CI run and review round (scheme name, dismissAll re-entrancy snapshot, non-finite duration guard, plugin listener teardown on engine detach), and the two API removals below.

Breaking changes (all in the 0.8.0 CHANGELOG with migration pointers)

  • CocoaPods dropped: iOS builds require flutter config --enable-swift-package-manager.
  • Install is now a pubspec git dependency with path: liquid_toasts and ref: vX.Y.Z; pub.dev publishing is deferred (would need a vendoring step — documented in the plan).
  • useDynamicIslandOrigin removed entirely — from Toast, every toast.* method, ToastHandle.update, the wire, the Android/iOS decoders, the native facade, and the geometry snapshot's supportsDynamicIslandOrigin key. No renderer on either platform ever consulted it. toast.queryGeometry() still reports the cutout itself.
  • The deprecated legacy LiquidToasts facade, LoadingToast, and showLoading are deleted (were marked "Removed in 1.0"); every member has a one-line toast.* equivalent.

Needs verification on macOS (no Apple toolchain in this environment)

CI covers the builds (the swift, example, and android jobs compile everything, and the example job exercises the plugin-through-SwiftPM symlink path — the plan's one flagged structural risk, now passing). Before tagging v0.8.0, still worth a human pass:

  1. A quick run of the example app plus the simulator probes (bg_probe_demo.dart, render_probe_demo.dart) to confirm runtime behavior is unchanged.
  2. A scratch native app installing the branch by git URL to smoke-test the LiquidToast facade.

🤖 Generated with Claude Code

https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq

claude added 7 commits August 30, 2026 20:17
… plugin)

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq
…e, org URL

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq
Wire decoding moves out of Models.swift into bridge-side WireModels.swift;
the models gain plain memberwise initializers whose defaults mirror the wire
defaults exactly. Image bytes already crossed the plugin boundary as Data.
Flutter is now imported only by LiquidToastsPlugin.swift and WireModels.swift.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq
Typed events and dismiss reasons (raw values are the wire strings), listener
fanout on ToastManager (bridge and native facade coexist on one stack), a
curated public surface for the future core module, and the native facade:
LiquidToast.show/success/error/warning/info/loading, LiquidToastHandle with
patch updates and dismissal callbacks/await, async promise that returns the
value and rethrows, native id minting, and a SemanticDefaults table kept in
lockstep with lib/src/semantic_defaults.dart. Flutter wire behavior is
unchanged (event maps verified key-for-key; flushed events never cross).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq
…er plugin

liquid-toasts-swift/Sources/LiquidToasts is the Flutter-free core, built by a
root Package.swift (SwiftPM requires the manifest at the repo root for git-URL
installs). The Flutter plugin moves to liquid_toasts/ (basename doubles as its
SwiftPM identity, ending the checkout-rename caveat) and its ios package keeps
only the bridge (plugin + wire decoding), consuming the core by relative path.
The podspec is deleted (SwiftPM-only). URLs point at SimplifyJobs; new umbrella
and native READMEs; CLAUDE.md rewritten for the layout.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq
ci.yml runs dart analyze/test, an iOS-simulator build of the root LiquidToasts
package, the example app in SwiftPM mode, and the plugin's Android unit tests.
release.yml fires on v* tags: it reuses ci.yml via workflow_call, guards that
the tag matches the pubspec version, and publishes a GitHub Release whose body
is that version's CHANGELOG section plus a pinned install block. Version bumps
to 0.8.0 with a CHANGELOG entry covering the restructure and the two breaking
install changes (CocoaPods dropped; git dependency with path).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 176 files

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread liquid_toasts/ios/liquid_toasts/Package.swift
Comment thread liquid-toasts-swift/Sources/LiquidToasts/LiquidToastCenter.swift
Comment thread liquid-toasts-swift/Sources/LiquidToasts/ToastManager.swift
Comment thread liquid-toasts-swift/Sources/LiquidToasts/Models.swift
Comment thread liquid-toasts-swift/Sources/LiquidToasts/Models.swift Outdated
Comment thread liquid-toasts-swift/Sources/LiquidToasts/Models.swift
Comment thread liquid-toasts-swift/Sources/LiquidToasts/LiquidToastConfiguration.swift Outdated
Comment thread liquid-toasts-swift/Sources/LiquidToasts/LiquidToast.swift
- CI: xcodebuild's auto-generated scheme is named after the package
  (liquid-toasts), not the product; fix the swift job and add a -list step.
- LiquidToastCenter.dismissAll: snapshot registry ids before the sweep so a
  toast shown from an onDismissed callback mid-sweep isn't completed out from
  under its live view.
- ToastDuration: treat non-finite or un-representable intervals as persistent
  instead of trapping in the Int conversion.
- LiquidToastsPlugin: unregister the event listener in detachFromEngine so
  re-registration doesn't stack dead listeners on the app-lifetime manager.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 5 files (changes from recent commits).

Reply with feedback, questions, or to request a fix.

Re-trigger cubic

Comment thread CLAUDE.md
claude added 3 commits August 30, 2026 21:52
The useDynamicIslandOrigin flag threaded through every layer (Dart model and
facades, wire, Android and iOS decoders, Swift facade) but no renderer on any
platform ever consulted it — it is gone entirely, including the geometry
snapshot's supportsDynamicIslandOrigin key. Both wire decoders defaulted when
the key was absent, so protocolVersion stays 1; queryGeometry still reports
the cutout itself.

The long-deprecated legacy LiquidToasts facade, LoadingToast, and showLoading
are deleted (every member has a one-line toast.* equivalent, mapped in the
CHANGELOG), along with legacy_facade_test.dart.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq
The wrap decision now has a synchronous UIKit pre-measurement
(ToastPreMeasurement, mirroring the off-screen probe's reference-width math)
that seeds ToastView's initial state, so a tall toast's first layout is
already at final height and the sibling push is one continuous spring.
Previously the toast entered at single-line height and grew a frame later
when the probe landed — an unanimated re-layout that snapped every visible
sibling down before the spring caught up. The probe still confirms after
layout; a disagreement (or a later morph across the wrap boundary) animates
instead of applying instantly, so the didMeasure gate is gone.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq

@cubic-dev-ai cubic-dev-ai Bot 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.

All reported issues were addressed across 4 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Re-trigger cubic

Comment thread liquid-toasts-swift/Sources/LiquidToasts/ToastView.swift
claude added 2 commits August 30, 2026 22:54
A wide action label could skew the pre-measured wrap decision (it used the
flat 72pt estimate) and shift the toast's height once the live button
reported its width. ToastPreMeasurement now measures the label at the
button's real font + capsule insets (routed through ToastMetrics so the
lockstep is structural) and seeds both actionWidth and the wrap decision,
so the probe's first pass agrees with the entrance layout even for
action toasts.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq
With both CGSize members implicit, the literal resolves against CGFloat and
Double candidates and fails to compile; spell the type out.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014CcBgqiJJfA28A8BKzdUWq
@rehmatsg
rehmatsg merged commit 111ae61 into main Sep 1, 2026
5 checks passed
@rehmatsg
rehmatsg deleted the claude/liquid-toasts-monorepo-plan-mk3yud branch September 1, 2026 21:46
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