voo_watch_ui 0.4.0 copy "voo_watch_ui: ^0.4.0" to clipboard
voo_watch_ui: ^0.4.0 copied to clipboard

Cross-platform UI DSL for smartwatches. Define your watch UI in Dart and render it identically on Apple Watch (native SwiftUI) and Wear OS (Flutter).

Changelog #

All notable changes to voo_watch_ui will be documented in this file.

0.4.0 - 2026-04-29 #

Added #

  • Closure-form event handlers. WatchView.button(onTap: () => count++), WatchView.toggle(onChanged: (bool v) => ...), etc. — every interactive factory now accepts a Dart closure in addition to the existing string/WatchEventId forms. The closure is auto-registered against a synthetic id, replaced on each render() call, and dispatched when the watch fires the event back. Eliminates most VooWatchUi.instance.onEvent(...) registrations in the common case. Supported signatures: VoidCallback, void Function(bool|int|double|String), void Function(Map<String, Object?>). WatchAlertAction.onTap accepts the same forms (constructor is no longer const — drop the const keyword on call sites if present).
  • Typed icons. New WatchIconData value type pairs an SF Symbol name with a Material code-point so the same call renders correctly on both Apple Watch and Wear OS / phone-side preview. Curated WatchIcons catalog of ~40 common icons. WatchView.icon / chip / iconButton / toast factories now accept Object icon — WatchIconData, Flutter's IconData (auto-resolves SF Symbol via the catalog, falling back to questionmark.circle for uncatalogued icons), or a raw String (legacy SF Symbol passthrough).
  • WatchEventId — typed const wrapper around an event id string. Pair WatchView.button(onTap: AppEvents.refresh) with VooWatchUi.instance.onEvent(AppEvents.refresh, ...) to share one source of truth and let the IDE catch typos via autocomplete / rename / find-usages.
  • WatchUiBootstrap — single wrapper widget that nests WatchUiHotRestartBindingWatchUiHotReloadBindingWatchUiThemeBinding in the correct order. Per-layer flags (hotReload, hotRestart, themeSync) for opt-out. Replaces the three-deep nested form in your MaterialApp.home.
  • package:voo_watch_ui/testing.dart — exports installFakeVooWatch(), resetVooWatch(), and withFakeVooWatch(() async { ... }) so tests no longer have to repeat the VooWatch.debugReset / FakeVooWatchTransport / VooWatch.debugInstall boilerplate by hand.
  • VooWatchUi.dispatchEvent(eventId, payload) and hasHandlerFor(eventId) — public hooks WatchUiPreview uses to route closure-form events through the active callback registry, so preview clicks fire the same handlers a real watch tap would.

Changed #

  • voo_watch_ui:init now also wires the watch target's @main App.swift (preserves the Xcode-generated struct name; conservative about user-modified files — pass --force to overwrite). Setup goes from 5 manual steps to 4 — the README's "Replace App.swift" step is gone.
  • Demo (apps/voo_watch_demo) migrated to closure-form events on the counter and reset/end-run alert flows; uses WatchIcons.heart / fire / WatchIconData for cross-platform icons. Most other events stay on the string-based onEvent API to demonstrate backwards compatibility.
  • WatchAlertAction constructor is no longer const (it accepts the closure/WatchEventId/String onTap forms). String-only call sites still compile — drop const from list literals if present.

0.3.1 - 2026-04-28 #

