Skip to content

ibitton/flutter-task-tracker

Repository files navigation

Flutter Task Tracker

A polished, offline-first task tracker built with Flutter, showcasing clean architecture, reactive data flow, and thoughtful UX design. This is a portfolio project demonstrating senior-level Flutter development practices.


Purpose

A task management app that prioritizes simplicity and speed. Designed for users who want to quickly capture tasks, organize them with tags, and track completion without friction.

Key Principles:

  • Offline-first: All data stored locally via SQLite (Drift)
  • Reactive: Real-time updates as tasks change
  • Responsive: Adaptive layout for phones and tablets
  • Polished: Smooth animations and thoughtful interactions

Architecture Overview

lib/
├── core/                    # Routing, theming, constants
├── domain/                 # Business logic (pure Dart)
│   ├── tasks/             # Task model, filters, lifecycle
│   └── tags/              # Tag repository interface
├── data/                   # Data layer
│   ├── database/          # Drift schema & provider
│   ├── tasks/             # Task repository implementations
│   └── tags/             # Tag repository implementations
└── features/             # UI layer
    ├── tasks/            # Task list, editor, detail view
    └── tags/            # Tag input field

Data Flow

flowchart TD
    A[UI Widgets] -->|watch| B[Riverpod Providers]
    B -->|query| C[Repository]
    C -->|watchAll| D[Drift Database]
    D -->|Stream| C
    C -->|Stream| B
    B -->|notify| A
Loading
  1. UI watches providers via ref.watch()
  2. Providers query repositories for data streams
  3. Repositories return Stream<T> from Drift
  4. Drift emits updates on database changes
  5. UI rebuilds automatically with new data

State Management: Riverpod

Why Riverpod?

  • Compile-safe: No runtime exceptions from missing providers
  • Testable: Easy to override with fakes in tests
  • Reactive: Built-in stream support for real-time updates
  • Scoped: Providers live with the widget tree, no global state

Pattern Used:

// Repository provider (injected)
final taskRepositoryProvider = Provider<TaskRepository>((ref) => ...);

// Stream provider (reactive)
final allTasksProvider = StreamProvider<List<Task>>((ref) {
  return ref.watch(taskRepositoryProvider).watchAll();
});

// Filtered provider (derived state)
final filteredTasksProvider = Provider<AsyncValue<List<Task>>>((ref) {
  final filter = ref.watch(taskFilterProvider);
  final tasks = ref.watch(allTasksProvider);
  return tasks.whenData((list) => filter.apply(list));
});

Key Features

Task Management

  • Create, edit, delete tasks with title, description, dates, and tags
  • Lifecycle states: Active, Scheduled, Completed
  • Due date buckets: Overdue, Today, Upcoming
  • Multi-tag filtering: AND logic for precise filtering

Adaptive Layout

Screen Size Layout
< 700px Single pane with navigation
>= 700px Split view: list (380px) + detail pane

Animations

  • Completion bounce: Scale animation on checkmark (1.0 → 1.3 → 1.0)
  • Strikethrough: Smooth text decoration transition
  • Selection indicator: Primary color left border on selected task

Trade-offs & Decisions

Decision Rationale
Drift over Hive/Isar Stronger architectural signal (SQL + migrations), reactive streams built-in
No undo snackbar Filter change already provides visual feedback; keeps UI uncluttered
No swipe gestures Tap + toggle is faster and more accessible
Selection clears on filter Selection coherence: only show what's in the current list
In-memory repos kept Useful for widget tests (no DB setup) and validates interface design
No cloud sync Scope control: offline-first keeps complexity manageable

Testing

flutter test

Coverage:

  • 96 tests across 13 test files
  • Unit tests: domain logic (filters, lifecycle)
  • Integration tests: Drift repositories with in-memory SQLite
  • Widget tests: screens, animations, user flows

Test Philosophy:

  • Fakes over mocks for repositories (test behavior, not implementation)
  • Async providers replay initial state immediately (no pumpAndSettle delays)
  • Riverpod overrideWithValue for dependency injection in tests

What I'd Build Next

  1. Local Notifications: Reminders for due dates using flutter_local_notifications
  2. Import/Export: JSON backup for data portability
  3. Dark Mode Polish: System-aware theme switching with persistence
  4. Recurring Tasks: Weekly/monthly task templates

Technical Stack

Layer Technology
State Management Riverpod
Routing go_router
Database Drift (SQLite)
Local Storage path_provider
Code Generation build_runner, freezed, drift_dev
Testing flutter_test, flutter_riverpod

Phone Layout

  • Task list with filters
  • Task editor
  • Empty states

Tablet Layout (Split View)

  • List + detail side by side
  • Selection indicator
  • Real-time filter changes

Getting Started

# Install dependencies
flutter pub get

# Generate code (Drift, Freezed, Riverpod)
flutter pub run build_runner build --delete-conflicting-outputs

# Run tests
flutter test

# Run app
flutter run

Project Structure Deep Dive

lib/
├── core/
│   └── routing/
│       ├── app_router.dart       # go_router configuration
│       └── app_routes.dart       # Route constants
│
├── domain/
│   └── tasks/
│       ├── task.dart             # Freezed model with lifecycle
│       ├── task_filter.dart      # Filtering logic (AND composition)
│       ├── task_lifecycle.dart   # Active/Scheduled/Completed logic
│       └── task_repository.dart  # Abstract interface
│
├── data/
│   ├── database/
│   │   ├── database.dart         # Drift schema (Tasks, Tags tables)
│   │   └── database_provider.dart
│   ├── tasks/
│   │   ├── drift_task_repository.dart    # SQLite implementation
│   │   └── in_memory_task_repository.dart # Test fake
│   └── tags/
│       ├── drift_tag_repository.dart
│       └── in_memory_tag_repository.dart
│
└── features/
    └── tasks/
        ├── presentation/
        │   ├── adaptive_task_list_screen.dart  # Split/narrow logic
        │   ├── task_detail_view.dart           # Right pane content
        │   ├── task_editor_screen.dart         # Create/edit form
        │   ├── task_list_screen.dart           # Narrow layout list
        │   └── widgets/
        │       ├── animations.dart             # Completion bounce
        │       └── task_list_item.dart         # List tile with swipe
        └── state/
            ├── task_filter_notifier.dart       # Filter state
            └── task_providers.dart             # Riverpod providers

License

MIT - Use as a reference for your own Flutter projects.


Contact

Built as a portfolio piece. Questions or feedback welcome!

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors