Skip to content

Enhance task priority visualization, UI layout, and animations#79

Merged
ohmzi merged 19 commits into
masterfrom
develop
May 27, 2026
Merged

Enhance task priority visualization, UI layout, and animations#79
ohmzi merged 19 commits into
masterfrom
develop

Conversation

@ohmzi
Copy link
Copy Markdown
Owner

@ohmzi ohmzi commented May 27, 2026

No description provided.

ohmzi added 19 commits May 25, 2026 13:32
This update introduces distinct iconography for different task priority levels and reorders category tiles on the Home screen across both Android and iOS. Priority markers now distinguish between "medium" and "high/urgent" tasks using specific icons instead of a single binary flag.

- **Priority Visualization**:
    - Implement `priorityIconFor` (Android) and `priorityIndicatorSymbolName` (iOS) to provide tiered icons: `PriorityHigh`/`exclamationmark.circle.fill` for high/urgent/important levels and `Flag` for medium.
    - Update task rows in Home, Todo List, Calendar, and Completed screens to display these specific priority indicators.
    - Expand color logic to consistently handle "urgent" and "important" priority strings.
    - Refactor task metadata layout to group list and priority icons within horizontal containers (`Row`/`HStack`) with standard spacing.

- **Home Screen Refinement**:
    - Reorder category tiles to prioritize "Scheduled" and "Priority" on the top row, moving "Overdue" to the second row alongside "All".
    - Standardize tile colors and watermark icons across platforms for better visual consistency.

- **Technical Refactoring**:
    - Replace boolean `isHighPriority` checks with optional icon lookups to support multiple priority states.
    - Ensure case-insensitive and trimmed string comparison for priority parsing on both platforms.
    - Update `buildScheduledSections` in `TodoListScreen` to handle priority and list modes with explicit logic branches.
…forms

Synchronize the UI color scheme by updating hex values for home categories and list accents. This change standardizes color keys across Android and iOS, shifts the default list color, and adjusts the visual weight of list containers.

- **Color Palette Refresh**:
    - Update hex codes for home categories (Scheduled, Priority, Overdue, All, Completed, and Calendar) with a refined color set.
    - Update the global list accent colors with new hex values across all feature screens (Home, Todos, Completed, Calendar) and task creation components.

- **List Color Logic**:
    - Change the default list color key from `BLUE` to `PINK`.
    - Implement color normalization to map legacy or alternative keys like `GREEN` to `LIME` and `GRAY` to `SLATE`.
    - Reorder and update list color option definitions for consistency between Android and iOS.

- **UI & Presentation**:
    - Adjust list container color blending weight (lerp/blending amount) to `0.66` to enhance list item background prominence.
    - Ensure fallback colors for list accents match the new `PINK` default.
Refine drag-and-drop logic in Todo and Calendar screens to prevent invalid drops on the current due date and improve visual feedback across Android and iOS.

- **Validation & Logic**:
    - Implement `canDropTodoInTimelineSection` and `calendarTaskAlreadyDueOnDate` to filter out drop targets that match a task's existing due date.
    - Update drop target detection to ignore ineligible sections/dates during active drags.
    - Ensure both in-app drags and system-level drag-and-drop events (from external sources) respect these validation rules.

- **UI/UX Enhancements**:
    - Disable drop target highlights and placeholders when hovering over the task's original section or date.
    - Android: Refactor `TodoListScreen` and `CalendarScreen` to use unified drop target filtering in `updateActiveTimelineDropTarget` and `activeCalendarDropDate`.
    - iOS: Update `TodoTimelineSection` and `CalendarScreen` to use the new `canMoveTodo` and `canMove` validation blocks.
    - Fix an issue where empty timeline sections were unnecessarily forced to a minimum height during certain drag states.

- **State Management**:
    - Centralize drag session state in `TodoTaskDragSession` and `CalendarTaskDragSession` on iOS to ensure consistent validation across different view modifiers.
    - Refined `TodoListViewModel` integration to only trigger rescheduling moves when a valid target date is confirmed.
Introduce the ability to delete custom todo lists from both Android and iOS platforms. This includes a delete button in the list settings sheet and a confirmation dialog to prevent accidental data loss. Additionally, unify and refine UI spacing across the timeline, completed, and calendar screens for a more compact and consistent layout.

