Skip to content

Conversation

@kodjima33
Copy link
Collaborator

Summary

  • Added Tomorrow category between Today and No Deadline
  • Tasks with due dates for tomorrow now appear in their own section
  • Updated both mobile and desktop versions
  • Dragging a task to Tomorrow sets the deadline to tomorrow at 11:59 PM

Test plan

  • Verify tasks due tomorrow appear in Tomorrow section
  • Test drag-and-drop to Tomorrow category sets correct deadline
  • Check desktop version matches mobile

🤖 Generated with Claude Code

- Added Tomorrow category between Today and No Deadline
- Tasks due tomorrow are now shown in their own section
- Updated both mobile and desktop versions
- Drag a task to Tomorrow sets deadline to tomorrow 11:59 PM

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@kodjima33 kodjima33 merged commit acdf4f8 into main Dec 29, 2025
1 check passed
@kodjima33 kodjima33 deleted the feat/tasks-tomorrow-category branch December 29, 2025 07:41
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request successfully adds the 'Tomorrow' category for tasks on both mobile and desktop versions. The logic for categorizing tasks and setting default due dates appears correct.

However, I've identified significant code duplication between the mobile (action_items_page.dart) and desktop (desktop_actions_page.dart) implementations. Several methods and the TaskCategory enum are duplicated, which will make future maintenance more difficult and error-prone. My main feedback is to refactor this shared logic into a common location, such as a mixin, to improve code reuse and maintainability. Please see my detailed comment.

import 'package:omi/ui/atoms/omi_button.dart';

enum TaskCategory { today, noDeadline, later }
enum TaskCategory { today, tomorrow, noDeadline, later }
Copy link
Contributor

Choose a reason for hiding this comment

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

high

There is significant code duplication between this file and app/lib/pages/action_items/action_items_page.dart. The TaskCategory enum, and the methods _categorizeItems, _getCategoryTitle, _getDefaultDueDateForCategory, and _updateTaskCategory are nearly identical in both files.

This duplication makes the code harder to maintain. Any future changes to task categorization logic will need to be applied in two places, increasing the risk of inconsistencies and bugs.

To resolve this, I recommend extracting the shared logic into a mixin. This will promote code reuse and ensure that both the mobile and desktop views share the same business logic for handling task categories.

Here's an example of how this could be structured:

// In a new shared file, e.g., 'app/lib/features/action_items/task_categorization_mixin.dart'
import 'package:flutter/material.dart';
import 'package:omi/backend/schema/schema.dart';
import 'package:omi/providers/action_items_provider.dart';
import 'package:provider/provider.dart';

enum TaskCategory { today, tomorrow, noDeadline, later }

mixin TaskCategorization<T extends StatefulWidget> on State<T> {
  Map<TaskCategory, List<ActionItemWithMetadata>> categorizeItems(
      List<ActionItemWithMetadata> items, bool showCompleted) {
    final now = DateTime.now();
    final startOfTomorrow = DateTime(now.year, now.month, now.day + 1);
    final startOfDayAfterTomorrow = DateTime(now.year, now.month, now.day + 2);
    final sevenDaysAgo = now.subtract(const Duration(days: 7));

    final Map<TaskCategory, List<ActionItemWithMetadata>> categorized = {
      for (var category in TaskCategory.values) category: [],
    };

    for (var item in items) {
      // Only show items that match the completion status filter.
      if (item.completed != showCompleted) continue;

      // Skip old tasks without a future due date (only for non-completed)
      if (!showCompleted) {
        if (item.dueAt != null) {
          if (item.dueAt!.isBefore(sevenDaysAgo)) continue;
        } else {
          if (item.createdAt != null && item.createdAt!.isBefore(sevenDaysAgo)) continue;
        }
      }

      if (item.dueAt == null) {
        categorized[TaskCategory.noDeadline]!.add(item);
      } else {
        final dueDate = item.dueAt!;
        if (dueDate.isBefore(startOfTomorrow)) {
          categorized[TaskCategory.today]!.add(item);
        } else if (dueDate.isBefore(startOfDayAfterTomorrow)) {
          categorized[TaskCategory.tomorrow]!.add(item);
        } else {
          categorized[TaskCategory.later]!.add(item);
        }
      }
    }
    return categorized;
  }

  String getCategoryTitle(TaskCategory category) {
    switch (category) {
      case TaskCategory.today:
        return 'Today';
      case TaskCategory.tomorrow:
        return 'Tomorrow';
      case TaskCategory.noDeadline:
        return 'No Deadline';
      case TaskCategory.later:
        return 'Later';
    }
  }

  DateTime? getDefaultDueDateForCategory(TaskCategory category) {
    final now = DateTime.now();
    switch (category) {
      case TaskCategory.today:
        return DateTime(now.year, now.month, now.day, 23, 59);
      case TaskCategory.tomorrow:
        return DateTime(now.year, now.month, now.day + 1, 23, 59);
      case TaskCategory.noDeadline:
        return null;
      case TaskCategory.later:
        // Day after tomorrow
        return DateTime(now.year, now.month, now.day + 2, 23, 59);
    }
  }

  void updateTaskCategory(ActionItemWithMetadata item, TaskCategory newCategory) {
    final provider = Provider.of<ActionItemsProvider>(context, listen: false);
    final newDueDate = getDefaultDueDateForCategory(newCategory);
    provider.updateActionItemDueDate(item, newDueDate);
  }
}

You can then apply this mixin to both DesktopActionsPageState and _ActionItemsPageState and remove the duplicated code from them.

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