Skip to content

Feature/m3 and related mods#65

Merged
NateEaton merged 8 commits intomainfrom
feature/M3-and-related-mods
Feb 18, 2026
Merged

Feature/m3 and related mods#65
NateEaton merged 8 commits intomainfrom
feature/M3-and-related-mods

Conversation

@NateEaton
Copy link
Copy Markdown
Owner

Summary

Complete M3/UX refactor (Phases 0–4, 6) of the MyDeck Android app, aligning with Material Design 3 guidelines and Readeck's UX model. This is a large, multi-phase body of work that modernizes navigation architecture, component usage, label management, filtering, and visual polish. Phase 5, tablet layout, will be implemented in a separate branch.

Phase 0: Foundation & Design Tokens

  • Created Dimens.kt with centralized spacing, icon size, and corner radius tokens
  • Added material3-adaptive and material3-window-size-class dependencies for future tablet layout work

Phase 1: Navigation Architecture Refactor

  • Lifted ModalNavigationDrawer and navigation chrome out of BookmarkListScreen into a new app-level AppShell composable
  • NavHost is now a child of AppShell — drawer state persists across destinations
  • Eliminated white flash between screen transitions (persistent themed Surface wrapping NavHost)
  • Extracted AppDrawerContent as a shared composable

Phase 2: M3 Component Remediation

  • Replaced custom Row layouts in Settings screens with M3 ListItem
  • Redesigned Mosaic cards: gradient-over-image overlay with title + action icons (favorite, archive, view original, delete)
  • Added tappable label chips to Grid and Compact card variants
  • Separated Sepia from the Theme enum into an independent boolean preference — Sepia now applies whenever the effective theme is light (Light mode or System Default resolving to light)
  • Inline SingleChoiceSegmentedButtonRow for theme selection (Light/Dark/System)
  • Drawer typography and divider refinements matching Google Settings patterns
  • Swapped Find in Article (now direct icon) and Bookmark Detail (now in overflow) positions in reading view TopAppBar
  • Reading view header width now honors user's text width setting

Phase 3: Labels — Cross-Cutting Selection Mode

  • Replaced the labels "pseudo-screen" with a LabelsBottomSheet (searchable label list with counts)
  • Labels mode is now cross-cutting: shows ALL bookmarks with a given label regardless of archive/favorite status
  • Tapping a label chip on any card enters label mode for that label
  • Fixed DAO label filter queries: case-sensitive + exact-match ("AI" no longer matches "email")
  • Sort and layout controls converted to dropdown menus across all list views
  • Removed viewingLabelsList from codebase entirely

Phase 4: Unified Filtering System

  • Phase 4a: New drawer items (Articles, Videos, Pictures) as preset filter configurations; filter icon (funnel) replacing search bar; FilterBottomSheet with search, type chips, progress chips, tri-state boolean fields, date pickers, and text fields
  • Phase 4b: Extended filter fields (title, author, site, label-in-filter, dates, is-loaded, with-labels, with-errors); FilterBar summary chips below TopAppBar; expanded DAO query builder supporting 15+ filter parameters
  • DrawerPreset enum and FilterFormState data class replace the old FilterState

Phase 6: Polish & Transitions

  • Navigation transitions: slideInHorizontally/slideOutHorizontally + fadeIn/fadeOut at 300ms
  • Haptic feedback on bookmark delete, favorite, and archive actions
  • Shimmer loading placeholders for bookmark card images
  • Empty state screens updated to M3 pattern (48dp icon + titleMedium headline)
  • Edge-to-edge already implemented via enableEdgeToEdge()

Test plan

  • All existing routes navigate correctly (drawer items, deep links, share intents)
  • Drawer opens/closes, state persists across destinations, no white flash
  • Mosaic cards show gradient overlay with title and action icons
  • Grid cards show label chips; Compact cards show all labels as chips
  • Theme selection (Light/Dark/System) works with inline segmented buttons
  • Sepia applies when effective theme is light (both Light mode and System Default in light)
  • Labels bottom sheet opens from drawer and from label chip taps
  • Label mode shows cross-cutting bookmarks, sort/layout dropdowns work
  • Label filter is case-sensitive and exact-match
  • Filter bottom sheet opens from funnel icon, all field types functional
  • FilterBar chips appear for active non-default filters, each individually dismissable
  • New drawer presets (Articles, Videos, Pictures) filter correctly
  • Navigation transitions animate smoothly
  • Haptic feedback fires on delete, favorite, archive
  • All 10 locale string files have new strings

🤖 Generated with Claude Code

NateEaton and others added 8 commits February 16, 2026 13:53
- Create Dimens.kt with centralized design tokens (spacing, icons, corner radius)
- Add Material3 adaptive and window-size-class library dependencies
- Prepare foundation for Phase 1 navigation refactoring and tablet layout support

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
Move ModalNavigationDrawer and DrawerState out of BookmarkListScreen
into a new AppShell composable that wraps the NavHost. This is a
structural-only refactor — no ViewModel logic, route definitions, or
visual behavior changed.

- New AppShell owns drawer + themed Surface (eliminates white flash)
- New AppDrawerContent extracts drawer items (functionally identical)
- BookmarkListScreen becomes pure content (no drawer wrapping)
- Navigation events handled in AppShell for drawer close coordination
- Drawer gestures scoped to BookmarkListScreen via gesturesEnabled

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Replace custom Row layouts in Settings screens with ListItem
- Redesign BookmarkCard for all variants (Mosaic, Grid, Compact):
  - Mosaic: gradient overlay with title + action icons, no label chips
  - Grid: tappable label chips, no Open in Browser
  - Compact: all labels as chips, no Open in Browser