- **List Management**:
    - Add `onDeleteList` callback and `showDeleteListConfirmation` state to `TodoListScreen`.
    - Implement `ListSettingsDeleteButton` in the list settings bottom sheet.
    - Add "Delete list" option with a destructive alert dialog in iOS `ListSettingsSheet`.
    - Update `TodoListViewModel` to handle list deletion with optimistic updates.

- **UI & Layout Refinement**:
    - Standardize timeline spacing (e.g., 2dp for same-date tasks, 6dp for date groups) across Android and iOS.
    - Reduce default row heights (58dp to 56dp) and minimal vertical padding for a more compact view.
    - Centralize timeline metrics in `TodoTimelineMetrics` on iOS.
    - Refine section header heights and spacings in `TodoListScreen`, `CompletedScreen`, and `CalendarScreen`.
    - Implement `timelineTaskBottomSpacing` logic to handle dynamic padding between tasks and date dividers.
…ons for completed tasks

This update introduces the ability to delete entire lists and ensures that completed task history maintains its relationship to the parent list. It includes backend database migrations, offline sync support, and UI enhancements across Android and iOS.

- **Backend Changes**:
    - Add `listID` column to the `CompletedTodos` table with associated database migration.
    - Update `ListService` to perform cascading deletions of associated tasks and instances when a list is deleted.
    - Enhance `CompletedTodoService` to support updates and ensure `listID` is captured upon task completion.
    - Refactor `CompletedTodoRoutes` to support targeted deletion by ID and partial updates.

- **Sync & Data Layer**:
    - Implement `DELETE_LIST` mutation kind in `SyncManager` for both Android and iOS.
    - Update `OfflineSyncState` and cache mappers to include `listId` for completed records.
    - Refactor `ListRepository` to support optimistic deletion of lists and their associated tasks/completed items.
    - Migrate Android Room database to version 4 to include `listId` in `cached_completed`.

- **UI & UX Enhancements**:
    - **Android**:
        - Implement `ListDeleteConfirmationDialog` with a custom styled `Dialog`.
        - Update `HomeScreen` to handle list row animations and prevent redundant cascade reveals during deletions.
        - Add "Earlier" section collapsing logic for list-specific views in `TodoListScreen`.
    - **iOS**:
        - Implement `ListDeleteConfirmationOverlay` for list settings.
        - Add spring-animated transitions for list additions and removals on the `HomeScreen`.
        - Ensure navigation pops back to Home when a list is deleted from its detail view.

- **Infrastructure**:
    - Update shared models and API DTOs to include `listID` in completed task responses.
    - Improve idempotency in list deletion endpoints.
Introduce a multi-stage animation sequence for task completion and restoration across Android (Compose) and iOS (SwiftUI). Task rows now transition through discrete phases—checked, struck-through, and fading—with coordinated vertical offsets and alpha shifts for a more polished feel.

- **Animation Refinements**:
    - Implement a 3-step completion sequence: immediate checkmark toggle, delayed animated strike-through (160ms), and a final fade-out with upward translation (360ms delay, 260ms duration).
    - Sync restoration animations in the "Completed" screens to follow a similar multi-stage reversal.
    - Replace standard `TextDecoration.LineThrough` with custom drawing logic (`drawWithContent` in Compose, `overlay` in SwiftUI) to allow for animated strike-through progress.
    - Standardize animation durations using new constants (e.g., `TASK_COMPLETION_FADE_MS`).

- **List & UI Improvements**:
    - Migrate home and calendar task lists to use `animateItem()` for smoother layout transitions during addition/deletion.
    - Update list headers to show date/time subtitles when viewing specific lists, matching the behavior of "All" and "Priority" modes.
    - Add a semi-transparent scrim and click-to-dismiss behavior to the delete confirmation dialog in `TodoListScreen`.

- **Platform Parity**:
    - **iOS**: Create `TodoTimelineTaskTitle` reusable view to handle the new animated strike-through logic.
    - **Android**: Ensure `HomeTodayTaskRow`, `CalendarTodoRow`, and `SwipeTodoRow` all implement the unified animation phases.
…and border

Introduce a `calendarCardChrome` modifier to centralize and refine the visual appearance of calendar cards. This update replaces the basic shadow and background with a more sophisticated design that adapts to light and dark themes.

- **Styling Refinement**:
    - Implement a dual-shadow system using ambient and key shadows for better depth perception.
    - Add a subtle 1dp border (stroke) that adjusts its opacity based on the surface luminance (dark vs. light mode).
    - Centralize card constants including corner radius (24.dp) and shadow elevations.