Added #

  • WatchUiHotReloadBinding — drop-in widget that re-publishes the last watch tree on State.reassemble() so phone-side hot reload pushes edited trees to the paired device even when render(...) is called from initState or an event handler (which don't re-fire on hot reload). Toggle off with enabled: false. Pairs with the existing WatchUiThemeBinding — wrap your home screen in both: WatchUiHotReloadBinding(child: WatchUiThemeBinding(child: HomeScreen())).
  • VooWatchUi.republishOnHotReload() — public API powering the binding above. Clears the dedup cache and re-flushes the most recent tree.

Fixed #

  • Watch theme is now correct on cold start when the phone app hasn't been launched in the current session. The Wear OS Flutter watch (WatchUiTreeListener) now caches the most recently seen theme to SharedPreferences and hydrates from it on init; the Apple Watch SwiftUI watch (WatchUiState) caches to UserDefaults and hydrates in its initializer. Previously the watch would flash indigo defaultDark until the phone app's WatchUiThemeBinding published its first frame.

Changed #

  • VooWatchUi.render now also publishes via updateApplicationContext whenever the theme changes (typically once per app launch and again on dark-mode toggle). This seeds Apple Watch's WCSession.receivedApplicationContext so a watch launched standalone — phone backgrounded or never opened — hydrates the correct brand theme on cold start. Tree-only renders stay on the live sendMessage channel as before. Effective extra IPC cost is roughly one applicationContext write per app launch.
  • WatchUiTreeListener.initialTheme doc clarified: it's the floor used only when both the disk cache and the live channel are empty. Pass a WatchTheme.fromColorScheme(myBrandScheme) so users who install the watch app and open it before ever launching the phone app see brand colors instead of defaultDark.

Migration #

  • The watchOS WatchUiState.swift template emitted by voo_watch_ui:init gained a custom initializer for UserDefaults hydration. Re-run dart run voo_watch_ui:init in your watch target, or hand-merge the private init() and themeCacheKey additions from the published template.

0.3.0 - 2026-04-28 #

Added #

  • WatchUiPreview widget — a drop-in watch-shaped frame around WatchUiFlutterRenderer for hot-reload previews on phone, desktop, or web. Supports Apple Watch and Wear OS round silhouettes via WatchPreviewShape. Replaces the ~25-line ad-hoc preview block that was duplicated across the example and demo apps.
  • Hot-reload preview workflow documentation in the README — run apps/voo_watch_preview with flutter run -d chrome for a sub-second iteration loop on watch UI trees without an iOS Watch target or paired device.

Changed #

  • voo_watch_ui now works on Flutter web. The transitive voo_watch bridge automatically falls back to an in-memory transport when kIsWeb is true, so VooWatchUi.instance.render(...) is a harmless no-op in browser-based previews.
  • Bumped voo_watch constraint to ^0.3.0.

0.2.2 - 2026-04-28 #

Added #

  • example/ app — phone-side demo that builds a WatchView tree, previews it on the phone with the same WatchUiFlutterRenderer that ships on Wear OS, registers onEvent handlers for tap/toggle/slider, and exposes buttons to trigger watch haptics. Required for pub.dev's "Provide documentation" category.

Changed #

  • Declared platforms: ios, android explicitly in pubspec.yaml (previously inferred via the voo_watch import chain).
  • Inlined formatter: page_width: 160 in analysis_options.yaml so pana scores the package under the project's column width.

0.2.1 - 2026-04-27 #

Documentation #

  • Expanded the Apple Watch setup section into a numbered five-step walk- through (add target → scaffold templates → replace App.swift → fix the Xcode build cycle → run), including the --watch-target and --force flags and a table describing what each scaffolded Swift file does.
  • New Troubleshooting section covering the most common pitfalls hit on first run: Xcode's "unable to attach DB" build database corruption, the "NSPOSIXErrorDomain code 2" install error (with the IDE/CLI DerivedData hash-mismatch root cause), the "Awaiting UI…" stall, theme misplacement under MaterialApp, simulator animation lag, and Wear OS pairing requirements.

0.2.0 - 2026-04-27 #

Added #

  • Theme system. WatchTheme (9 semantic colors: primary, onPrimary, surface, onSurface, muted, background, success, warning, danger), WatchTheme.defaultDark, WatchTheme.indigo, WatchTheme.fromColorScheme, and JSON roundtrip. WatchUiUpdate now carries an optional theme that the watch caches; updates that don't change the theme omit it.
  • WatchUiThemeBinding. A StatelessWidget that reads Theme.of(context).colorScheme and pushes a matching WatchTheme to VooWatchUi.instance.theme. Drop it under MaterialApp and the watch follows the phone's brand colors automatically — including dark-mode toggles.
  • Modals. WatchAlert (blocking confirmation with cancel/destructive actions), WatchSheet (modal bottom sheet rendering arbitrary content), WatchToast (transient overlay banner with optional icon/color/position). All declarative — phone owns visibility.
  • Animation primitives. WatchAnimatedScale and WatchAnimatedRotation for state-tracking animation. WatchPulse for trigger-based animation that runs locally on the watch (no IPC round-trip per frame — what you want for tap feedback and success bursts).
  • Haptics. WatchHapticKind enum (click / success / warning / failure / notification / start / stop) and VooWatchUi.instance.haptic(kind) API. Maps to WKInterfaceDevice.play() on watchOS and Flutter's HapticFeedback on Wear OS.
  • WatchSafeArea. Per-edge safe-area handling for the watch's status bar and TabView page-dot insets.
  • Display widgets. WatchAvatar (circular image + initials fallback), WatchBadge (count or dot overlay; auto "99+" cap), WatchChip (pill-shaped tag with optional icon).
  • Input widget. WatchStepper (+/- value editor; native Stepper on watchOS picks up digital crown rotation).
  • Per-instance color overrides on every input primitive: Switch, Slider, Checkbox, Button, IconButton, TextField, Stepper. Themes provide the default; per-widget props override.
  • Progress polish. WatchProgressIndicator now accepts color, size, and strokeWidth.
  • WatchUiTreeListener.initialTheme. Wear OS apps can now set a startup theme so the watch shows brand colors from frame 1, before the phone connects.

Changed #

  • The Flutter renderer is now theme-aware: Card, Text, Button, Icon, Divider, IconButton, TextField, Switch, Slider, Checkbox, Progress, Stepper, and the page-dot indicator all read defaults from the current theme.
  • The SwiftUI renderer mirrors the same theme-aware defaults via @Environment(\.watchUiTheme).
  • _PageView (SwiftUI) now pins each page to WKInterfaceDevice.screenBounds to escape watchOS TabView's design-imposed margins. List titles no longer truncate to "…".
  • _Button (SwiftUI) now uses Button { } label: { WatchUiButtonLabel } with .buttonStyle(.plain) so an outer Expanded actually fills the row.
  • Optimistic-UI pattern for live inputs (Slider, Toggle, Checkbox, Stepper, TextField): @State mirrors the prop and resyncs via onChange(of:) — prevents the IPC round-trip lag on each tap.

Fixed #

  • _LiveSlider no longer ping-pongs between the phone-driven and local values (loose-equality syncback guard).
  • Cards span the full watch width (the long-running TabView inset bug).
  • WatchAnimatedOpacity is no longer the only motion primitive.

0.1.0 - 2026-04-26 #

Added #

  • Initial release of the cross-platform Dart watch UI DSL.
  • 30 widget primitives covering layout (Column, Row, Stack, Wrap, Center, Padding, SizedBox, Expanded, Flexible, Spacer), display (Text, Image, Icon, Container, Divider, Card), input (Button, IconButton, TextField, Switch, Slider, Checkbox), lists (ListView, ScrollView), motion (GestureDetector, AnimatedOpacity), feedback (ProgressIndicator), navigation (Page, PageView), and a Custom escape hatch.
  • VooWatchUi facade with render(), event registry, and tap callbacks dispatched through the voo_watch bridge.
  • Pure-Dart Flutter renderer (used on Wear OS and in tests).
  • SwiftUI renderer template set in tools/watchos_renderer/ (copied into a watchOS target by dart run voo_watch_ui:init).
  • WatchUiUpdate and WatchUiEvent message types built on voo_watch.
  • FakeWatchUi test harness exported via package:voo_watch_ui/testing.dart.
2
likes
160
points
295
downloads

Documentation

API reference

Publisher

verified publishervoostack.com

Weekly Downloads

Cross-platform UI DSL for smartwatches. Define your watch UI in Dart and render it identically on Apple Watch (native SwiftUI) and Wear OS (Flutter).

Homepage
Repository (GitHub)
View/report issues

Topics

#flutter #watch #watchos #wear-os #sdui

License

MIT (license)

Dependencies

args, flutter, meta, path, shared_preferences, voo_watch, voo_wear

More

Packages that depend on voo_watch_ui