Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
3.8 KiB
Data Model: M3 Expressive Design System Adoption
Date: 2025-07-18 | Branch: 20260513-160000-m3-expressive-adoption
Overview
This feature is primarily a UI/styling upgrade with minimal data model impact. The only new persistent state is the swipe-action discoverability hint preference.
New Entities
SwipeHintPreference
Location: core/datastore (user preferences)
| Field | Type | Default | Description |
|---|---|---|---|
hasCompletedSwipeAction |
Boolean |
false |
Permanently dismisses swipe hint after first successful swipe action |
Storage: DataStore UserPreferences proto or preferences file (existing infrastructure).
State Transitions:
false → true (on first successful swipe-to-action completion)
One-way flag. Never resets to false (permanent dismissal).
SwipeHintSessionState (transient)
Location: In-memory, ViewModel-scoped
| Field | Type | Default | Description |
|---|---|---|---|
hasShownHintThisSession |
Boolean |
false |
Prevents repeated hint animation within same process lifecycle |
Lifecycle: Resets on process death. Within a session, hint shows once per list screen visit until hasCompletedSwipeAction becomes true.
Modified Entities
AppTypography (Type.kt)
Current State: val AppTypography = Typography() — empty default
Target State: Full expressive typescale definition:
| Property | Value Source |
|---|---|
displayLarge |
Standard M3 default (auto-emphasized by expressive theme) |
displayMedium |
Standard M3 default |
displaySmall |
Standard M3 default |
headlineLarge |
Standard M3 default |
headlineMedium |
Standard M3 default |
headlineSmall |
Standard M3 default |
titleLarge |
Standard M3 default |
titleMedium |
Standard M3 default |
titleSmall |
Standard M3 default |
bodyLarge |
fontSize = 16.sp minimum (design standards §5) |
bodyMedium |
fontSize = 16.sp minimum (design standards §5) |
bodySmall |
Standard M3 default |
labelLarge |
Standard M3 default |
labelMedium |
Standard M3 default |
labelSmall |
Standard M3 default |
Note: Emphasized variants (displayLargeEmphasized, titleMediumEmphasized, etc.) are auto-generated by MaterialExpressiveTheme based on the standard scale. No manual definition needed.
Component State Models
SwipeToRevealState
Location: core/ui/component/SwipeToRevealBox.kt
| Field | Type | Description |
|---|---|---|
anchoredDraggableState |
AnchoredDraggableState<SwipeAnchor> |
Manages drag position and anchoring |
currentAnchor |
SwipeAnchor |
Current snapped position |
SwipeAnchor Enum:
enum class SwipeAnchor {
Start, // Resting position (0 offset)
RevealEnd, // Left-swipe reveals end actions
RevealStart, // Right-swipe reveals start actions
}
Relationships
UserPreferences (DataStore)
└── hasCompletedSwipeAction: Boolean
NodeListScreen
├── uses SwipeToRevealBox (per item)
│ └── owns AnchoredDraggableState
└── reads hasCompletedSwipeAction (via ViewModel)
MessageListScreen
├── uses SwipeToRevealBox (per item)
│ └── owns AnchoredDraggableState
└── reads hasCompletedSwipeAction (via ViewModel)
Validation Rules
| Rule | Constraint |
|---|---|
bodyLarge.fontSize |
>= 16.sp (design standards §5 minimum) |
bodyMedium.fontSize |
>= 16.sp (design standards §5 minimum) |
| Touch target minimum | 44.dp × 44.dp on all interactive elements (design standards accessibility) |
| Swipe threshold | Action reveals at ≥ 56.dp horizontal drag (comfortable thumb distance) |
| Swipe velocity threshold | Fling detected at ≥ 400.dp/s (standard Material swipe velocity) |