- **Code Health**:
    - Refactor `CalendarScreen` to use the `calendarCardChrome` extension modifier, reducing duplication in the card composition logic.
Introduce a multi-stage animation sequence for task completion and restoration across Android (Compose) and iOS (SwiftUI). Task rows now transition through discrete phases—checked, struck-through, and fading—with coordinated vertical offsets and alpha shifts for a more polished feel.

- **Animation Refinements**:
    - Implement a 3-step completion sequence: immediate checkmark toggle, delayed animated strike-through (160ms), and a final fade-out with upward translation (360ms delay, 260ms duration).
    - Sync restoration animations in the "Completed" screens to follow a similar multi-stage reversal.
    - Replace standard `TextDecoration.LineThrough` with custom drawing logic (`drawWithContent` in Compose, `overlay` in SwiftUI) to allow for animated strike-through progress.
    - Standardize animation durations using new constants (e.g., `TASK_COMPLETION_FADE_MS`).

- **List & UI Improvements**:
    - Migrate home and calendar task lists to use `animateItem()` for smoother layout transitions during addition/deletion.
    - Update list headers to show date/time subtitles when viewing specific lists, matching the behavior of "All" and "Priority" modes.
    - Add a semi-transparent scrim and click-to-dismiss behavior to the delete confirmation dialog in `TodoListScreen`.

- **Platform Parity**:
    - **iOS**: Create `TodoTimelineTaskTitle` reusable view to handle the new animated strike-through logic.
    - **Android**: Ensure `HomeTodayTaskRow`, `CalendarTodoRow`, and `SwipeTodoRow` all implement the unified animation phases.
Redesign the `ListSettingsSheet` with a modern, custom card-based interface replacing the standard SwiftUI Form. This update significantly expands personalization options and improves the overall user experience.

- **UI & UX Enhancements**:
    - Implement a custom layout with dedicated sections for List name, Color, and Icon.
    - Add a live preview header showing the selected icon and color in a large circular badge.
    - Replace the standard list name field with a centered, bold `TextField` in a custom styled container.
    - Introduce horizontally scrolling pickers for colors and icons using circular swatches with selection indicators.
    - Custom design the "Delete list" button with a bordered, low-opacity error background.
    - Set presentation detents to 80% and configure custom corner radius (34pt) for the bottom sheet.

- **Content & Logic**:
    - Significantly expand the available icon set by adding `todoListSettingsIconKeys` (60+ new icons).
    - Refactor color and icon selection logic to use standardized key mapping and normalization (`normalizedTodoListIconKey`).
    - Improve keyboard behavior with interactive scroll dismissal and keyboard-aware safe area handling.
    - Add haptic feedback to the delete action and improve accessibility labels for all selection options.
…and Android.

This update replaces the previous `animateContentSize` (Android) and simple opacity transitions (iOS) with a coordinated layout system that handles height changes between month, week, and day views more smoothly. It introduces a "below calendar offset" to ensure content following the calendar card moves in sync with height animations, avoiding overlapping or jumping during mode switches.

- **Cross-Platform Layout Sync**:
    - Implement a staged transition logic: when expanding, content below shifts down immediately; when collapsing, the shift is delayed to match the card's animation.
    - Added constants for lead/trail delays (~110-130ms) to fine-tune the feel of the transition.
    - Managed transition state via `calendarLayoutMode` and `belowCalendarOffset` to decouple visual selection from physical layout during animations.

- **iOS (SwiftUI) Improvements**:
    - Replaced conditional `if/else` rendering in `animatedCalendarModeCard` with a `ZStack` containing all modes to prevent layout resets.
    - Added `accessibilityHidden` and `allowsHitTesting` toggles to inactive calendar views.
    - Applied `.offset(y: belowCalendarOffset)` to the task list header, task items, and error views.

- **Android (Compose) Improvements**:
    - Defined explicit height constants (`CalendarMonthModeCardHeight`, `CalendarPeriodModeCardHeight`) for deterministic animations.
    - Replaced `animateContentSize` with explicit `Modifier.height()` animation using `animateDpAsState`.
    - Wrapped mode views in a `ForEach` with alpha animations and `graphicsLayer` for better performance and cross-fading.
    - Applied offset logic to `ErrorRetryCard` and task list items.
…tions

Streamline the calendar view mode transitions in both iOS (SwiftUI) and Android (Compose) by removing complex manual offset calculations and staggered animations.