- Standardize drawer header typography and dividers (REV 2d, 2e)
- Add segmented button theme selector (Light/Dark/System) in UiSettings
- Separate Sepia into an independent boolean preference (REV 2f):
  - Remove Theme.SEPIA from enum; migrate existing Sepia users
  - Sepia now applies whenever effective theme is light (Light or System)
  - Sepia toggle always visible regardless of selected theme mode
- Fix reading view title width to honor text width setting (REV 2c):
  - fillMaxWidth(0.9f) for Wide, fillMaxWidth(0.75f) for Narrow
- Swap Find in Article and Bookmark Detail in reading view top bar (REV 2g):
  - Find in Article promoted to direct icon button (article + reader mode only)
  - Bookmark Detail moved to overflow menu between Read/Unread and Delete
- Update M3 Implementation Roadmap with all Phase 2 completion status
- Add Material Design 3 Compliance Review reference doc

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Fix DAO label filter: use JSON-quoted LIKE pattern and COLLATE BINARY
  to prevent substring false positives (e.g. "ai" matching "email")
- Cross-cutting label mode: ignore archive/favorite status filters when
  viewing by label so all matching bookmarks are shown
- Label mode TopAppBar: decorative label icon + name in title, overflow
  menu with Rename/Delete label, no search icon
- Fix label dialogs: rename button text (OK → Rename), delete dialog
  uses confirmation question with Cancel/Delete buttons
- Clear label filter and return to My List after deleting current label
- Sort icon: SwapVert (up/down arrows) with RadioButton indicators
- Layout toggle: icon dynamically reflects current layout mode
- Add LabelsBottomSheet composable for label browsing and management
- Add string resources (rename, delete, delete_label_confirm_message)
  to all 10 locale files

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add DrawerPreset enum, FilterFormState, and ProgressFilter domain models
- Expand BookmarkDao with getFilteredBookmarkListItems supporting multi-type,
  progress, and full-text search across title/labels/siteName/authors
- Add observeFilteredBookmarkListItems to repository layer
- Replace FilterState with DrawerPreset + FilterFormState in ViewModel;
  label mode and filter mode remain independent
- Add Articles, Videos, Pictures drawer items with bookmark counts
- Replace TopAppBar search bar with FilterList (funnel) icon
- Add FilterBottomSheet with search, type chips, progress chips, and
  tri-state segmented buttons for isFavorite and isArchived
- Enter key in search field triggers apply; empty results show message
- String resources added for all 10 supported locales

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…hase 4b: Extended Filter System Completion

Completes the unified filtering system started in Phase 4a by adding
the remaining filter fields and FilterBar summary component:

- FilterBottomSheet: added title, author, site, label (picker via
  LabelsBottomSheet), from/to date (DatePickerDialog), is-loaded,
  with-labels, and with-errors fields to the filter form
- FilterBottomSheet: tri-state boolean fields (is-favorite, is-archived,
  is-loaded, with-labels, with-errors) implemented via CompactTriStateRow
- FilterBottomSheet: initial sheet height set to half-screen
  (skipPartiallyExpanded = false) so text fields are immediately
  accessible; user can drag to full height or hit enter to apply
- FilterBar: persistent summary bar below TopAppBar showing active
  non-default filters as dismissible InputChip elements
- DAO: observeFilteredBookmarkListItems() expanded to support all 15
  filter parameters including multi-type, date range, progress range,
  content state, and full-text search across title/authors/siteName

## Test Suite Fixes (Phases 0–4b regression cleanup)

Several refactors across Phases 2–4a left tests out of sync with
production code. All issues identified and resolved:

BookmarkListViewModelTest:
- Replaced all observeBookmarkListItems() mocks (7-param, old API) with
  observeFilteredBookmarkListItems() (15-param) to match the ViewModel
  refactored in Phase 4a
- Updated FilterState/filterState references → FilterFormState/filterFormState
  (Phase 4a renamed the filter state model)
- Removed 3 search tests (onSearchQueryChange, onClearSearch,
  searchBookmarkListItems) that referenced methods removed when search
  was folded into FilterFormState.search in Phase 4a
- Updated onClickLabel/onRenameLabel tests to use activeLabel property
  (Phase 3 replaced the old filterState.label approach)

BookmarkDetailViewModelTest:
- Added missing sepiaEnabledFlow mock to @before setup; this StateFlow
  was added to SettingsDataStore during Phase 2 Sepia independence work
  but the test setup was not updated, causing all 17 tests to fail at
  ViewModel construction

## Documentation

- docs/M3-and-Related-Features-Impl-Roadmap.md: added Section H
  documenting the test coverage gaps identified during Phases 0–4b,
  what was fixed, what remains (observeAllBookmarkCounts,
  observeAllLabelsWithCounts, renameLabel, deleteLabel,
  observeFilteredBookmarkListItems repository tests), and a 4–6 hour
  implementation plan for the next test coverage session
- Screen transitions: slide + fade at 300ms on all NavHost routes in AppShell
- Shimmer loading: animated horizontal gradient shown while bookmark images load (Mosaic and Grid cards)
- Empty states: M3 pattern with 48dp icon + titleMedium headline; context-appropriate icons (Bookmarks, CloudOff, SearchOff)
- Haptic feedback: LongPress feedback on archive, delete, and favorite bookmark actions

Edge-to-edge was already implemented via enableEdgeToEdge() in MainActivity.

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@NateEaton NateEaton merged commit 4313faf into main Feb 18, 2026
3 checks passed
@NateEaton NateEaton deleted the feature/M3-and-related-mods branch February 20, 2026 16:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant