morphui 0.1.3 copy "morphui: ^0.1.3" to clipboard
morphui: ^0.1.3 copied to clipboard

Automatic UI adaptation for Flutter. Dark mode, accessibility, and behavioral layout adaptation — zero configuration.

Changelog #

0.1.3 #

Theme palette — persistent local cache #

  • GeneratedTheme.toJson() — new serialization method mirroring fromJson. Enables Hive persistence of AI-generated palettes.
  • Hive-backed palette cache in MorphProvider — successful /flutter/theme/generate responses are persisted to cml_config (same box as the license cache). On subsequent app launches the adapted palette is applied immediately with zero network latency. TTL: 48 h. Cache key includes the raw background hex + target brightness — changing your base colors auto-invalidates.

Fatigue detection — new APIs #

  • FatigueAdaptiveForm.onReset — optional callback invoked when the user taps the "Start over" button on the fatigue banner. The SDK resets its own score first, then calls this so host apps can clear form state.
  • context.morphFatigueDetector — new BuildContext extension exposing the live FatigueDetector directly. Use it to feed recordKeystroke() / recordTapError() from anywhere without threading the detector manually.
  • FatigueDetector.debugForceHighFatigue() — dev/test helper that bypasses the cold-start guard and immediately forces a high fatigue score so the banner and simplified form are reachable in demos without a real session.
  • Banner UI refresh: icon added, "Start over" label, surfaceContainerHighest background, rounded corners.

Interruption recovery — new APIs #

  • morphSetCheckoutMultiStepContext — new extension method for multi-step checkouts (shipping → payment → review). Writes a fresh snapshot per step under the same workflowId; the engine fetches the full chain on resume via InterruptionRecovery.pendingChain. Accepts strategy and ttl overrides.
  • morphSetProductContext — now accepts optional strategy (RecoveryStrategy.confirm / .auto / .silent) and ttl parameters.