- **iOS (SwiftUI)**:
    - Remove `calendarLayoutMode`, `belowCalendarOffset`, and associated transition task logic from `CalendarScreen`.
    - Replace the `ZStack` of all calendar modes with a single active view, simplifying the view hierarchy.
    - Remove legacy animation constants and manual delays for view resizing.
    - Clean up logic by passing state directly to `CalendarMonthGrid`, `CalendarWeekGrid`, and `CalendarDayGrid` without conditional activity checks.

- **Android (Compose)**:
    - Replace manual height and offset animations with `Modifier.animateContentSize()` on the calendar card container.
    - Remove `calendarLayoutViewKey`, `belowCalendarOffsetTarget`, and related `animateDpAsState` logic.
    - Remove hardcoded height constants (e.g., `CalendarMonthModeCardHeight`) and transition delay constants.
    - Replace the loop-based `ZStack`-like approach with a direct `when` statement to render only the selected `CalendarViewMode`.
    - Remove `offset(y = belowCalendarOffset)` from the task list and error views, allowing the layout to adjust naturally.
This update improves the smoothness of switching between calendar display modes (e.g., month vs. week) by manually controlling the height transition. It decouples the container resizing from the content updates to prevent layout artifacts during mode changes.

- **Animation & State Management**:
    - Introduce `@State private var calendarCardHeight` to explicitly manage and animate the calendar container's height.
    - Refactor `selectCalendarMode` to update `displayMode` and `visibleMonth` within a transaction that disables animations, preventing internal content flickering.
    - Use `withAnimation` to explicitly trigger the height change for the calendar card.
- **UI Adjustments**:
    - Replace the computed `calendarModeCardHeight` property with the new state variable in the view's frame modifier.
    - Remove implicit `.animation` modifiers from the list and card content to avoid redundant or conflicting animation triggers.
    - Set `transaction.disablesAnimations = true` within the calendar content view to ensure a clean state transition before the height animation occurs.
…Compose) and iOS (SwiftUI) platforms.

### Android (Compose)
- **Shared UI Logic**:
    - Introduce `CollapsingTitleScrollBehavior` and its variants (`rememberLazyListCollapsingTitleScrollBehavior`, `rememberScrollCollapsingTitleScrollBehavior`) to centralize collapsing top bar logic, replacing redundant `NestedScrollConnection` implementations.
    - Introduce `TaskSwipeRevealState` and `animateTaskSwipeOffsetAsState` to encapsulate swipe-to-action logic, state management (hinting, dragging, settling), and constants.
- **Screen Refactors**:
    - Migrate `HomeScreen`, `TodoListScreen`, `CompletedScreen`, `SettingsScreen`, and `LatestReleaseScreen` to use the new shared scroll and swipe behavior utilities.
    - Improve drop target detection in `TodoListScreen` to avoid redundant state updates.

### iOS (SwiftUI)
- **Performance & Optimization**:
    - Centralize `DateFormatter` and `ISO8601DateFormatter` instances within private `enum` containers (e.g., `TodoTimelineFormatters`, `ReleaseDateFormatters`) to prevent expensive re-allocation during list rendering.
    - Refactor `HomeTodayTaskRow` to use a new `.todoTrailingSwipeActions()` modifier, significantly simplifying the view body.
- **UX Refinements**:
    - Improve `SwipeActions` gesture detection by adding a horizontal activation bias and tuning spring animations for a more native feel.
    - Enhance `PullToRefresh` snapping logic with velocity thresholds and smoother spring transitions.
    - Fix a bug where swipe actions remained open when the component was disabled.
… gesture handling

Replaces the SwiftUI `DragGesture` in `SwipeActions` with a custom `UIViewRepresentable` observer that utilizes `UIPanGestureRecognizer`. This change improves gesture reliability and coordination within scroll views by leveraging UIKit's gesture delegate system.

- **Swipe Performance & Logic**:
    - Implement `HorizontalSwipePanObserver` to manage pan gestures via a `Coordinator` attached to the enclosing `UIScrollView`.
    - Define a `gestureRecognizerShouldBegin` logic to strictly enforce horizontal swipe detection, preventing accidental triggers during vertical scrolling.
    - Support simultaneous gesture recognition to ensure the parent scroll view remains responsive.
    - Refactor `SwipeActions` modifier to apply the new observer as a background element.
