Phase 7: 2-step category create/edit flow, scale settings step, alarms on edit - #184
Merged
Conversation
Adds the redesign's only genuinely new table: a category group that owns a colour role and a default input type. Fully additive; no UI changes. - Group entity (table `groups`) + GroupDao; TrackingCategory gains a nullable groupId (no FK: deleting a group unfiles members instead of cascading). MIGRATION_23_24 creates the table and adds the column; existing rows keep groupId NULL and their colorToken, so nothing changes visually after migrating. - Group CRUD, reorder, delete-with-unfile, and assign/unassign methods on TrackingRepository (new nullable groupDao constructor param, wired in GoFloApplication). - Colour inheritance per PLAN.md section 5: new "inherit" colorToken sentinel resolved by TrackingCategory.effectiveColorToken(groups) to the group's colorRole, or neutral surfaceVariant when groupless. Deliberately not a CategoryColor entry so the Phase 1 role picker does not offer it. Existing tokens are untouched (no grey wipe; confirmed with owner against the handover's neutral-by-default). - Migration test (Migration23To24Test): runs the real MIGRATION_23_24 against a real SQLite v23 schema via sqlite-jdbc (test-only dep), routing execSQL through a reflection proxy, and asserts the exact schema Room expects plus data preservation. MigrationTestHelper is unusable here (no instrumented tests, exportSchema = false). - PLAN.md section 7 progress log updated; subsystem map 02 updated for v24; changelog fragment (minor); LESSONS.md entry on JVM-side Room migration testing. Verified: migration SQL executed against a seeded v23 schema in SQLite (PRAGMA output matches the test's expected schema exactly); a11y_check.py and wcag_check.py both clean. Claude-Session: https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg Co-authored-by: Claude <noreply@anthropic.com>
Adds the ~12 stateless, parameterised Compose primitives every later
redesign screen is assembled from, in ui/components/, previews only.
No existing screen is rewired; nothing is removed.
- SectionHeader: uppercase 11sp section label with right-aligned value
- ListCard / ListRow / HairlineDivider: hairline-outlined card of rows
- StepScale: discrete rising tap-steps; exposes to TalkBack as a single
control ("Flow, Medium, 3 of 4") with per-step custom actions
- ChipToggle / ChipRow: tonal-fill + check selection chips (FilterChip)
- ToneHero: tonal hero container, Comfortaa word applied explicitly
- SegmentedToggle: single-choice segmented buttons, optional role tint
- RolePicker: 6 in-theme role pills + fixed-colour track, standalone
(visuals mirrored from the Phase 1 inline picker; ManageCategories
keeps its copy until a later phase rewires it)
- IconPicker: 48dp icon tile grid with radio semantics + display names
- SwitchRow: full-row toggle, Role.Switch + stateDescription, inner
Switch has no click handler
- Timeline / TimelineEntry: timestamped multiple-per-day list with
per-row overflow and an append row
- PrimarySaveBar: sticky 52dp pill with gradient fade
- MetricInput facade stub + MetricConfig/MetricValue value types
(incl. YesNo/TimeOfDay variants ready for Phase 4)
Every primitive accents from a passed-in role Color (tonal container
fills derived via roleContainerTint, lerp toward surface); each carries
light, dark, and 200% font-scale previews through GoFloTheme so the
extended-roles CompositionLocal path is exercised. a11y_check.py and
wcag_check.py both clean. PLAN.md progress log updated; DB stays at 24.
Claude-Session: https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg
Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg Co-authored-by: Claude <noreply@anthropic.com>
Completes the MetricInput facade so it renders every category input type,
and refactors LogCategoryScreen to render through it with behaviour parity:
- CategoryType gains YES_NO ("yes_no") and TIME ("time"). Both store their
readings as plain value-label strings ("Yes"/"No"; 24-hour "HH:mm") in
tracking_log_values per the owner's resolution of PLAN.md §8 decision #3:
no new columns, no migration (DB stays at v24).
- MetricInput: whole-step rating scales (up to 10 steps) render as StepScale;
decimal or wider ranges keep the parity slider including whole-number
stepped behaviour, large readout, scale labels, min/max labels, and the
unset-value hint. numeric_free keeps unit label + placeholder; increment
keeps the never-below-zero counter (decrement disabled at 0); yes_no
renders a role-tinted SegmentedToggle; time renders the new TimeField
primitive (Material time picker, 24h).
- LogCategoryScreen: the inline per-type when is gone; every non-timed input
renders via MetricInput. Timed increment stays screen-driven (per-tap
immediate saves, no Save button) and now renders the Timeline primitive.
Notes 500-char cap, save/update, delete, date selection, edit-existing,
empty-catalog text, and "previously recorded (removed)" chips unchanged.
- LogCategoryViewModel: additive setSelectedValues; yes_no/time flow through
selectedValues, so the existing else-branch save path persists them and
the numeric_free empty-blocks-save / increment <=0-blocks-save rules are
untouched.
- LogPeriodScreen: PinnedCategoryInput gains additive yes_no/time branches
delegating to MetricInput (pre-existing branches untouched); additive
LogPeriodViewModel.setPinnedSingleValue feeds the existing selection-set
save path.
- TrackingCategory.isNumeric now enumerates the numeric types explicitly so
yes_no/time chart as label categories in Stats instead of being fed into
numeric chart math.
- Create flow: the two new types appear automatically in the New Category
type chips; the unit field is now limited to the genuinely numeric types.
- Docs: PLAN.md §7 row + §8 #3 resolution, subsystem map 01 drift note,
LESSONS.md entry on negation-defined classifications, changelog fragment
(minor).
Claude-Session: https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg
Co-authored-by: Claude <noreply@anthropic.com>
The flow slider mapping (1 Spotting / 2 Light / 4 Heavy / else Medium), the flow and symptom fan-out into the tracking system, the pinned-category value rules, and the episode day-number helper move from private members of LogPeriodViewModel into an internal PeriodDaySync object, so the unified day screen (next commit) shares the exact same code instead of a copy that could drift. LogPeriodViewModel delegates to it; behaviour is unchanged. Also widens LogCategoryScreen's metricConfigFor and TimedIncrementTimeline from private to internal for the same reuse. Claude-Session: https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg Co-authored-by: Claude <noreply@anthropic.com>
New LogScreen + LogViewModel compose the Phase 3/4 primitives into one
per-day surface behind the additive route log_day?date={date}:
- Off-period: the first tracked category leads as a ToneHero, flow is not
rendered, and the footer is a quiet Period-started-today row (which flips
the screen into its on-period arrangement before saving).
- On-period: the Flow group (StepScale, stepped slider, or chips per the
category's mode, with the 1 Spotting / 2 Light / 4 Heavy / else Medium
mapping) slots in at the top with the period dates card, pinned
showInLogPeriod categories render in the flow context, and the footer is a
filled status row with End/Undo.
- Between the two states everything is identical: symptoms chips with the
inline Add dialog, tracked metrics organised by group (two or more members
render as one ListCard of rows with the active row's input beneath; a group
of one renders as its own open section), per-entry notes with the 500-char
cap, previously-recorded chips, track-against-time, per-entry delete, and
timed-increment timelines with per-tap saves.
- The title and every metric header open a switch sheet organised by group
and tinted by role: from the title it switches day or jumps to a category;
from a metric header it re-files the entered value under another category
without losing it.
- Saving reuses the period screen's exact sequence via PeriodDaySync
(episode continuation and boundary edits, episode meta, flow/symptom/pinned
fan-out, widget and prediction-reminder refresh); off-period saves write
only categories the user touched, using the category screen's per-type
rules. Remove-day, delete-entire-period, disable-period-logging, and the
unsaved-changes guard are all ported.
The LogPeriod and LogCategory routes stay registered and every existing
entry point still uses them; the only new entry is an opt-in preview row in
the calendar day sheet. Removal is Phase 8.
Claude-Session: https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg
Co-authored-by: Claude <noreply@anthropic.com>
Marks Phase 5 done in PLAN.md with its deviations, records the new screen and the PeriodDaySync extraction in subsystem map 01, adds the minor-bump changelog fragment, and adds a lesson on translating single-entry save blocking into per-entry skip rules on a batch save surface. Claude-Session: https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg Co-authored-by: Claude <noreply@anthropic.com>
CI failed compileDebugKotlin on PR #180: role/selected/contentDescription/ customActions were assigned inside semantics{} blocks as this.role etc. without importing the corresponding androidx.compose.ui.semantics extension properties (importing the Role class does not cover the lowercase role property). Adds the missing imports to IconPicker, ListCard, RolePicker, StepScale, and Timeline, and extends the LESSONS.md shadowing entry with the import requirement. Verified with a semantics-vs-imports sweep over every main-source Kotlin file plus a11y_check.py. Claude-Session: https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg Co-authored-by: Claude <noreply@anthropic.com>
…meField Brings in the phase-3 fix for unresolved semantics extension properties and applies the same fix to TimeField.kt (Phase 4 file, missing the lowercase androidx.compose.ui.semantics.role import), found by sweeping every main-source file with the same checker. Claude-Session: https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg Co-authored-by: Claude <noreply@anthropic.com>
ManageCategoriesScreen becomes the Grouped/Ungrouped management home from the row-4 mock: a SegmentedToggle swaps between role-tinted group cards (colour dot + name + Edit, member rows resolved via effectiveColorToken, inline "Add category to this group") and the neutral ungrouped list, each row carrying an "Add to group" affordance. - Add-to-group sheet: pick a group, jump to pre-filled group creation, or remove from the current group; a "Use the group's colour" switch sets the category's token to the "inherit" sentinel so it adopts and follows the group's role. Past entries are always kept. - Group-centric add-member sheet lists ungrouped categories first, then members of other groups labelled with where they live, plus a New category row that pre-selects the group's default input type and files the category on creation. - Group editor dialog: name, in-theme role via RolePicker (new additive showFixedSection flag hides the hex track: a group's role is never a hex), default input type, member unfiling, move up/down reorder, and delete with a confirmation explaining members are kept. - ManageCategoriesViewModel gains the groups Flow and group CRUD / moveGroup / assign (with adopt-colour) / unassign on the Phase 2 repository API. No DB changes (schema stays v24). - Preserved unchanged: archive/unarchive and delete swipes with system protection, global drag reorder via the toolbar reorder mode, category creation dialog, ManageCategoryValues navigation, tracking modes and quick-log surfaces, archived section. - Help dialog documents groups and the two views; PLAN.md §7 and map 02 updated; changelog fragment (minor); LESSONS.md entry on snapshotting Compose state into locals before async completion callbacks. Claude-Session: https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg Co-authored-by: Claude <noreply@anthropic.com>
…s on edit New CategoryEditScreen + CategoryEditViewModel (route category_edit?categoryId&groupId) replace AddCategoryDialog's role in navigation: - Create step 1: name, IconPicker, RolePicker (6 roles + fixed hex + custom HSV slot), input-type chips (all 6 types), unit for the numeric family, and allow-multiple / log-with-period / track-against-time switch rows. Creating from inside a group pre-selects the group's default input type, files the category on save, and offers a "Use the group's colour" switch that writes the "inherit" sentinel (consistent with the Phase 6 adopt-colour sheets). - Create step 2 (numeric_slider only): min/max range, per-step word labels, allow-decimals; both steps share one route with in-screen step state so the half-built form never crosses navigation. - Edit: the same surface prefilled, plus a Reminders section wired to the existing CustomAlarm/EditAlarm system (rows open EditAlarm, switches toggle scheduling via ReminderScheduler), a "Scale settings" row into step 2, and a danger-zone delete-with-history row (system categories protected). - Owner decision (PLAN.md section 8 item 2): categoryType is "fixed once logged" - editable until the category has a tracking log, then locked with a one-line explanation. Checked live via additive TrackingLogDao. countLogsForCategory / TrackingRepository.hasLogs and re-guarded at save. - ManageCategoryValues keeps values/settings/alarms unchanged; its rename and palette dialog actions are superseded by one Edit action opening the new flow. Superseded dialogs stay in place for Phase 8 removal. DB stays at v24. Changelog fragment (minor), PLAN.md section 7/8 updated, subsystem map 02 drift-noted, LESSONS.md entry added. a11y_check, wcag_check, and the semantics-import sweep are clean. Claude-Session: https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg Co-authored-by: Claude <noreply@anthropic.com>
…gn-phase-4 # Conflicts: # app/src/main/java/com/mapgie/goflo/ui/components/MetricInput.kt # docs/design/logging-redesign/PLAN.md
…gn-phase-5 # Conflicts: # LESSONS.md # app/src/main/java/com/mapgie/goflo/ui/screens/log/LogCategoryScreen.kt # docs/design/logging-redesign/PLAN.md # docs/design/logging-redesign/subsystem-maps/01-logging-screens.md
…gn-phase-6 # Conflicts: # docs/design/logging-redesign/PLAN.md
…gn-phase-7 # Conflicts: # app/src/main/java/com/mapgie/goflo/ui/screens/categories/ManageCategoriesScreen.kt # docs/design/logging-redesign/PLAN.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 7 — category creation & edit (rows 5/6)
Builds the row-5/row-6 create and edit flows on top of Phase 6's "What You Track" home. New
CategoryEditScreen+CategoryEditViewModel(routecategory_edit?categoryId={id}&groupId={id}) is one surface for both create and edit, assembled from the Phase 3 component library (IconPicker,RolePicker,SwitchRow,ListCard/ListRow,SectionHeader,PrimarySaveBar).What changed
Create (2 steps). Step 1 stays short: name, icon, colour (6 in-theme roles, fixed hex swatches, and the custom HSV picker), input-type chips over all 6 types, unit for the numeric family, and allow-multiple / log-with-period / track-against-time switch rows. Step 2 appears only for the Scale type (
numeric_slider): min/max range, per-step word labels, allow-decimals. Both steps live in one route with in-screen step state, so the half-built form never crosses navigation and back from step 2 keeps everything. Every create entry point (FAB, Ungrouped "New category" CTA, group add-member sheet) now navigates here instead of openingAddCategoryDialog. Creating from inside a group pre-selects the group's default input type, files the category on save, and offers a "Use the group's colour" switch (default on) that writes the"inherit"sentinel, extending Phase 6's adopt-colour sheets to creation. Default-type categories still continue to the values screen after creation, exactly as before.Edit. The same surface prefilled, reached from a single Edit action on
ManageCategoryValues(superseding its rename and palette dialogs), plus:ReminderScheduler.scheduleCustomAlarm/cancelCustomAlarm, mirroringCustomAlarmsViewModel); rows open the existingEditAlarmscreen; "+ Add alarm" opensScreen.EditAlarm.newForCategory(categoryId). No parallel alarm machinery. Alarms appear on edit only, never on first creation.Input-type mutability (owner decision, PLAN.md §8 item 2 — resolved).
categoryTypeis "fixed once logged": editable in the edit flow until the category has at least one tracking log, then shown read-only with one plain sentence ("The input type is locked because this category already has logged entries."). Checked live via additiveTrackingLogDao.countLogsForCategory/TrackingRepository.hasLogs, re-guarded inCategoryEditViewModel.save. No value-migration machinery. System categories always keep their type (Flow's chip/slider switch stays onManageCategoryValues).Data: no DB changes; v24 unchanged. Persistence reuses
addCategory/updateCategoryFullSettings/assignCategoryToGroup; the only additions are the count query andhasLogs.Superseded but kept for Phase 8 (now unreferenced, annotated in place):
AddCategoryDialog,EditAppearanceDialog,RenameCategoryDialog.CategoryColorPicker/CategoryIconGridremain referenced byAddCategoryDialog/EditAppearanceDialogonly.FullColorPickerDialogandisCustomColorTokenwere widened tointernaland are reused by the new flow's custom-colour slot;alarmScheduleLabellikewise.Docs: PLAN.md §7 Phase 7 row (done, deviations, type-mutability resolution) and §8 item 2 annotated resolved; subsystem map 02 drift-noted; LESSONS.md gains an entry on gating storage-representation fields on dependent data. Changelog fragment
changelog/unreleased/category-create-edit-redesign.json(minor).Acceptance criteria (guide)
addCategory) — all 6 types (Default kept alongside the mock's 5) wired through the flow by inspection; CI is the build checkscaleLabelsviaencodeScaleLabels), and decimalsCustomAlarmsystem — sameEditAlarmscreen andReminderSchedulerpath as beforedeleteCategoryrepository guard)a11y_check.pygreen (icon/role pickers =Role.RadioButtonvia components; switches =Role.Switch+stateDescriptionviaSwitchRow; content descriptions on icon-only controls;liveRegionon range validation)Feature-preservation checklist (guide)
CustomAlarm/EditAlarmscheduling behaviour unchanged; no duplicate alarm systemManageCategoryValues) still reachable fordefaultcategories — category rows still open it; its values, per-type settings, flow slider toggle, archive/delete menu, and alarms section are untouchedmodeKeycategories (tracking modes) still creatable/editable —ModesScreenuntouched; edit passes the storedmodeKeythroughDeviations
🤖 Generated with Claude Code
https://claude.ai/code/session_01PZJLynVBkgLtehJFXffnfg
Generated by Claude Code