Skip to content

Refactor and enhance timeline UI and settings screens across platforms#75

Closed
ohmzi wants to merge 94 commits into
masterfrom
develop
Closed

Refactor and enhance timeline UI and settings screens across platforms#75
ohmzi wants to merge 94 commits into
masterfrom
develop

Conversation

@ohmzi
Copy link
Copy Markdown
Owner

@ohmzi ohmzi commented May 22, 2026

No description provided.

…eline screens.

This update introduces a dynamic top inset for the first item in the first section of the timeline, providing a smoother visual transition ("elastic clearance") as the screen title collapses.

- **Timeline UI Improvements**:
    - Implement `firstPinnedRowElasticTopInset` in `TodoListScreen` and `CompletedScreen` to calculate dynamic padding based on `titleCollapseProgress`.
    - Apply this inset specifically to the first item of the first section when certain view modes (Overdue, Scheduled, or specific "earlier" priority groups) are active.
    - Update `ForEach` loops in both screens to use enumerated arrays to identify the first item (`itemIndex == 0`) for padding application.

- **Metrics & Constants**:
    - Add `firstPinnedRowElasticClearance` (34pt), `firstPinnedRowElasticStart` (0.42), and `firstPinnedRowElasticEnd` (1.0) to `TodoTimelineMetrics` to control the animation threshold and distance.
This update refactors the elastic clearance logic used in `CompletedScreen` and `TodoListScreen` to improve visual consistency during scroll interactions. It ensures that pinned headers and the first items in sections respect collapse progress metrics, while also introducing a custom button style for the timeline top bar.

- **Elastic Layout Improvements**:
    - Rename `firstPinnedRowElastic` constants to `firstPinnedElastic` in `TodoTimelineMetrics` to reflect broader usage across headers and rows.
    - Implement `firstPinnedHeaderElasticTopInset` in both `CompletedScreen` and `TodoListScreen` to apply dynamic top padding to pinned section headers based on scroll progress.
    - Refactor row clearance into a reusable `firstPinnedElasticClearance` helper function.
    - Update `shouldApplyFirstPinnedElasticClearance` in `TodoListScreen` to include the "Today" view mode and specific section IDs ("earlier").

- **UI & Components**:
    - Introduce `TimelineTopBarButtonStyle`, a custom `ButtonStyle` that replaces `TdayPressButtonStyle` for top bar actions, featuring refined ripple effects, scale transforms, and dynamic shadows based on the button's fill state.
    - Update `minimalTimelineRow` in `TodoListScreen` to use an enumerated `ForEach` to correctly identify the first item in a section for applying elastic offsets.

- **Refactoring**:
    - Consolidate logic for calculating top insets for pinned elements to reduce duplication and improve maintainability of the timeline's "sticky" behavior.
…reen.

This change introduces a dynamic top inset for the mode tabs that responds to the calendar's scroll progress, ensuring smoother visual transitions as the title collapses.

- **Animation & Metrics**:
    - Add `modeTabsElasticClearance`, `modeTabsElasticStart`, and `modeTabsElasticEnd` constants to `CalendarTitleHandoff` to define the elastic animation range.
    - Implement `modeTabsElasticTopInset` computed property to calculate the dynamic offset based on `titleCollapseProgress`.
- **UI Integration**: Update the `CalendarModeTabs` list row in `CalendarScreen.swift` to apply the calculated elastic top padding.
This change improves the visual feedback and touch behavior for date cells within the `CalendarScreen` by implementing a bounded ripple effect and ensuring proper clipping.

- **UI & Interaction**:
    - Update `CalendarDayCell` to use a bounded `ripple` indication with a fixed radius of 28.dp.
    - Explicitly clip the cell to its defined `cellShape` to ensure the click interaction and ripple are contained within the cell boundaries.
    - Implement `MutableInteractionSource` for the cell's clickable modifier.
…s on iOS and Android.

This update replaces custom-built tab implementations with platform-standard components—`Picker` on iOS and `SegmentedButton` on Android. This change simplifies the UI logic while maintaining a consistent visual identity across both platforms.

- **iOS (SwiftUI)**:
    - Replace the custom `HStack` and `Button` layout in `CalendarViewModeTabs` with a native `Picker` using the `.segmented` picker style.
    - Add an `accentColor` parameter to `CalendarViewModeTabs` to drive the picker's tint.
    - Implement a local `Binding` to bridge the picker’s selection state with the existing `onSelect` callback.

- **Android (Compose)**:
    - Replace the custom `Card` and `Row` implementation with Material 3 `SingleChoiceSegmentedButtonRow` and `SegmentedButton`.
    - Define a custom color scheme for the segmented buttons using `CalendarAccentPurple` for active states and standard surface colors for inactive states.
    - Simplify the layout logic by using `SegmentedButtonDefaults.itemShape` and removing manual padding and background management.
This update simplifies the layout logic for the `CalendarScreen` by removing elastic inset calculations for the mode tabs and standardizing the title row height.

- **Layout & Metrics**:
    - Replace `expandedTitleHeight` with a local `titleRowHeight` constant (mapped to `TodoTimelineMetrics.titleCollapseDistance`) for the calendar header.
    - Remove `modeTabsElasticTopInset` logic, including its associated progress calculation and constants (`modeTabsElasticStart`, `modeTabsElasticEnd`, and `modeTabsElasticClearance`).
    - Set the top inset of the task mode tabs to a static `0`, removing the dynamic shifting behavior during scroll.
- **UI Consistency**: Ensure the header title frame explicitly uses the new `titleRowHeight` for both minimum and maximum height constraints.
…for the Android Compose client.

This update replaces the standard Material 3 `SingleChoiceSegmentedButtonRow` with a custom-built animated selector and adjusts the layout spacing and dimensions of the calendar navigation cards for a more polished look.

- **Calendar View Mode Tabs**:
    - Implement a custom `CalendarViewModeTabs` using a sliding background selector with `animateDpAsState`.
    - Add tactile feedback using scale animations and custom ripple effects on selection.
    - Enhance visual styling with a semi-transparent `surfaceVariant` background, custom shadows, and `CalendarAccentPurple` highlights.
    - Replace the `ExperimentalMaterial3Api` segmented buttons with a manual `Row` and `selectableGroup` implementation.

- **Mini-Calendar UI Refinement**:
    - Adjust `RoundedCornerShape` values across calendar cards from 28.dp to 24.dp.
    - Standardize card heights and increase vertical spacing/padding for better visual balance.
    - Update `CalendarDayItem` shape and height to match the new layout constraints.
    - Add explicit height constraints to navigation rows and animated content containers to prevent layout jumping during transitions.
…and iOS platforms.

This update introduces a custom segmented control for calendar view modes on iOS, enhances the visual feedback of the selection UI on Android, and refactors timeline header elasticity to improve list scrolling behavior.

- **iOS Calendar & UI**:
    - Implement `ThickSegmentedControl`, a custom `UISegmentedControl` subclass with a fixed 52pt height for improved touch targets.
    - Replace the standard SwiftUI `Picker` with a `UIViewRepresentable` implementation of the new thick control.
    - Add `tint` support to `TimelineTopBarAction` and `TimelineTopBarButton` to allow accent-colored header actions.
    - Apply the calendar accent color to the "Jump to Today" button.

- **Android Calendar UI**:
    - Enhance `CalendarViewModeSelector` with sophisticated press animations, including scaling effects and dynamic alpha adjustments for surface and accent layers.
    - Implement a "press halo" background effect for unselected segments when pressed.
    - Integrate haptic feedback (`CLOCK_TICK`) when switching between calendar modes.
    - Update the "Jump to Today" top bar button to support accent-colored styling with a dedicated border and tint.

- **Task Timeline Refinement**:
    - Remove elastic top insets from pinned section headers in `TodoListScreen` and `CompletedScreen`, applying the clearance solely to the first row of the section.
    - Rename elastic metrics from `firstPinnedElastic*` to `firstPinnedRowElastic*` to more accurately reflect their application to list items rather than headers.
    - Simplify `EdgeInsets` logic in timeline lists to use static offsets for non-primary sections.
…the iOS client.

This update restores the system swipe-to-back gesture when using custom navigation configurations and improves the visual consistency of the todo list interface, particularly for the "List" view mode.

- **Navigation**:
    - Implement `NavigationInteractivePopGestureConfigurator` to re-enable the interactive pop gesture (swipe-to-back) even when the default back button is hidden or customized.
    - Add `.navigationInteractivePopGesture()` view extension to simplify gesture attachment.

- **UI & Components**:
    - Enhance `TimelineTopBarButton` with a new `.outlined` chrome style featuring a subtle border.
    - Update `TimelineTopBarAction` to support optional circular chrome, used for the settings button in list view.
    - Update the "List" mode icon from `slider.horizontal.3` to `ellipsis`.

- **Todo List Logic**:
    - Refactor `TodoListScreen` to treat `.list` mode as a minimal timeline mode, improving layout consistency with `.scheduled` and `.priority` views.
    - Align `todoTimelineSections` for `.list` mode with the standard future timeline builder to ensure consistent section grouping and sorting.
    - Update todo row metadata in `.list` mode to explicitly display "Overdue" status when applicable.
This update applies the `.navigationInteractivePopGesture()` modifier to the main navigation stack in `AppRootView.swift`, ensuring that users can use the standard edge-swipe gesture to navigate back even when custom navigation configurations are present.
…discovery.

This update improves the consistency of the custom back gesture by introducing more robust navigation controller lookup and addressing timing issues during view transitions.

- **Gesture Handling & Reliability**:
    - Update `scheduleGestureUpdate` to perform multiple state applications with incremental delays (0ms, 50ms, and 200ms) to ensure the gesture state is correctly applied after layout transitions.
    - Trigger gesture updates in `viewDidAppear` to handle cases where the view re-enters the hierarchy.
    - Set `cancelsTouchesInView` to true on the `interactivePopGestureRecognizer` to prevent touch conflicts.
    - Implement `shouldRecognizeSimultaneouslyWith` to allow the interactive pop gesture to operate alongside other gesture recognizers.

- **Navigation Controller Discovery**:
    - Add a recursive extension `nearestNavigationControllerInHierarchy()` to `UIViewController` to better locate the active navigation stack.
    - Refactor discovery logic to traverse the entire window hierarchy, including child and presented view controllers, ensuring the correct `UINavigationController` is targeted even in complex nested layouts.
…tUI client.

This update replaces the standard navigation bar with a custom-designed header to align with the application's visual style. The new header features stylized "Cancel" and "Submit" buttons with a capsule-shaped geometry and refined typography.

- **Header Implementation**:
    - Create `CreateTaskSheetHeader` to replace the default navigation title and toolbar.
    - Implement `CreateTaskSheetHeaderButton` using a `Capsule` shape, custom border stroke, and `tdayRounded` typography.
    - Add `CreateTaskSheetHeaderButtonStyle` to handle press interactions with scale and opacity animations.

- **UI Refactoring**:
    - Wrap the `Form` and the new header in a `VStack` within `CreateTaskSheet`.
    - Hide the standard navigation bar using `.toolbar(.hidden, for: .navigationBar)`.
    - Adjust padding and layout constraints to ensure the header remains fixed at the top of the sheet.
    - Update the submit button logic to display "Saving..." during the asynchronous submission process.
…ents.

This update replaces hardcoded layout values with centralized constants for the calendar period card components, ensuring visual consistency across platforms and simplifying future layout adjustments.

- **iOS (SwiftUI)**:
    - Introduce `CalendarPeriodCardMetrics` to define shared spacing, height, and padding values.
    - Standardize the pager height at 78pt for both week and day views.
    - Update `CalendarPeriodCard` and `CalendarDayCard` to use the new metric constants.
- **Android (Compose)**:
    - Introduce `CalendarPeriodCardPageHeight` (78.dp) and `CalendarPeriodCardBottomPadding` (18.dp) constants.
    - Standardize the height of the calendar pager across the `CalendarPeriodCard` and `DayPager` components.
    - Adjust the bottom padding of the day view to match the week view's layout.
…e calendar's visual consistency across both Android and iOS platforms.

- **iOS UI/UX Enhancements**:
    - Redesign `CreateTaskSheet` and `ListSettingsSheet` headers, replacing text-based "Cancel" and "Save" buttons with circular icon buttons (xmark/checkmark) featuring colored strokes and custom press styles.
    - Update sheet titles from "Create Task" to "New task" for brevity and increased font weight/size.
    - Implement a custom `ListSettingsSheetHeader` to standardize the appearance of list configuration screens.
    - Refine accent colors for destructive and affirmative actions across various action sheets.

- **Android Calendar Refinement**:
    - Introduce a comprehensive set of design tokens for the `CalendarScreen` to manage dimensions, paddings, and typography consistently.
    - Redesign the mini-calendar month grid: cells now feature a circular background for the selected date/today and a more compact layout for task indicators.
    - Update navigation buttons with specific dimensions and active/pressed state background colors.
    - Adjust weekday headers and day cell typography for improved readability and alignment.

- **Cross-Platform Consistency**:
    - Align header heights and horizontal paddings in calendar period cards across both iOS and Android.
    - Standardize task count summary styling and date range formatting in calendar views.
…o unify the visual style, improve spacing, and enhance "today" highlighting.