- **Cleanup**:
    - Remove legacy state variables (`isHorizontalDragging`, `dragStartOffsetX`) and thresholds from the SwiftUI view.
    - Update `onChange` closures to use the modern Swift 5.9+ syntax.
…roid

Introduce a 10-minute cooldown period for offline notices to prevent redundant alerts during frequent connectivity fluctuations.

- **Common Logic**: Added a cooldown mechanism that tracks the last time an offline notice was displayed and suppresses subsequent notices until 10 minutes have elapsed.
- **iOS (SwiftUI)**: Updated `AppViewModel` with `offlineNoticeCooldownSeconds` and a `shouldShowOfflineNotice()` helper to gate `offlineNoticeID` increments.
- **Android (Compose)**: Introduced an `OfflineNoticeCooldown` internal class and integrated it into `AppViewModel` to manage `offlineNoticeId` updates across session bootstrapping and sync operations.
- **Testing**: Added unit tests for `OfflineNoticeCooldown` in Android to verify the 10-minute suppression logic.
…roid

Introduce a 10-minute cooldown period for offline notices to prevent redundant alerts during frequent connectivity fluctuations.

- **Common Logic**: Added a cooldown mechanism that tracks the last time an offline notice was displayed and suppresses subsequent notices until 10 minutes have elapsed.
- **iOS (SwiftUI)**: Updated `AppViewModel` with `offlineNoticeCooldownSeconds` and a `shouldShowOfflineNotice()` helper to gate `offlineNoticeID` increments.
- **Android (Compose)**: Introduced an `OfflineNoticeCooldown` internal class and integrated it into `AppViewModel` to manage `offlineNoticeId` updates across session bootstrapping and sync operations.
- **Testing**: Added unit tests for `OfflineNoticeCooldown` in Android to verify the 10-minute suppression logic.
…bility

This update refines the calendar view's gesture handling and data fetching logic across iOS and Android. It ensures all todo items are loaded into the calendar state and prevents scrolling interference during drag-and-drop operations on iOS.

- **Calendar Data Loading**:
    - Update `CalendarViewModel` (iOS and Android) to fetch todos using `TodoListMode.ALL` (or `.all`) instead of scheduled items only. This affects initial state creation, cache hydration, and manual refresh cycles.

- **iOS UI & Gesture Handling**:
    - Disable scrolling in `CalendarScreen` when an active in-app drag operation is detected (`inAppDrag != nil`).
    - Update the gesture recognizer coordinator to prevent simultaneous recognition with the scroll view's pan gesture, ensuring more reliable drag-and-drop triggers.
Update `CalendarScreen` to set `placementSpec` to null within the item animation configuration. This removes the spring-based placement animation while maintaining the existing fade and duration transitions.
@deepsource-io
Copy link
Copy Markdown

deepsource-io Bot commented May 27, 2026

DeepSource Code Review

We reviewed changes in cd5a026...ddd5f27 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 ↗

Important

Some issues found as part of this review are outside of the diff in this pull request and aren't shown in the inline review comments due to GitHub's API limitations. You can see those issues on the DeepSource dashboard.

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
JavaScript May 27, 2026 4:08p.m. Review ↗
Kotlin May 27, 2026 4:08p.m. Review ↗
Secrets May 27, 2026 4:08p.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.

}

fun revealProgress(offsetX: Float): Float {
return (-offsetX / revealWidthPx).coerceIn(0f, 1f)
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.


@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
fun TodoListScreen(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`TodoListScreen` has a cyclomatic complexity of 136 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.


@OptIn(ExperimentalMaterial3Api::class, ExperimentalFoundationApi::class)
@Composable
fun CalendarScreen(
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

`CalendarScreen` has a cyclomatic complexity of 55 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.

"DEEP_BLUE" -> Color(0xFF6F86C6)
"CORAL" -> Color(0xFFD39A82)
"TEAL" -> Color(0xFF67AAA7)
"SLATE", "GRAY" -> Color(0xFF7F8996)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Multiple occurrences of the same string literal within a single file detected. Prefer extracting the string literal into a property or constant.


Avoiding repeated string literals in the same scope is considered good practice in Kotlin. By using shared constants/variables, one improves code maintainability, readability, consistency, and support for localization efforts. Repeated string literals can make code harder to understand, update, and translate. Using shared constants or variables promotes code consistency and potential performance optimizations.

@ohmzi ohmzi merged commit 32b79b8 into master May 27, 2026
4 of 5 checks passed
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