morphui 0.1.2
morphui: ^0.1.2 copied to clipboard
Automatic UI adaptation for Flutter. Dark mode, accessibility, and behavioral layout adaptation — zero configuration.
Changelog #
0.1.2 #
Plan gating — never leak Morph branding to end users (behavioural change) #
PlanGateno longer auto-renders a Morph-branded upsell card when the resolved plan is insufficient. The default fallback is nowSizedBox.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
_UpgradeCardis now exposed as the publicMorphUpsellCardwidget. Pass it explicitly viaPlanGate.fallbackonly on YOUR admin / dev surfaces — never on end-user screens. context.requireMorphPro()/context.requireMorphAgency()no longer auto-show a dialog. The new contract isonAllowed(sufficient plan) andonDenied(insufficient — wire to your own UI, or toshowDialog(builder: (_) => MorphUpgradeDialog(...))on YOUR admin surface).- The
onUpgradeparameter onrequireMorphPro/Agencyis replaced byonDenied. Existing call sites still compile —onUpgradewas never required — but devs that relied on the auto-dialog need to passonDenied: () => showDialog(...)explicitly.
Interruption recovery — production-ready #
- Pause bucketing. Pauses are now classified into
quick(30s–2min),real(2min–10min) andabandonment(>10min) buckets viaInterruptionBucket. 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
declareContextcall (debounced 1s) instead of only onpaused. 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), orRecoveryStrategy.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 viaInterruptionRecovery.pendingChain, so a host app can restore "step 1 → step 4" of a KYC instead of just the last step. - Per-context TTL.
RecoverySnapshotnow has attlfield; expired snapshots are silently dropped on resume. Sensible defaults baked in viakRecoveryDefaultTtl— 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 > 50mno longer immediately drop the user back tounknown— 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 reportsstationarybut the accelerometer shows ≥5 seconds of high-variance motion, the emitted context is upgraded tovehicle— 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.scoreStreamemits a 0..100 value so UIs can interpolate smoothly instead of snapping between three buckets. The legacy bucketedstreamis 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. PassFatigueAdaptation.steppedto 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 legacyrecordRetryis now@Deprecatedbut still works. FatigueDetector.startSession()andresetFatigue()are nowFuture<void>(they reload the persisted baseline). Existingvoid-returning call sites should wrap withunawaited(...)— handled internally forMorphProvider/FatigueAdaptiveForm.
Battery — production-ready #
BatteryAdapternow records every foreground session (start/end level, duration, was-charging flag). Aggregated stats are exposed viaBatteryAdapter.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 toBatteryMode.mediumto 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 remainsimposedfor backward compatibility. - New
BatteryAwareTheme(isOLED: bool?)override + automatic detection viaDeviceCapabilities.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
normalwhen plugged in) is now explicitly documented in the README — was already shipped, just invisible.
Grip detection — persistence + customisation #
GripDetectornow reads the previously detected hand fromBehaviorDBonstart()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.GripDetectorconstructor now takes an optionalpersistPreferenceflag (defaulttrue). Set it tofalsefor ephemeral detection without storage.GripDetector.start()is nowFuture<void>so it canawaitthe prior read. Existingunawaited(start())callers keep working.GripAdaptiveLayoutnow exposestransitionDuration(default 300ms) andtransitionCurve(defaulteaseOutCubic) 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_fluttertomorphuito align withmorphui.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 baseThemeData. - Behavior storage backed by Hive — visibility, taps, sequences, zoom events.
BuildContextextensions:context.morph,context.morphTheme,context.morphPalette,context.zoneOrder.- Origin-binding via
appIdpayload — backend rejects calls from packages not declared in the license'sallowed_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).