- **Unified Styling & Colors**:
    - Introduce a dedicated "today" tint color (Blue #509AE6) for both platforms to distinguish current day from selection (Purple).
    - Update day cell backgrounds, borders, and text colors to use subtler opacities and thicker strokes for active states.
    - Synchronize typography across both platforms, notably increasing the calendar header title size to 21sp/pt.

- **Android (Compose) Enhancements**:
    - Wrap the calendar card in a `Box` with consistent shadow, clipping, and `AnimatedContent` size transformations to prevent layout jumps during view mode transitions.
    - Refactor `CalendarMonthDateCell` and `CalendarPeriodDayCell` with updated dimensions (42dp height) and rounded rectangle shapes (16dp).
    - Implement a custom interaction state for month cells, replacing the standard ripple with a bespoke background/border animation.
    - Adjust grid spacing from 11dp to 8dp and inner content arrangement for a denser, cleaner look.

- **iOS (SwiftUI) Enhancements**:
    - Update `CalendarMonthGridMetrics` and `CalendarPeriodCardMetrics` to match Android's new spacing and sizing logic.
    - Refactor month day cells to use a `RoundedRectangle` background and stroke instead of the previous `Circle` highlight.
    - Implement `CalendarNavButton` to standardize the appearance and behavior of navigation chevrons.
    - Adjust cell horizontal gutters and vertical spacing to improve alignment within the paging component.

- **Shared Logic**:
    - Standardize task count indicators with a consistent dot size (4.6dp) and refined typography.
    - Update navigation logic to ensure consistency in disabled states and padding across week, month, and day views.
…o unify the visual style, improve spacing, and enhance "today" highlighting.

- **Unified Styling & Colors**:
    - Introduce a dedicated "today" tint color (Blue #509AE6) for both platforms to distinguish current day from selection (Purple).
    - Update day cell backgrounds, borders, and text colors to use subtler opacities and thicker strokes for active states.
    - Synchronize typography across both platforms, notably increasing the calendar header title size to 21sp/pt.

- **Android (Compose) Enhancements**:
    - Wrap the calendar card in a `Box` with consistent shadow, clipping, and `AnimatedContent` size transformations to prevent layout jumps during view mode transitions.
    - Refactor `CalendarMonthDateCell` and `CalendarPeriodDayCell` with updated dimensions (42dp height) and rounded rectangle shapes (16dp).
    - Implement a custom interaction state for month cells, replacing the standard ripple with a bespoke background/border animation.
    - Adjust grid spacing from 11dp to 8dp and inner content arrangement for a denser, cleaner look.

- **iOS (SwiftUI) Enhancements**:
    - Update `CalendarMonthGridMetrics` and `CalendarPeriodCardMetrics` to match Android's new spacing and sizing logic.
    - Refactor month day cells to use a `RoundedRectangle` background and stroke instead of the previous `Circle` highlight.
    - Implement `CalendarNavButton` to standardize the appearance and behavior of navigation chevrons.
    - Adjust cell horizontal gutters and vertical spacing to improve alignment within the paging component.

- **Shared Logic**:
    - Standardize task count indicators with a consistent dot size (4.6dp) and refined typography.
    - Update navigation logic to ensure consistency in disabled states and padding across week, month, and day views.
…OS and Android platforms.

This update focuses on polishing the layout of the list creation interface, improving typography, and enhancing the visual transition of the top bar during scroll interactions.

- **iOS Todo List Enhancements**:
    - Introduce "handoff cover" metrics and logic in `TodoListScreen` to provide a smoother visual transition for the top bar as content scrolls beneath it.
    - Simplify `shouldApplyFirstPinnedRowElasticClearance` by using a comprehensive switch statement over `viewModel.mode`.
    - Add a background overlay to the top bar with dynamic opacity (`handoffCoverOpacity`) to blend with the background during scroll.

- **iOS Home & List Creation**:
    - Remove the outer `ScrollView` from the `CreateListSheet` and adjust the layout to a fixed `VStack` with a flexible `fraction(0.8)` detent.
    - Reduce font sizes for the "New list" title, section headers, and the list name `TextField` for a more compact design.
    - Adjust padding and corner radii within the list creation cards and input fields.

- **Android Home & List Creation**:
    - Remove `verticalScroll` from the list creation sheet to maintain a stable layout.
    - Implement auto-focus logic using `FocusRequester` and `LaunchedEffect` to automatically show the keyboard when the "New list" sheet appears.
    - Remove the redundant "List" section title to match the streamlined iOS layout.
…n both iOS and Android platforms."

This reverts commit 1d94a36.
…(SwiftUI) to improve UI consistency, simplify navigation, and enhance the user experience.

This update replaces multi-page navigation flows with single-page scrollable layouts, introduces dropdown menus for selection on Android, and refines typography and spacing across both platforms.

- **Android (Compose)**:
    - **Simplified Task Creation**: Remove `TaskSheetPage` state and multi-page navigation. Consolidate scheduling and organization into a single view.
    - **Dropdown Selection**: Replace full-page selection screens for Lists, Priority, and Repeat options with `DropdownMenu` components (`SheetDropdownRow`).
    - **Improved UX**: Add `FocusRequester` to the "New List" sheet to automatically focus the name field and show the keyboard on launch.
    - **UI Polish**: Update icons (e.g., `ExpandMore` instead of `ChevronRight`) and refine layout spacing in `CreateTaskBottomSheet` and `HomeScreen`.

- **iOS (SwiftUI)**:
    - **Task Sheet Redesign**: Replace `Form` and `Picker` with custom `CreateTaskSheetGroupCard` and `Menu` based rows for a more modern, integrated look.
    - **New Components**: Implement `CreateTaskSheetDueRow` with integrated `DatePicker` chips and `CreateTaskSheetMenuRow` for list/priority/repeat selection.
    - **Color & Style**: Add helper functions for consistent color swatches across lists, priorities, and repeat rules. Update typography to use `tdayRounded` with revised weights and sizes.
    - **Presentation**: Adjust sheet presentation to use a `0.8` fraction detent and a larger corner radius (34pt).

- **Shared UI Logic**:
    - Harmonize section titles and headers across both platforms for a consistent brand identity.
    - Update list and task creation headers to use a more compact typography style.
This update focuses on improving the visual consistency and responsiveness of "Create Task" and "Create List" sheets. It introduces a custom dialog-based selector on Android to replace standard dropdowns and implements dynamic sheet heights on iOS to better accommodate keyboard states and content size.

- **Create Task UI Improvements**:
    - **iOS**: Replace `ViewThatFits` with a simplified `HStack` layout for date and time chips. Implement a custom `ZStack` for `DatePicker` to allow better text styling (bold, rounded) while maintaining native picker functionality.
    - **Android**: Refactor `SheetRow` to improve alignment of value text and chevron icons.
    - **Unified Component**: Update `CreateTaskSheetDatePickerChip` and `SheetRow` with consistent padding and geometry.

- **Selection Dialogs (Android)**:
    - Replace `DropdownMenu` with `CenteredSelectorDialog`, a custom modal dialog providing a more focused selection experience for list colors and icons.
    - Implement `CenteredSelectorRow` with support for color swatches, checkmark indicators, and bold typography.

- **Dynamic Sheet Behavior (iOS)**:
    - Implement dynamic height adjustment for the "Create List" sheet using `PreferenceKey` and `GeometryReader`.
    - Add support for multiple presentation detents, automatically switching between a compact height and a "typing" height (80% fraction) when the name field is focused.

- **Keyboard & Focus Handling (Android)**:
    - Update `CreateListBottomSheet` to dynamically toggle between `wrap_content` and `fillMaxHeight(0.8f)` based on IME (keyboard) visibility and focus state.
    - Center-align text within the list name input field.
… standard system menus with a custom overlay-based selector and a unified date-time control.

- **Custom Selector UI**:
    - Introduce `CreateTaskSheetSelector` enum to manage the state of active selection overlays for lists, priorities, and recurrence rules.
    - Replace `CreateTaskSheetMenuRow` (using system `Menu`) with `CreateTaskSheetSelectorTriggerRow` and a dedicated `selectorOverlay` using `CreateTaskSheetSelectorCard`.
    - Implement `CreateTaskSheetSelectorRow` to provide a consistent, branded selection experience with color swatches and checkmark indicators.

- **Date & Time Picking**:
    - Replace individual date and time chips with a unified `CreateTaskSheetDateTimeControl` component.
    - Refactor the underlying layout to use a single container with a custom border and a vertical divider between date and time labels.
    - Update typography to use `.tdayRounded` weight `.heavy` for improved legibility in the date-time display.

- **Component Refactoring**:
    - Extract repeated UI patterns into new sub-views: `CreateTaskSheetSelectorCard`, `CreateTaskSheetSelectorRow`, and `CreateTaskSheetSelectorDivider`.
    - Adjust styles for existing components, including updated corner radii, background opacities, and font weights to align with a more refined design language.
This update renames the `.repeat` case to `.recurrence` within the `CreateTaskSheetSelector` enum and its associated logic. This change improves code clarity and avoids potential conflicts with the `repeat` keyword.

- **Refactoring**:
    - Rename `CreateTaskSheetSelector.repeat` to `CreateTaskSheetSelector.recurrence`.
    - Update `activeSelector` assignments and switch-case statements in `CreateTaskSheet.swift` to reflect the rename.
    - Ensure the UI display title for the `.recurrence` case remains "Repeat".
…ss Android and iOS clients.

This update introduces tracking for list creation dates (`createdAt`) in the local offline cache. This data is utilized to implement a standardized sorting mechanism (`orderListsLikeWeb`) that orders lists by creation date descending, ensuring UI consistency with the web platform.

- **Data Model & Persistence**:
    - Add `createdAtEpochMs` to `CachedListEntity` (Android) and `CachedListRecord` (iOS).
    - **Android**: Increment Room database version to 3 and implement `MIGRATION_2_3` to add the `createdAtEpochMs` column to the `cached_lists` table.
    - **iOS**: Update `CachedListEntity` SwiftData model and `CachedListRecord` to include the optional creation timestamp.
    - Update entity mappers and DTO parsers on both platforms to handle the new `createdAt` field.

- **Sorting Logic**:
    - Implement `orderListsLikeWeb` utility function to sort lists by `createdAtEpochMs` in descending order, falling back to original indices for stability.
    - Integrate the new sorting logic into `SyncManager`, `TodoRepository`, and `ListRepository` on both Android and iOS to ensure a consistent list display.
    - Replace previous alphabetical sorting in the iOS `ListRepository` with the creation-date-based order.

- **Refinement & Testing**:
    - Update `ListSummary` domain models to include the `createdAt` property.
    - Enhance `CacheMappersTest.kt` with new test cases for round-trip mapping and sorting verification of list creation timestamps.
    - Ensure local list creation accurately captures and persists the current timestamp.
…for both Android and iOS.

This update replaces the standard system-styled settings on iOS with a bespoke, branded design and introduces a dedicated "App Version" screen to track releases. Additionally, it refines the timeline experience by adding smooth expand/collapse animations and visual feedback for section headers.

- **Settings & Versioning (iOS)**:
    - Redesign `SettingsScreen` with custom cards, iconography, and a tailored typography system, moving away from `Form` and `Picker` defaults.
    - Implement `LatestReleaseScreen` to display GitHub release notes, version compatibility status, and links to official releases.
    - Add `GitHubRelease` model and update `AppViewModel` to fetch release metadata and changelogs from the GitHub API.
    - Update `AppRoute` and `AppRootView` to support navigation to the new version details screen.

- **Timeline UI & Animations (Multi-platform)**:
    - **Android (Compose)**: Implement `AnimatedVisibility` with `expandVertically` and `shrinkVertically` for todo and completed sections. Add rotation animations and state-aware color tinting to section chevrons.
    - **iOS (SwiftUI)**: Implement a custom multi-phase collapse/reveal system in `CompletedScreen` and `TodoListScreen` to manage view rendering and opacity transitions during section toggling.
    - Enhance section headers with press-responsive brightness adjustments and smoother haptic-like visual feedback.

- **Admin Features**:
    - Improve the "AI task summary" toggle in settings with loading states, error handling for validation, and clearer "saving" indicators.

- **Navigation**:
    - Add `latest-release` deep-link path and update navigation logic to handle the new versioning view.
… and iOS clients to improve performance and animation smoothness.

This update simplifies the rendering logic for collapsible list sections by moving away from manual opacity/visibility tracking in favor of native transition and animation systems.

- **Android (Compose)**:
    - Flatten `LazyColumn` structure by replacing nested `AnimatedVisibility` with direct item-level rendering conditional on the collapse state.
    - Utilize `animateItem()` with custom `fadeInSpec`, `fadeOutSpec`, and `placementSpec` (FastOutSlowInEasing) for smoother row transitions.
    - Refactor `CompletedTimelineSection` and `TimelineSectionBody` into granular header and row components to reduce recomposition scope.
    - Animate the bottom spacing of section headers during transitions using `animateDpAsState`.

- **iOS (SwiftUI)**:
    - Remove redundant `@State` properties (`collapsingSectionIDs`, `revealingSectionIDs`) used for manual animation orchestration.
    - Replace custom opacity logic with `AnyTransition.asymmetric` combining opacity and vertical movement for rows.
    - Update `toggleTimelineSection` to use a spring animation (`response: 0.28`, `dampingFraction: 0.9`) for a more responsive feel.
    - Prevent empty sections from being marked as collapsible.

- **General**:
    - Synchronize animation durations across platforms (approx. 200–300ms) for a consistent user experience.
    - Improve "Quick Add" logic to properly handle section collapse states.
This change optimizes the task list rendering by removing invisible spacer rows previously used for empty sections.

- **UI Refinement**: Remove the `Color.clear` placeholder and its associated layout logic (frames, insets, and separator hiding) when a timeline section contains no items.
- **Cleanup**: Simplify the `ForEach` loop within the task list to conditionally render sections only when they contain one or more items.
…screens.

This update replaces the static headers in the Settings and App Version screens with a dynamic, scroll-responsive navigation system. It introduces smooth transitions between expanded hero titles and compact top bars, aligning these screens with the application's established timeline animation patterns.

- **Navigation & UI Consistency**:
    - Replace `SettingsPageHeader` with `TimelineTopBar` and `TimelineExpandedTitleRow` to support title collapse animations.
    - Implement `TimelineScrollOffsetObserver` in `SettingsScreen` and `AppVersionScreen` to track scroll progress.
    - Add `onVerticalScrollSnap` logic to handle snapping transitions based on `TodoTimelineMetrics.titleCollapseDistance`.
    - Configure `safeAreaInset` to host the persistent top bar and hide the default system navigation bar.

- **Refactoring**:
    - Remove the redundant `SettingsPageHeader` struct and `SettingsBackButtonStyle`.
    - Centralize title collapse progress calculation logic within the screen views using a private `titleCollapseProgress` property.
    - Standardize back button behavior using the custom `.navigationBackButtonBehavior()` modifier.
…e iOS SwiftUI client.

This update simplifies the `CompletedScreen` by removing the ability to "uncomplete" or restore items. It streamlines the UI by replacing the interactive checkmark with a static icon and removing the multi-phase restoration animations.

- **CompletedScreen**:
    - Remove `CompletedRestorePhase` enum and related state tracking logic.
    - Replace the interactive "Restore" button and checkmark with a static `checkmark.circle.fill` image.
    - Simplify item styling by making the strikethrough and opacity values static instead of phase-dependent.
    - Remove the `restoreCompletedItem` function and the leading "Restore" swipe action.
    - Update `completedTimelineAnimationKey` to only depend on item IDs.
    - Remove the `onChange` modifier that pruned restoration phases.

- **CompletedViewModel**:
    - Remove the `uncomplete(_:)` method and its associated error handling for task restoration.
This update replaces static prefix strings with formatted string resources in the Android Compose client. This change ensures better support for localization and follows Android's recommended practices for dynamic string construction.

- **String Resources**:
    - Replace `todos_due_overdue_prefix` and `todos_due_prefix` with formatted versions: `todos_due_overdue_text` ("Overdue, %1$s") and `todos_due_text` ("Due %1$s").
- **UI & Logic**:
    - Update `TodoListScreen.kt` to use `stringResource` with arguments when displaying due dates and overdue statuses in task subtitles and detail views.
    - Simplify string concatenation logic by leveraging resource-based formatting.
…ents.

This update standardizes text input behavior in the task creation sheet, simplifies the "Completed" screen by removing the undo functionality, and polishes UI elements like timestamps and labels.

- **Task Creation Enhancements**:
    - **iOS**: Update `CreateTaskSheet` to strip newlines from title and notes. Add a "Done" submit label and ensure the keyboard dismisses on submission.
    - **Android**: Update `CreateTaskBottomSheet` to force single-line input for both title and notes (stripping newlines). Implement `ImeAction.Done` to clear focus and dismiss the keyboard.

- **Completed Screen Refactoring**:
    - **Android**: Remove the "uncomplete" (undo) logic, including the multi-phase restoration animation and the `uncomplete` method in `CompletedViewModel`.
    - **UI Polish**: Replace the interactive checkmark with a static icon in the completed list. Add a clock icon next to the completion timestamp for better visual hierarchy.
    - **iOS**: Update the timeline row to include a system clock icon and adjust the opacity of the completion time text.

- **Resource & String Updates**:
    - Refactor `settings_role_prefix` to `settings_role_label` using string placeholders for better localization support.
    - Remove unused completion-related strings in `strings.xml`.
    - Fix a UI alignment issue in the Android Settings screen role label.
OmarI-Kubra and others added 27 commits May 21, 2026 11:25
…in `HomeScreen`.

This update replaces the fixed maximum height for search results with a calculated height based on the number of items. This ensures the dropdown matches its content size for small result sets while still respecting the maximum height limit for longer lists.

- **Dynamic Height Logic**:
    - Add constants for row height (`66`), vertical padding (`8`), and separator height (`1`).
    - Implement a `resultsHeight` computed property that calculates the total height based on the number of tasks and separators.
    - Constrain the final height using `min(contentHeight, maxResultsHeight)` to maintain the 320pt cap.
- **UI Integration**:
    - Update the search results container in `HomeScreen` to use the dynamic `resultsHeight` instead of a static `maxHeight`.
…Android and iOS.

This update standardizes the pull-to-refresh visual dimensions across platforms, improves the reliability of refresh triggers in SwiftUI, and streamlines the highlighted item scrolling logic in the Android Compose client.

- **Pull-to-Refresh Enhancements**:
    - **Visuals (Android & iOS)**: Increased dimensions for the refresh indicator container, dots, and spacing. Updated corner radius and offsets for a bolder appearance.
    - **iOS (SwiftUI)**: Replaced the standard `.refreshable` modifier with a custom manual trigger logic using `PullProgressChange`. This ensures more reliable execution and state synchronization between `isRefreshing` and local flight states.
    - **iOS (SwiftUI)**: Improved `UIScrollView` detection logic to better locate the nearest scrollable area (searching both ancestors and descendants).
    - **iOS (SwiftUI)**: Set `scrollBounceBehavior` to `.always` on the Home screen to ensure pull-to-refresh is accessible even with short content.

- **Android (Compose) List Improvements**:
    - **Scroll Logic**: Simplified the highlighted todo navigation in `TodoListScreen`. Replaced the multi-step delayed animation (pre-scroll, delay, center scroll) with a single `scrollToItem` call using a calculated centered offset.
    - **Section State**: Updated `collapsedSectionKeys` to remain expanded when a `highlightedTodoId` is present, ensuring search results or deep-linked items are visible.
    - **Clean-up**: Removed several unused constants related to the legacy multi-stage scroll animation and layout delays.

- **iOS App State & Sync**:
    - **Offline Handling**: Refined `confirmOfflineSyncFailure` in `AppViewModel` to perform a forced sync with a connection probe before marking the app as offline. This reduces false-positive offline notifications.
    - **UI**: Removed the redundant `ProgressView` from the Home screen when loading the initial summary.
… search navigation and pull-to-refresh UI.

This update introduces logic to automatically re-sync data when the app returns to the foreground, improves the reliability of navigating to specific tasks from search results, and refines the pull-to-refresh animation across Android and iOS.

- **App Lifecycle & Sync**:
    - **Android & iOS**: Added `reconnectAfterForeground()` to `AppViewModel`. This triggers a background sync and refreshes the realtime connection when the app is resumed from a paused or background state.
    - Added a `LifecycleEventObserver` on Android and `scenePhase` observation on iOS to detect foreground transitions.
    - Centralized server reconnection logic to ensure consistent behavior across connectivity changes and manual refreshes.

- **Search & Navigation (Android)**:
    - **Search Result Handling**: Added a short delay (`260ms`) when opening a task from search results to allow for a smoother transition before closing the search overlay.
    - **Reliable Highlighting**: Implemented a `PENDING_SEARCH_HIGHLIGHT_TODO_ID` in the navigation `SavedStateHandle`. This ensures that when navigating to the "All Todos" screen from search, the target task is correctly identified and highlighted even if the navigation takes time to settle.
    - **Smooth Scrolling**: Replaced `scrollToItem` with `animateScrollToItem` when highlighting a task, adding a `480ms` delay to ensure the list layout has stabilized.

- **Pull-to-Refresh UI Refinement**:
    - **Visual Polish**: Increased the number of animated bars from 3 to 5 and added a horizontal "sweep" background effect that tracks pull progress and animates during refreshing.
    - **Metrics**: Standardized dimensions across platforms (e.g., container width increased from `72dp` to `116dp`, adjusted dot spacing and heights).
    - **Shadows & Transitions**: Updated shadow colors and opacities to better align with the brand theme; refined scale and offset animations for a more fluid feel.

- **Bug Fixes & Clean-up**:
    - Fixed an issue where the offline notice wouldn't consistently trigger during network-driven sync failures.
    - Standardized connectivity probe timeouts for background refreshes.
…ftUI client.

This update adjusts the dimensions, styling, and layout logic of the `TdayPullRefreshIndicator` to provide a more polished and prominent visual experience during the pull-to-refresh gesture.

- **Metrics & Dimensions**:
    - Increased `triggerDistance` from 98 to 112 and updated container dimensions to 152x58.
    - Adjusted dot sizes (width 9, max height 30) and spacing (10).
    - Updated `sweepHeight` to 40 and `cornerRadius` to 29 for a rounder appearance.

- **Styling & Effects**:
    - Added a subtle stroke to the internal sweep area for better definition.
    - Updated background opacity logic for the sweep area based on pull progress.
    - Refined shadow values (radius and offsets) for both the primary indicator and the black drop shadow to enhance depth.
    - Adjusted entrance animation offsets and scale effects for a smoother appearance.

- **Layout & Logic**:
    - Refactored the internal `ZStack` to use a `clipShape`, ensuring the background sweep effect stays contained within its track.
    - Simplified bar metric calculations by removing the manual `verticalOffset`, relying on the `HStack` alignment instead.
    - Removed the manual horizontal offset calculation for the sweep indicator in favor of a centered layout within the track.
… in the Android Compose client.

This update overhauls the pull-to-refresh component with more robust gesture handling and updated styling, refactors title collapse logic for better performance, and improves search result navigation.

- **Pull-to-Refresh Enhancements**:
    - **Visuals**: Updated `TdayPullRefresh` with new dimensions, increased container size, larger dots, and refined elevation/spacing constants in `Dimens.kt`.
    - **Interaction**: Implemented explicit pointer detection (`PointerEventPass.Initial`) to track user pull state, ensuring content offsets only apply during active manual pulls.
    - **Rendering**: Replaced `pullToRefreshIndicator` with a custom `graphicsLayer` implementation and added `clipRect` to handle drawing outside bounds during transitions.
    - **Animation**: Adjusted spin duration and added scaling effects to the refresh indicator.

- **List & Navigation Improvements**:
    - **Search Scrolling**: Introduced `animateSearchResultScrollToItem`, a multi-pass scroll logic that estimates item positions and corrects for dynamic content height to accurately center search results.
    - **Collapse Logic**: Simplified title collapse behavior across `TodoListScreen`, `CalendarScreen`, `CompletedScreen`, and `SettingsScreen`. Replaced `NestedScrollConnection` and `animateFloatAsState` with `derivedStateOf` based on list scroll offsets for a more direct, non-animated response.
    - **Performance**: Added `contentType` to `LazyColumn` items to improve composition performance and reused static `DateTimeFormatter` instances for task rows.

- **UI/UX Refinements**:
    - Standardized date and time formatters across various task row types.
    - Reduced `SEARCH_RESULT_NAV_SETTLE_DELAY_MS` for snappier navigation transitions.
    - Fixed vertical centering of refresh bar dots by zeroing out previous offsets.
…Android and iOS clients.

This update replaces standard empty state UI components with a new "watermark" style background illustration (large, faded, rotated icons) and centered text messages. This ensures a consistent, modern aesthetic when screens have no content to display.

- **Shared UI Components**:
    - **iOS**: Introduced `EmptyTaskWatermark` in `TdayTheme.swift`, featuring a large system icon with custom blending, rotation, and positioning.
    - **Android**: Integrated `EmptyTaskWatermark` and `EmptyTaskBackgroundMessage` (Compose) to handle empty state visuals.

- **Feature Integration**:
    - **Todo List & Search**: Updated `TodoListScreen` on both platforms to display mode-specific watermarks (e.g., sun for "Today," flag for "Priority," or custom list icons).
    - **Calendar**: Added a "calendar" watermark and centered empty message when no tasks are scheduled for a selected date.
    - **Completed**: Implemented a "checkmark" watermark for the completed tasks screen.

- **UI/UX Refinements**:
    - **Android**: Refactored `LazyColumn` layouts into `Box` containers to overlay watermarks behind the list area.
    - **iOS**: Simplified `TimelineCategoryEmptyState` by removing redundant icon logic, relying instead on the new background watermark overlay.
    - Updated specific iconography: Changed "Overdue" from a clock to an error outline/exclamation mark and "Scheduled" to a clock/calendar icon.
    - Ensured empty states only trigger when `isLoading` is false to prevent flickering during data fetches.

- **Code Clean-up**:
    - Removed legacy empty state composables and view modifiers (`EmptyTimelineState`, `EmptyCalendarState`) in favor of the new standardized components.
    - Optimized logic for selecting icons based on the current list mode or custom list keys.
…termark and background message.

This update refactors the "empty state" presentation across the Completed, Todo, and Calendar screens. It replaces scattered text views and legacy empty state components with a consistent `ZStack` layout that pairs the `EmptyTaskWatermark` with a new `EmptyTaskBackgroundMessage` component.

- **Theme & Components**:
    - **EmptyTaskWatermark**: Refactored to use `GeometryReader` for more precise positioning. Increased icon size to `194` and adjusted the layout to align relative to the bottom-trailing area (2/3 down the screen height).
    - **EmptyTaskBackgroundMessage**: Introduced as a reusable component for empty state text, featuring a bold rounded font, center alignment, and horizontal padding.

- **Feature Integration**:
    - **CompletedScreen**: Replaced `TimelineEmptyState` with the unified watermark and "No completed tasks" message overlay.
    - **TodoListScreen**: Removed `TimelineEmptyState` and `TimelineCategoryEmptyState`. Replaced with a `ZStack` overlay containing the appropriate watermark and dynamic category message.
    - **CalendarScreen**: Removed the inline "No pending task..." list row. Added an overlay containing the calendar watermark and background message when no tasks are present.

- **Clean-up**:
    - Removed unused metrics (`emptyStateSize`, `emptyStateOffset`) from `TodoTimelineMetrics`.
    - Deleted legacy `TimelineEmptyState` and `TimelineCategoryEmptyState` struct definitions from `TodoListScreen.swift`.
    - Applied `.allowsHitTesting(false)` and `.accessibilityHidden(true)` to background decorations to ensure they don't interfere with user interactions.
…mpty states and standardize its implementation across Android and iOS screens.

This update refactors the empty state UI by creating a dedicated `EmptyTaskWatermark` and `EmptyTaskBackgroundMessage` system. On Android, the layout logic is moved outside of scrollable containers to ensure watermarks remain fixed and correctly layered, while iOS receives corresponding cleanup.

- **New Core UI Components (Android)**:
    - **EmptyTaskWatermark**: A decorative, large-scale icon watermark positioned with a slight rotation and opacity. It supports optional accent color blending.
    - **EmptyTaskBackgroundMessage**: A bold, centered text component for display when no tasks are present.

- **Feature Integration & Refactoring**:
    - **TodoListScreen & CompletedScreen (Android)**: Refactored the layout to wrap the `LazyColumn` and empty state components in a `Box`. This ensures watermarks are rendered relative to the screen dimensions rather than as list items, preventing them from scrolling or affecting list spacing.
    - **Timeline Adjustments**: Refined spacing in `TodoListScreen` by increasing `timelineHeaderBodySpacing` to `4.dp` and adding top padding to section headers (except the first) for better visual rhythm.
    - **CalendarScreen cleanup**: Removed local implementations of empty state watermarks on both Android and iOS in favor of a more consistent architectural approach.

- **Layout Fixes**:
    - Wrapped `LazyColumn` in an additional `Box` within `Scaffold` content to properly handle system padding while allowing full-screen overlays like the watermark to be positioned accurately.
…g for Android and iOS.

This update introduces a standardized title collapse mechanism across multiple screens on Android using a new snapping utility. It also refines how task sections are ordered in the "All" todo list view and improves the robustness of scroll snapping on iOS.

- **Android (Compose)**:
    - **Title Collapse & Snapping**:
        - Introduced `snapTitleCollapsePx` utility to calculate whether a header should snap to a collapsed or expanded state based on scroll velocity and position.
        - Integrated `NestedScrollConnection` and `onPreFling` logic in `TodoListScreen`, `CalendarScreen`, `CompletedScreen`, `LatestReleaseScreen`, and `SettingsScreen` to handle manual and velocity-based header snapping.
        - Added `animateFloatAsState` for smoother transitions of the collapse progress across all top-level screens.
        - Added a `LaunchedEffect` to ensure headers snap to a valid state (fully expanded or fully collapsed) when scrolling stops.
    - **Todo List Logic**:
        - Modified `buildScheduledSections` to allow conditional placement of the "Earlier" section. In "All" mode, "Earlier" tasks now appear before "Today" to improve chronological flow.
        - Updated `TodoListScreen` to automatically collapse the "Today" header when navigating to a specific task search result.

- **iOS (SwiftUI)**:
    - **PullToRefresh Snapping**:
        - Refactored `PullToRefresh` snapping logic to use a `Timer`-based check (`scheduleSnapCheck`) ensuring the scroll view is fully idle (not dragging or decelerating) before snapping.
        - Added `maxScrollableOffset` validation to prevent snapping issues on short lists where the content doesn't exceed the collapse distance.
        - Improved memory management by invalidating the snap timer on deinitialization.

- **Clean-up**:
    - Removed `derivedStateOf` logic in favor of more performant state-driven animations for header progress.
    - Standardized naming and constants for collapse thresholds and durations.
…troduce a reusable swipe action component.

This update synchronizes timeline header logic and swipe action appearances across the iOS app while adding a dedicated UI component for swipe actions in the Android client. Key changes include consistent tinting for task interactions, improved header collapse animations, and adjustments to timeline section ordering.

- **iOS (SwiftUI)**:
    - **Swipe Actions**: Introduced `TaskSwipeActionTint` to define standard RGB colors for "edit" (blue) and "delete" (red) actions. Updated `CompletedScreen`, `TodoListScreen`, and `CalendarScreen` to use these consistent tints.
    - **Timeline Header & Metrics**:
        - Increased `expandedTitleHeight` from 42 to 56 in `TodoTimelineMetrics`.
        - Refined `CalendarHeroTitle` to handle height collapse based on scroll progress, ensuring a smoother transition to the pinned state.
    - **Timeline Logic**:
        - Modified `buildFutureTimelineSections` to support conditional positioning of the "Earlier" section. In "All Tasks" mode, "Earlier" now appears before "Today", while in "Priority" or "List" modes, it appears after "Today".
        - Simplified scroll progress calculations in `SettingsScreen` by removing the "snapped" progress and elastic top insets.
    - **Bug Fixes & Cleanup**: Removed the `.destructive` role from delete buttons to allow for custom `.tint` application while maintaining standard swipe behavior.

- **Android (Compose)**:
    - **New Component**: Added `TaskSwipeActionButton`, a reusable component for swipeable list items. It features:
        - Animated scaling and alpha transitions based on reveal progress.
        - Haptic-friendly touch feedback using `MutableInteractionSource` and `animateFloatAsState`.
        - Standardized layout with a card-based icon container and a bold label.

- **UI/UX Refinements**:
    - Standardized row heights and spacing across different timeline modes to ensure visual consistency between the calendar and task lists.
…troduce a reusable swipe action component.

This update synchronizes timeline header logic and swipe action appearances across the iOS app while adding a dedicated UI component for swipe actions in the Android client. Key changes include consistent tinting for task interactions, improved header collapse animations, and adjustments to timeline section ordering.

- **iOS (SwiftUI)**:
    - **Swipe Actions**: Introduced `TaskSwipeActionTint` to define standard RGB colors for "edit" (blue) and "delete" (red) actions. Updated `CompletedScreen`, `TodoListScreen`, and `CalendarScreen` to use these consistent tints.
    - **Timeline Header & Metrics**:
        - Increased `expandedTitleHeight` from 42 to 56 in `TodoTimelineMetrics`.
        - Refined `CalendarHeroTitle` to handle height collapse based on scroll progress, ensuring a smoother transition to the pinned state.
    - **Timeline Logic**:
        - Modified `buildFutureTimelineSections` to support conditional positioning of the "Earlier" section. In "All Tasks" mode, "Earlier" now appears before "Today", while in "Priority" or "List" modes, it appears after "Today".
        - Simplified scroll progress calculations in `SettingsScreen` by removing the "snapped" progress and elastic top insets.
    - **Bug Fixes & Cleanup**: Removed the `.destructive` role from delete buttons to allow for custom `.tint` application while maintaining standard swipe behavior.

- **Android (Compose)**:
    - **New Component**: Added `TaskSwipeActionButton`, a reusable component for swipeable list items. It features:
        - Animated scaling and alpha transitions based on reveal progress.
        - Haptic-friendly touch feedback using `MutableInteractionSource` and `animateFloatAsState`.
        - Standardized layout with a card-based icon container and a bold label.

- **UI/UX Refinements**:
    - Standardized row heights and spacing across different timeline modes to ensure visual consistency between the calendar and task lists.
…he SwiftUI client.

This update replaces the static hero title row with a dynamic `CalendarElasticTopBar` that responds to scroll gestures. The new implementation features a sophisticated handoff animation between expanded and collapsed states, including parallax offsets and alpha transitions.

- **Animation & Layout**:
    - Define `CalendarTitleHandoff` constants to manage collapse distances (180pt), fade thresholds, and snapping behaviors.
    - Implement `CalendarElasticTopBar` which transitions from a large hero title to a centered navigation bar title as the user scrolls.
    - Apply `scaleEffect` and vertical offsets to the collapsed title for a "reveal" effect from behind the top bar buttons.
    - Adjust the expanded title's opacity and position using linear progress mapping to ensure smooth fading and lifting transitions.

- **Scroll Interaction**:
    - Introduce `CalendarTitleCollapseScrollObserver`, a `UIViewRepresentable` that monitors the underlying `UIScrollView`'s pan gestures and content offsets.
    - Implement custom scroll consumption logic to prioritize title collapse/expansion before allowing the list content to scroll.
    - Add snapping logic via a timer-based check to ensure the title always settles in either a fully expanded or fully collapsed state.
    - Added `sliderPartialSnapDistance` to automatically snap the calendar view mode tabs to the top if they are partially visible after a scroll.

- **UI Refinements**:
    - Refactor top bar buttons into `CalendarTopBarButton` with support for plain, filled, and outlined chrome styles.
    - Use `TdayPressButtonStyle` for consistent haptic and visual feedback on button interactions.
    - Clean up the main `CalendarScreen` by removing the manual `calendarHeroTitleRow` in favor of the inset `CalendarElasticTopBar`.
…he SwiftUI client.

This update replaces the static hero title row with a dynamic `CalendarElasticTopBar` that responds to scroll gestures. The new implementation features a sophisticated handoff animation between expanded and collapsed states, including parallax offsets and alpha transitions.

- **Animation & Layout**:
    - Define `CalendarTitleHandoff` constants to manage collapse distances (180pt), fade thresholds, and snapping behaviors.
    - Implement `CalendarElasticTopBar` which transitions from a large hero title to a centered navigation bar title as the user scrolls.
    - Apply `scaleEffect` and vertical offsets to the collapsed title for a "reveal" effect from behind the top bar buttons.
    - Adjust the expanded title's opacity and position using linear progress mapping to ensure smooth fading and lifting transitions.

- **Scroll Interaction**:
    - Introduce `CalendarTitleCollapseScrollObserver`, a `UIViewRepresentable` that monitors the underlying `UIScrollView`'s pan gestures and content offsets.
    - Implement custom scroll consumption logic to prioritize title collapse/expansion before allowing the list content to scroll.
    - Add snapping logic via a timer-based check to ensure the title always settles in either a fully expanded or fully collapsed state.
    - Added `sliderPartialSnapDistance` to automatically snap the calendar view mode tabs to the top if they are partially visible after a scroll.

- **UI Refinements**:
    - Refactor top bar buttons into `CalendarTopBarButton` with support for plain, filled, and outlined chrome styles.
    - Use `TdayPressButtonStyle` for consistent haptic and visual feedback on button interactions.
    - Clean up the main `CalendarScreen` by removing the manual `calendarHeroTitleRow` in favor of the inset `CalendarElasticTopBar`.
… Android and iOS.

This update ensures that the application splash screen remains visible for at least one second, preventing a "flickering" experience during fast app initialization or bootstrap sequences.

- **Android (Compose)**:
    - Introduce `SPLASH_MIN_DISPLAY_MS` constant set to 1,000ms.
    - Update `AppNavigationEffect` to track the splash start time and inject a `delay` if the initial loading and authentication checks complete faster than the minimum duration.
    - Define `isStartupSplashRoute()` to identify initial entry routes (Splash, Login, ServerSetup) where the delay should apply.

- **iOS (SwiftUI)**:
    - Add `hasMetLaunchSplashMinimum` state to `AppRootView` to track the splash timing requirement.
    - Implement a `.task` modifier that sleeps for 1 second before allowing the transition from `AppLaunchSplashView` to the main content.
    - Update the conditional rendering logic to ensure the splash view stays active until both the initial bootstrap is complete and the minimum time has elapsed.
…atus codes on Android and iOS.

This update refines the logic used to determine if an API error should be treated as a transient connectivity issue. By including specific HTTP status codes related to timeouts and gateway errors (e.g., 408, 502, 503, 504, and Cloudflare-style 52x errors), the application can better handle scenarios where the server is temporarily unreachable or overloaded.

- **Common Logic**:
    - Add `isLikelyServerUnavailableStatus` helper to identify connectivity-related HTTP status codes: 408 (Request Timeout), 502 (Bad Gateway), 503 (Service Unavailable), 504 (Gateway Timeout), and 520–524 (Server/Origin errors).

- **Android (Compose)**:
    - Update `isLikelyConnectivityIssue` in `ApiResponseUtils.kt` to check `ApiCallException` status codes.
    - Expand string-based error matching to include keywords like "bad gateway", "service unavailable", "gateway timeout", and "origin unreachable".
    - Add `ApiResponseUtilsTest.kt` to verify classification of various status codes.

- **iOS (SwiftUI)**:
    - Update `isLikelyConnectivityIssue` in `TdayAPIService.swift` to evaluate `APIError` status codes using the new classification logic.
    - Add `ConnectivityClassificationTests.swift` to the `TdayCoreTests` target to ensure consistent behavior across status codes.
    - Update project configuration to include the new test file.
… Android and iOS.

This update replaces the fixed 1.5-second splash screen timer with a gesture-based mechanism that allows users to keep the splash screen visible by pressing and holding the screen. The app now transitions to the main content immediately after initialization unless the splash screen is being actively held.

- **Android (Compose)**:
    - Replace `SPLASH_MIN_DISPLAY_MS` constant and `delay` logic with an `isStartupSplashHeld` state.
    - Update `SplashScreen` to use `pointerInput` and `detectTapGestures` to track press and release events.
    - Refactor `HandleNavigation` to observe `isStartupSplashHeld` before triggering initial routing.
    - Use `DisposableEffect` to ensure the hold state is cleared when the splash component is disposed.

- **iOS (SwiftUI)**:
    - Replace `hasMetLaunchSplashMinimum` and `Task.sleep` logic with an `isLaunchSplashHeld` state.
    - Add a `DragGesture` (with `minimumDistance: 0`) to `AppLaunchSplashView` to detect touch start and end.
    - Apply `contentShape(Rectangle())` to ensure the entire screen area is gesture-responsive.
    - Ensure `isHeld` is reset to `false` in `onDisappear`.
… flow.

This update introduces a visual identity to the iOS launch process by adding branding elements to the static launch storyboard and synchronizing it with a SwiftUI-based splash view during app initialization.

- **Launch Storyboard**:
    - Update `LaunchScreen.storyboard` to include a centered `StackView` containing the app title ("T'Day") and a tagline ("Your server remembers, so you don't have to").
    - Add Auto Layout constraints to ensure the branding elements remain centered and properly padded on different screen sizes.
    - Define and apply new named colors `LaunchForeground` and `LaunchMuted` for the text elements, supporting both light and dark modes.

- **App Initialization**:
    - Refactor `TdayApp` to defer `AppContainer` initialization. The `appContainer` is now an optional state variable initialized asynchronously within a `.task` modifier.
    - Introduce `isLaunchSplashHeld` state to manage the transition from the splash view to the main application interface.
    - Wrap the main window content in a `Group` that displays `AppLaunchSplashView` while the container is loading or the splash is held, ensuring a seamless transition from the system launch screen to the app UI.

- **UI Components & Assets**:
    - Export `AppLaunchSplashView` from `AppRootView.swift` to make it accessible for the top-level app transition.
    - Add color assets for `LaunchForeground` and `LaunchMuted` with specific sRGB components for light and dark appearances.
This change enhances the initial loading experience by introducing the brand's upright logo and transitioning from system fonts to the custom "Nunito-ExtraBold" typeface on the launch screen.

- **Assets & Configuration**:
    - Add `LaunchSplashLogoUpright.png` to the project resources and update the Xcode project file references.
    - Register the `Nunito.ttf` font within the `LaunchScreen.storyboard` custom fonts section.

- **Launch Screen UI**:
    - Add an `imageView` to the `LaunchScreen.storyboard` to display the new splash logo (160x160).
    - Insert a spacer view to provide 24pt of vertical separation between the logo and the application title.
    - Update the "T'Day" title and slogan labels to use the `Nunito-ExtraBold` font.
    - Refine the `stackView` layout, increasing its height to accommodate the new visual elements while maintaining center alignment.
…ets across Android and iOS.

This update standardizes error messaging for server reachability and connectivity issues across both platforms. It also refines the visual identity of the Android application by updating the launcher and splash icons and improves the pull-to-refresh animation.

- **Networking & Auth**:
    - **Unified Error Messaging**: Introduced `serverUnreachableMessage` (iOS) and `SERVER_UNREACHABLE_MESSAGE` (Android) to provide a consistent "Cannot reach server..." message for connectivity issues.
    - **Expanded Error Detection**: Updated `AuthViewModel` and `AuthRepository` on both platforms to catch a wider range of network-related strings (e.g., "timed out", "bad gateway", "service unavailable", "web server is down") and HTTP status codes (408, 502-504, etc.).
    - **Android Auth Flow**: Improved `AuthRepository.kt` to better handle connectivity issues during the multi-step sign-in process, ensuring consistent error reporting.
    - **iOS Auth Flow**: Integrated `isLikelyServerUnavailableStatusCode` checks into `AuthRepository.swift` to catch server-side failures during the callback phase.

- **Android UI & Assets**:
    - **Launcher & Splash Icons**: Redesigned `splash_icon.xml` and `ic_launcher_foreground.xml` with a more detailed calendar-style vector graphic. Added new color resources in `colors.xml` (e.g., `ic_launcher_surface`, `ic_launcher_task`, `ic_launcher_outline`) to support the new designs.
    - **Pull-to-Refresh**: Enhanced `TdayPullRefresh.kt` with an animated `refreshingBottomOffset` to ensure the loading indicator maintains its correct position during the refreshing state.
    - **Dark Mode**: Added specific color overrides in `values-night/colors.xml` for launcher backgrounds.

- **iOS Assets**:
    - Added `LaunchSplashLogoUpright.png` to the resources directory.
…ets across Android and iOS.

This update standardizes error messaging for server reachability and connectivity issues across both platforms. It also refines the visual identity of the Android application by updating the launcher and splash icons and improves the pull-to-refresh animation.

- **Networking & Auth**:
    - **Unified Error Messaging**: Introduced `serverUnreachableMessage` (iOS) and `SERVER_UNREACHABLE_MESSAGE` (Android) to provide a consistent "Cannot reach server..." message for connectivity issues.
    - **Expanded Error Detection**: Updated `AuthViewModel` and `AuthRepository` on both platforms to catch a wider range of network-related strings (e.g., "timed out", "bad gateway", "service unavailable", "web server is down") and HTTP status codes (408, 502-504, etc.).
    - **Android Auth Flow**: Improved `AuthRepository.kt` to better handle connectivity issues during the multi-step sign-in process, ensuring consistent error reporting.
    - **iOS Auth Flow**: Integrated `isLikelyServerUnavailableStatusCode` checks into `AuthRepository.swift` to catch server-side failures during the callback phase.

- **Android UI & Assets**:
    - **Launcher & Splash Icons**: Redesigned `splash_icon.xml` and `ic_launcher_foreground.xml` with a more detailed calendar-style vector graphic. Added new color resources in `colors.xml` (e.g., `ic_launcher_surface`, `ic_launcher_task`, `ic_launcher_outline`) to support the new designs.
    - **Pull-to-Refresh**: Enhanced `TdayPullRefresh.kt` with an animated `refreshingBottomOffset` to ensure the loading indicator maintains its correct position during the refreshing state.
    - **Dark Mode**: Added specific color overrides in `values-night/colors.xml` for launcher backgrounds.

- **iOS Assets**:
    - Added `LaunchSplashLogoUpright.png` to the resources directory.
…nd refactor launch assets on iOS.

This update standardizes the pull-to-refresh indicator's visual identity using a brand-specific blue accent and introduces more robust refresh state handling in the Android Compose implementation.

- **Android (Compose)**:
    - **TdayPullRefresh**: Improved state management to handle "in-flight" refresh states. Added a `RefreshHandoffHoldMillis` (1.5s) delay to keep the indicator visible during short network transitions or until an external refresh signal is confirmed.
    - Updated `TdayPullToRefreshIndicator` to use `TdayTodayBlue` for background and dot accents instead of the default primary color scheme.
    - Added `zIndex(1f)` to the indicator to ensure it remains on top of content during the refresh animation.

- **iOS (SwiftUI)**:
    - **PullToRefresh**: Updated the refresh indicator components (rounded rectangle background, stroke, and dots) to use `Color.tdayTodayBlue` instead of the primary color.
    - Adjusted shadow colors to use the new blue accent for consistent branding.

- **Assets & Resources**:
    - **iOS**: Migrated `LaunchSplashStack` from an asset catalog (`.imageset`) to a standalone PNG resource in the `Resources` directory.
    - Updated the Xcode project file to reflect the removal of the image set and the addition of `LaunchSplashStack.png` to the build resources.
This update introduces a formal splash screen theme using the Android 12+ Splash Screen API and refactors the application startup sequence to defer non-critical initialization until the first frame is drawn.

- **Splash Screen & Branding**:
    - Add `Theme.Tday.Starting` to handle the initial window background and splash icon presentation.
    - Update `splash_icon.xml` and `ic_launcher_foreground.xml` with refined vector paths for better scaling and visual consistency.
    - Introduce `window_splash.xml` as a layered drawable for the starting window background.
    - Add `ic_launcher_monochrome.xml` and update adaptive icon definitions to support themed icons.
    - Remove `splash_blank.xml` in favor of the new branded splash assets.

- **Startup Optimization**:
    - **MainActivity**: Set the main app theme immediately in `onCreate` and wrap `TdayApp` with a callback to trigger deferred tasks.
    - **TdayApp**: Implement a "startup frame" logic using `withFrameNanos` to ensure the splash screen UI is rendered before transitioning to the main navigation.
    - **TdayApplication**: Introduce `runDeferredStartup()` to initialize heavy dependencies like Sentry and notification permission checks only after the UI is responsive.
    - Pass a randomized `tagline` from the startup state to `SplashScreen` to ensure visual continuity during the transition.

- **Theme & Styles**:
    - Update `themes.xml` (including v31) to link the new starting theme and splash attributes.
    - Standardize splash background colors across light and dark modes.
…egistration.

This update integrates the Jetpack Credentials API into the Android Compose client to support saving, updating, and retrieving credentials via the system password manager. It also updates the backend to support Digital Asset Links for cross-platform credential sharing.

- **Android (Compose)**:
    - **SystemCredentialService**: Introduce a new service to interact with `CredentialManager`, supporting `GetPasswordOption` for logins and `CreatePasswordRequest` for saving new accounts.
    - **Auth Integration**: Update `AuthViewModel` to trigger credential saving after successful manual login or registration. Added `LoginCredentialCoordinator` to handle one-time auto-fill requests when the login screen appears.
    - **Autofill UI**: Add a custom `tdayAutofill` modifier to the onboarding flow, linking `OutlinedTextField` components to `AutofillType.Password`, `AutofillType.EmailAddress`, and others.
    - **Session Management**: Ensure `clearCredentialState()` is called on logout to notify the system provider.
    - **Configuration**: Added `asset_statements` to `AndroidManifest.xml` to link the app with the web domain.

- **Backend (Ktor)**:
    - **Digital Asset Links**: Implement a new route `/.well-known/assetlinks.json` that serves the required JSON payload for Android credential sharing.
    - **Configuration**: Add `ANDROID_PACKAGE_NAME` and `ANDROID_SHA256_CERT_FINGERPRINTS` environment variables to populate the Asset Links manifest.
    - **Validation**: Added unit tests to ensure `assetlinks.json` correctly reflects provided fingerprints or returns an empty array when unset.

- **Testing**:
    - Add `AuthViewModelTest` and `LoginCredentialCoordinatorTest` to verify that credentials are only saved on success and only requested under appropriate UI states (e.g., not while typing or loading).
@deepsource-io
Copy link
Copy Markdown

deepsource-io Bot commented May 22, 2026

DeepSource Code Review

We reviewed changes in 250e094...3c5046d on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
JavaScript May 22, 2026 7:06a.m. Review ↗
Kotlin May 22, 2026 7:06a.m. Review ↗
Secrets May 22, 2026 7:06a.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.


@Composable
fun TdayApp() {
fun TdayApp(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`TdayApp` has a cyclomatic complexity of 16 with "High" risk


Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A function with high cyclomatic
complexity can be hard to understand and maintain. A higher cyclomatic
complexity indicates that the function has more decision points and is more complex.

@@ -38,20 +38,36 @@ internal fun extractApiErrorMessage(response: Response<*>, fallback: String): St
}

internal fun isLikelyConnectivityIssue(error: Throwable): Boolean {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`isLikelyConnectivityIssue` has a cyclomatic complexity of 23 with "High" risk


Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A function with high cyclomatic
complexity can be hard to understand and maintain. A higher cyclomatic
complexity indicates that the function has more decision points and is more complex.

)

suspend fun restoreSession(): SessionUser? {
return restoreSessionFromServer()?.also(::cacheSessionUser)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Functions with exact one statement, the return statement, can be rewritten with ExpressionBodySyntax.


Functions which only contain a return statement can be collapsed to an expression body. This shortens the code and makes it more readable.


@Module
@InstallIn(SingletonComponent::class)
abstract class SystemCredentialModule {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An abstract class without a concrete member can be refactored to an interface.


When an abstract class does not have any concrete members, it should be refactored into an interface. Similarly, if an abstract class does not define any abstract members, it should be refactored into a concrete class. This refactoring promotes better code organization, readability, and adherence to Kotlin language conventions.

Comment on lines +104 to +111
} catch (error: CreateCredentialException) {
Log.w(
LOG_TAG,
"Android Password Manager could not save credential: ${error.type}",
error
)
SystemCredentialSaveResult.FAILED
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This catch block is unreachable.


Unreachable catch blocks should be removed, because they serve no useful purpose and can lead to confusing and potentially incorrect behavior in exception handling.

}
}

private fun toFriendlyMessage(message: String?): String {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`toFriendlyMessage` has a cyclomatic complexity of 22 with "High" risk


Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A function with high cyclomatic
complexity can be hard to understand and maintain. A higher cyclomatic
complexity indicates that the function has more decision points and is more complex.


@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun CompletedScreen(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`CompletedScreen` has a cyclomatic complexity of 18 with "High" risk


Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A function with high cyclomatic
complexity can be hard to understand and maintain. A higher cyclomatic
complexity indicates that the function has more decision points and is more complex.


@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun OnboardingWizardOverlay(
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

`OnboardingWizardOverlay` has a cyclomatic complexity of 63 with "Critical" risk


Cyclomatic complexity is a software metric that measures the number of
independent paths through a function. A function with high cyclomatic
complexity can be hard to understand and maintain. A higher cyclomatic
complexity indicates that the function has more decision points and is more complex.

@ohmzi ohmzi closed this May 22, 2026
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.

2 participants