Commit Graph

9 Commits

Author SHA1 Message Date
Ruben Rosario a35eab35af Fix sync: CreateList action + server ID mapping
- Added SyncAction::CreateList variant
- create_task returns server Task, added create_list API
- Sync engine processes CreateList first, updates IDs in batch
- After Create/CreateList success, local IDs updated to server IDs
2026-06-21 18:14:24 +01:00
Ruben Rosario 5cb8d0cd4e Fix update_task: always set updated_at to now()
Local edits must always update updated_at to the current time.
The task.updated_at field is only relevant for insert_task
(API-synced tasks have a real server timestamp).
2026-06-21 16:20:30 +01:00
Ruben Rosario 27b42d7836 Fix created_at > updated_at for API-synced tasks
Use updated_at as fallback for created_at when no existing row,
so API tasks have created_at <= updated_at.
2026-06-21 16:15:16 +01:00
Ruben Rosario 9839ebe4de Fix ALTER TABLE migration for created_at column
SQLite ALTER TABLE ADD COLUMN does not support DEFAULT expressions,
only literal values. Use DEFAULT '' then UPDATE existing rows.
2026-06-21 16:09:05 +01:00
Ruben Rosario b3dcefcd65 Add created_at/updated_at to Task model, DB, and API
- Add created_at and updated_at fields to Task struct
- Preserve existing created_at on upsert in insert_task
- Parse updated field from Google Tasks API response
- Add created_at column to DB schema with migration
2026-06-21 16:03:40 +01:00
Ruben Rosario 6eee90f128 Add task count to task list panel header
Show 'X todo / Y done' in the Tasks panel title bar.

Also includes prior uncommitted work:
- Pagination in fetch_tasks (maxResults=100 + pageToken loop)
- fetch_tasks_since for incremental pull sync
- SyncStats struct with version/last_sync/last_pull/changed counts
- Periodic push (30s) and pull (5min) sync engine
- event::poll(100ms) for non-blocking UI refresh
- Ctrl+R full sync (push + pull)
- refresh_if_needed() to reload data after background sync
- Retry mechanism (MAX_SYNC_RETRIES=3) for sync queue items
- HTTP status code checks in fetch_lists/fetch_tasks/fetch_tasks_since
- Fix move_task URL to use reqwest query()
- Remove CASCADE via replace_all_lists (use insert_list instead)
- has_pending_sync() to prevent pull during pending push
2026-06-21 14:21:14 +01:00
Ruben Rosario 71befdf9f8 feat(api): google tasks oauth, sync engine, and background worker
- ApiClient with manual OAuth2 Device Flow (no yup-oauth2 dependency)
- Devide auth: POST device/code -> show URL+code -> poll token endpoint
- Token persistence in ~/.config/task_app/token.json
- CRUD: create_task, update_task, delete_task, move_task via Google Tasks API
- fetch_lists and fetch_tasks for initial sync import
- Db wraps Connection in std::sync::Mutex for thread-safe sharing via Arc
- Sync engine: background thread with tokio runtime, processes queue every 30s
- process_sync_queue drains sync_queue and calls API methods
- trigger_sync() called after every local mutation (create/update/delete/reorder)
- Network status propagated to UI (Online/Offline/Syncing)
- Initial sync skeleton ready for full import flow
2026-06-20 19:41:47 +01:00
Ruben Rosario 3626331a70 feat(infra): add sqlite storage with position-based ordering
- Db struct with rusqlite Connection (WAL mode, foreign keys)
- Tables: task_lists, tasks (with position column), sync_queue
- CRUD: get/insert/update/delete for lists and tasks
- reorder_task shifts positions of sibling tasks
- replace_all_lists and replace_all_tasks for sync import
- push_sync and drain_sync for offline queue management
- All reads sorted by position ASC
2026-06-20 19:35:56 +01:00
Ruben Rosario adf3889863 chore: initial project setup
- Cargo init with dependencies (ratatui, crossterm, tokio, reqwest, rusqlite, serde, chrono, dirs)
- Module structure: domain/, ui/, infrastructure/
- Domain models (TaskList, Task, TaskStatus, SyncAction, SyncQueueItem)
- .gitignore for target/ and *.db
- Rustls-based TLS (no OpenSSL dependency)
2026-06-20 19:35:19 +01:00