Suggestion overlay — improvements #

  • MorphSuggestionOverlay.onSuggestionRefused — new callback fired when the user dismisses a card. Receives the MorphSuggestion object so host apps can react per suggestion type (e.g. reset checkout state when a recovery card is refused).
  • Post-resume check — the overlay now listens to AppLifecycleState and fires a card check 1 500 ms after the app resumes, so interruption-recovery cards surface immediately without waiting for the next scheduled tick.
  • Keyboard guard — uses MediaQuery.viewInsets.bottom instead of FocusManager.hasFocus; fixes a silent block on Android where hasFocus stayed true after returning from background even after the IME was dismissed.
  • Bug fix: rootNavigator: true in suggestion navigation — resolves a routing dead-end on iOS when the suggestion context originates from the overlay (which sits above the router's navigator in the tree).
  • Removed secondary confirm dialog on zone-reorder suggestions — the card tap is already confirmation; the showDialog path caused a non-resolving Future on iOS.

Dev mode config (MorphConfig) #

  • devMinPauseSeconds — overrides the 30-second minimum background pause required for recovery to trigger. Set to 5 in demo builds; omit (null) in production.
  • devEnableAllFeatures — treats all plan capability checks as Business tier, unlocking fatigue detection, grip detection, battery-aware UI, etc. regardless of the actual license key. Never set true in production.

0.1.2 #

Plan gating — never leak Morph branding to end users (behavioural change) #

  • PlanGate no longer auto-renders a Morph-branded upsell card when the resolved plan is insufficient. The default fallback is now SizedBox.shrink() — gated features silently disappear instead. End users of integrating apps no longer see "Upgrade to Morph Pro" prompts when YOUR Morph subscription lapses; YOU receive renewal emails instead.
  • Internal _UpgradeCard is now exposed as the public MorphUpsellCard widget. Pass it explicitly via PlanGate.fallback only on YOUR admin / dev surfaces — never on end-user screens.
  • context.requireMorphPro() / context.requireMorphAgency() no longer auto-show a dialog. The new contract is onAllowed (sufficient plan) and onDenied (insufficient — wire to your own UI, or to showDialog(builder: (_) => MorphUpgradeDialog(...)) on YOUR admin surface).
  • The onUpgrade parameter on requireMorphPro/Agency is replaced by onDenied. Existing call sites still compile — onUpgrade was never required — but devs that relied on the auto-dialog need to pass onDenied: () => showDialog(...) explicitly.

Interruption recovery — production-ready #

  • Pause bucketing. Pauses are now classified into quick (30s–2min), real (2min–10min) and abandonment (>10min) buckets via InterruptionBucket. The recovery card adapts its title, tone, and confidence per bucket — abandonment recoveries surface with more cautious copy.
  • Robust persistence. The active context is now written to Hive on every declareContext call (debounced 1s) instead of only on paused. An app crash between context declaration and lifecycle pause no longer loses the snapshot.
  • Recovery strategies. Each snapshot can declare a RecoveryStrategy.auto (silent restore, no card — for safe values), RecoveryStrategy.confirm (default, card before restore — for stakes-sensitive flows), or RecoveryStrategy.silent (analytics-only).
  • Multi-step workflow chains. Snapshots can declare a workflowId + workflowStep + workflowTotalSteps. On resume the engine fetches the entire chain and exposes it via InterruptionRecovery.pendingChain, so a host app can restore "step 1 → step 4" of a KYC instead of just the last step.
  • Per-context TTL. RecoverySnapshot now has a ttl field; expired snapshots are silently dropped on resume. Sensible defaults baked in via kRecoveryDefaultTtl — checkout 30 min, transfer 2 min, KYC 24 h, generic 1 h. Devs can override per call.
  • Local learning. New recordOutcome(bucket, RecoveryOutcome.accepted | rejected | ignored) API tracks per-bucket acceptance. After 5 samples in a bucket, the engine suppresses suggestions there if the rejection rate exceeds 70% — the SDK respects users who consistently dismiss recoveries. Stays on-device, never transmitted.

GPS context — production-ready #

  • Hysteresis on the speed→mode transitions. Walking→cycling kicks in at 7 km/h, but cycling→walking only at 5 km/h. A user steady at 7 km/h no longer flickers the UI between the two modes on every fix.
  • New tunnel-mode behaviour. Updates with accuracy > 50m no longer immediately drop the user back to unknown — the adapter keeps emitting the last good context for 30 seconds. Going through a tunnel or under a bridge holds the previous mode instead of popping the UI back to a default.
  • Accelerometer-aware fallback. GpsContextAdapter.start() now subscribes to the accelerometer and detects sustained train-like vibration. When GPS reports stationary but the accelerometer shows ≥5 seconds of high-variance motion, the emitted context is upgraded to vehicle — useful in metros and trains where GPS loses lock for minutes at a time.
  • The accuracy-gate (drop fixes with >50m error) was already shipped in earlier versions but is now explicitly documented in the README.

Fatigue detection — production-ready #

  • New continuous score stream — FatigueDetector.scoreStream emits a 0..100 value so UIs can interpolate smoothly instead of snapping between three buckets. The legacy bucketed stream is kept for backward compatibility.
  • New FatigueAdaptiveForm(adaptation: FatigueAdaptation.smooth) (default) — field scale interpolates continuously from 1.00 to 1.30, banner fades in past score 40. Pass FatigueAdaptation.stepped to keep the old three-step behaviour.
  • Per-user baseline. After 3 completed sessions the detector grades the user against their own typical accuracy + typing speed instead of universal thresholds. A 8% miss rate is "fatigued" for a 2%-baseline user, "normal" for an 8%-baseline user — universal thresholds got both wrong.
  • Auto-reset after 5 minutes paused. The next resume rolls the buffers so a user who put the phone down and came back doesn't carry the previous session's fatigue.
  • Cold-start guard. The first 30 seconds of the day's first session are excluded from scoring — stiff fingers in the morning aren't fatigue.
  • Post-resume retry suppression. For 30 seconds after returning from background, error counters don't accumulate — coming back after a notification doesn't penalise the user.
  • New typed error API: recordTapError, recordTypingError, recordNavigationError. Each carries its own weight in the score (5%, 5%, 15%). The legacy recordRetry is now @Deprecated but still works.
  • FatigueDetector.startSession() and resetFatigue() are now Future<void> (they reload the persisted baseline). Existing void-returning call sites should wrap with unawaited(...) — handled internally for MorphProvider / FatigueAdaptiveForm.

Battery — production-ready #

  • BatteryAdapter now records every foreground session (start/end level, duration, was-charging flag). Aggregated stats are exposed via BatteryAdapter.getSessionStats(lookback: ...) so devs can credibly answer "how much battery does my app burn per minute?".
  • Charge-start events are timestamped per session and fed to a new ChargePatternPredictor. When the user is approaching their typical charge window (3+ events at the same hour over the last 7 days, day-of-week-weighted) and the device isn't already plugged in, the adapter pre-shifts to BatteryMode.medium to extend the runway.
  • New BatteryAwareTheme(adaptiveMode: BatteryAdaptiveMode.suggestion) mode — instead of imposing the dimmed scaffold the moment battery drops, the theme stays untouched until the user accepts the "Battery saver mode" suggestion. The default remains imposed for backward compatibility.
  • New BatteryAwareTheme(isOLED: bool?) override + automatic detection via DeviceCapabilities.isLikelyOLED. Pure-black scaffolds only apply when the screen is actually OLED — LCD devices fall back to dim grey, since pure black saves no power on LCD.
  • Charging-aware behaviour (level rule short-circuits to normal when plugged in) is now explicitly documented in the README — was already shipped, just invisible.

Grip detection — persistence + customisation #

  • GripDetector now reads the previously detected hand from BehaviorDB on start() and uses it as a prior. The UI lands on the right alignment immediately on the second session, and a matching live signal locks in after 5 samples instead of 10. A signal that contradicts the prior still goes through the full 10-sample window — switching hands mid-session works as before.
  • GripDetector constructor now takes an optional persistPreference flag (default true). Set it to false for ephemeral detection without storage.
  • GripDetector.start() is now Future<void> so it can await the prior read. Existing unawaited(start()) callers keep working.
  • GripAdaptiveLayout now exposes transitionDuration (default 300ms) and transitionCurve (default easeOutCubic) so devs can tune the feel of the side-switch animation.

Tooling + dependencies #

  • Added a minimal example/ so pana scores the package as having a runnable demo.
  • Bumped battery_plus (4.x → 7.x), sensors_plus (4.x → 7.x), package_info_plus (>=4 <10 → ^10) to the latest majors.
  • Fixed dartdoc HTML interpretation warning on Map<zoneId, orderIndex>.

0.1.1 #

  • Renamed package from morph_flutter to morphui to align with morphui.dev.
  • License switched to Apache 2.0.
  • Internal API base URL is now resolved at compile time — clients no longer pass any URL; SDK maintainers can override via --dart-define=CHAMELEON_API_BASE_URL=....

0.1.0 #

Initial public release.

Added #

  • MorphProvider — root widget that bootstraps theme detection, behavior storage, and zone scoring.
  • MorphZone / ReorderableColumn — wrappers that track interactions and reorder children based on usage.
  • AI-adapted color schemes via the Morph SaaS (/api/flutter/theme/generate) — automatic dark/light/high-contrast palettes generated from the host app's base ThemeData.
  • Behavior storage backed by Hive — visibility, taps, sequences, zoom events.
  • BuildContext extensions: context.morph, context.morphTheme, context.morphPalette, context.zoneOrder.
  • Origin-binding via appId payload — backend rejects calls from packages not declared in the license's allowed_packages.
  • MorphAnalyticsConfig — opt-in behavior reporting with configurable upload interval and minimum-interaction floor.
  • MorphFeatures.fintech() preset — interruption recovery, battery-aware UI, fatigue detection, GPS context (gated by license tier).
1
likes
70
points
216
downloads

Documentation

API reference

Publisher

verified publishermorphui.dev

Weekly Downloads

Automatic UI adaptation for Flutter. Dark mode, accessibility, and behavioral layout adaptation — zero configuration.

Homepage
Repository (GitHub)
View/report issues

License

Apache-2.0 (license)

Dependencies

battery_plus, crypto, flutter, hive, hive_flutter, http, package_info_plus, sensors_plus, shared_preferences, visibility_detector

More

Packages that depend on morphui