# Carry Your Live - Mobile To-Do & Calendar App

A minimalist, offline-first task management app built with Expo, React Native, and WatermelonDB. Features three primary screens: To-Do List, Add New Task, and Calendar with bottom navigation.

## Features

### Core Functionality
- **Offline-First Architecture**: Full CRUD operations work offline with WatermelonDB + SQLite
- **Auto-Sync**: Background synchronization with custom Postgres API when online
- **Cross-Platform**: iOS, Android, and Web from single codebase

### Screens

#### 1. To-Do List Screen
- **Header**: App logo + "TODO" title with rounded corners
- **Category Filter**: Horizontal scrollable chips (Work, Personal, School, Shopping, Health, Finance, All)
  - Single selection with visual feedback (thicker border, shadow, scale animation)
  - Instant task filtering
- **Task List**: Vertical scrolling with:
  - Checkbox (empty/checked states with animation)
  - Task title (truncated with ellipsis)
  - Three-dot overflow menu (Edit, Delete, Duplicate, Mark Complete, Change Category, Change Priority)
  - Priority badges with colors
  - Due date/time with overdue/due-today highlighting
  - Completed section (collapsible)
- **Floating Action Button**: Bottom-right, opens Add Task screen with press animation

#### 2. Add New Task Screen
- **Category Selector**: Horizontal row of colored circles (required)
- **Task Name**: Single-line input, 100 char max (required)
- **Subtasks**: Unlimited, add/remove individually
- **Date & Time**: Date picker, time picker, calendar button
- **Priority**: Dropdown (None, Low, Medium, High, Critical) with color indicators
- **Description**: Multi-line text area, 1000 char max
- **Bottom Actions**: Submit (primary) / Cancel (secondary) fixed buttons

#### 3. Calendar Screen
- **Date Strip**: Horizontal scrollable days of current month
- **Month Label**: Centered (e.g., "JAN 2026")
- **Task List**: Tasks for selected day with category color, title, time, completion status
- **Empty State**: "No tasks scheduled."

#### 4. Settings Screen
- Dark Mode toggle
- Push Notifications toggle
- Reminder Preferences
- Default Category selector
- Sort Tasks By (Date, Priority, Alphabetically, Creation Date)
- Backup & Sync
- Version, Privacy Policy, Terms of Service

### Task States
- **Pending**: Empty checkbox, normal text
- **Completed**: Checked checkbox, strikethrough, reduced opacity
- **Overdue**: Red due date, warning indicator
- **Due Today**: Blue highlight
- **High Priority**: Priority badge

### Interactions
- Tap task → Edit screen
- Long press → Selection mode (multi-delete, multi-complete, change category/priority)
- Swipe left → Delete
- Swipe right → Complete
- Pull down → Refresh

## Tech Stack

| Layer | Technology |
|-------|------------|
| Framework | Expo (React Native) |
| Language | TypeScript |
| Navigation | Expo Router (file-based) |
| Database | WatermelonDB + SQLite |
| State | WatermelonDB (reactive queries, no Redux needed) |
| Forms | React Hook Form + Zod validation |
| UI Components | React Native Paper + Custom SVG icons |
| Animations | React Native Reanimated |
| Date/Time | @react-native-community/datetimepicker + date-fns |
| Build | EAS Build / Gradle (local APK) |
| CI/CD | Gitea Actions (`.gitea/workflows/build-apk.yml`) |

## Project Structure

```
carry-your-live/
├── app/
│   ├── _layout.tsx              # Root layout + DatabaseProvider
│   ├── (tabs)/
│   │   ├── _layout.tsx          # Bottom tab navigator
│   │   ├── index.tsx            # Tasks screen
│   │   ├── calendar.tsx         # Calendar screen
│   │   └── settings.tsx         # Settings screen
│   └── add-task.tsx             # Add Task screen
├── src/
│   ├── components/              # Reusable UI components
│   │   ├── Header.tsx
│   │   ├── CategoryFilter.tsx
│   │   ├── TaskList.tsx
│   │   ├── TaskItem.tsx
│   │   ├── FloatingActionButton.tsx
│   │   ├── TabBarIcon.tsx
│   │   ├── CategorySelector.tsx
│   │   ├── TaskNameInput.tsx
│   │   ├── SubtasksSection.tsx
│   │   ├── DateTimePicker.tsx
│   │   ├── PrioritySelector.tsx
│   │   ├── DescriptionInput.tsx
│   │   ├── FormButtons.tsx
│   │   └── ListItem.tsx
│   ├── database/
│   │   ├── schema.ts            # WatermelonDB schema
│   │   ├── index.ts             # Database instance + collections
│   │   └── sync.ts              # Custom API sync adapter
│   ├── models/
│   │   ├── Task.ts
│   │   ├── Category.ts
│   │   └── Subtask.ts
│   ├── hooks/
│   │   ├── useDatabase.tsx      # Database context & providers
│   │   └── useTasks.tsx         # Task queries with reactive state
│   ├── constants/
│   │   └── index.ts             # Categories, priorities, colors
│   └── types/
│       └── index.ts             # TypeScript interfaces
```

## Data Models

### Task
```typescript
{
  id: string;
  title: string;
  description: string;
  categoryId: string;
  priority: 'none' | 'low' | 'medium' | 'high' | 'critical';
  completed: boolean;
  dueDate: number;        // timestamp
  dueTime: string;        // "HH:MM"
  createdAt: Date;
  updatedAt: Date;
  subtasks: Subtask[];
}
```

### Category
```typescript
{
  id: string;
  name: string;
  color: '#HEX';
  order: number;
}
```

### Subtask
```typescript
{
  id: string;
  taskId: string;
  title: string;
  completed: boolean;
  order: number;
  createdAt: Date;
  updatedAt: Date;
}
```

## Default Categories
| Name | Color | Order |
|------|-------|-------|
| Work | #E53935 (Red) | 0 |
| Personal | #43A047 (Green) | 1 |
| School | #1E88E5 (Blue) | 2 |
| Shopping | #FB8C00 (Orange) | 3 |
| Health | #8E24AA (Purple) | 4 |
| Finance | #FDD835 (Yellow) | 5 |

## Priority Colors
| Priority | Color |
|----------|-------|
| None | #9E9E9E |
| Low | #43A047 |
| Medium | #FB8C00 |
| High | #E53935 |
| Critical | #B71C1C |

## Getting Started

### Prerequisites
- Node.js 20+
- npm or yarn
- Expo CLI (`npm install -g expo-cli`)
- iOS Simulator (Mac) / Android Studio for mobile testing

### Installation
```bash
cd carry-your-live
npm install
```

### Development
```bash
# Start Expo dev server
npx expo start

# Run on specific platform
npx expo start --ios
npx expo start --android
npx expo start --web
```

### Building

#### EAS Build (cloud)
```bash
# Install EAS CLI
npm install -g eas-cli

# Configure project
eas build:configure

# Build for platforms
eas build --platform ios
eas build --platform android
eas build --platform web
```
Profiles are defined in `eas.json` (`development`, `preview`, `production`; production auto-increments version code).

#### Gradle (local Android APK)
The native Android project lives in `carry-your-live/android/`. Requires JDK 17+ and the Android SDK (platform 35, build-tools 35.0.0, NDK 27.1).

```bash
cd carry-your-live/android

# Debug APK (unsigned)
./gradlew assembleDebug

# Release APK (currently signed with the debug keystore)
./gradlew assembleRelease
```
Output:
```
android/app/build/outputs/apk/debug/app-debug.apk
android/app/build/outputs/apk/release/app-release.apk
```
Key notes:
- The debug keystore (`android/app/debug.keystore`) is generated by the CI pipeline and must exist for release builds — create it locally with the same command used in the pipeline (see below) if it's missing.
- Release builds use `signingConfig signingConfigs.debug` until a production keystore is configured.
- Versions are set in `android/app/build.gradle` (`versionCode`, `versionName`).

## CI/CD Pipeline (Gitea Actions)

`.gitea/workflows/build-apk.yml` builds a release APK on every push to `main` (also manually triggerable via workflow_dispatch):

1. **Checkout** and setup Node 22, JDK 17 (Temurin)
2. **Android SDK**: installs cmdline-tools, licenses, platform-tools, `platforms;android-35`, `build-tools;35.0.0`, `ndk;27.1.12297006`
3. **JS deps**: `npm ci` in `carry-your-live/`
4. **Debug keystore**: generates `carry-your-live/android/app/debug.keystore` with `keytool` (alias `androiddebugkey`, passwords `android`)
5. **Build**: `./gradlew assembleRelease` in `carry-your-live/android/`
6. **Upload**: the APK is saved as the `carry-your-live-release` artifact (downloadable from the run's artifacts page)

To run the build locally exactly as CI does:

```bash
keytool -genkeypair -v \
  -keystore carry-your-live/android/app/debug.keystore \
  -alias androiddebugkey -storepass android -keypass android \
  -keyalg RSA -keysize 2048 -validity 10000 \
  -dname "CN=Android Debug,O=Android,C=US"
cd carry-your-live/android && ./gradlew assembleRelease
```

## Sync API Specification

The app expects a custom API at `http://localhost:3000/api` (configurable in `src/database/sync.ts`):

### Pull Changes
```
GET /sync?since={timestamp}
```
Response:
```json
{
  "categories": [{ "id", "name", "color", "order", "createdAt", "updatedAt" }],
  "tasks": [{ "id", "title", "description", "categoryId", "priority", "completed", "dueDate", "dueTime", "createdAt", "updatedAt" }],
  "subtasks": [{ "id", "taskId", "title", "completed", "order", "createdAt", "updatedAt" }],
  "timestamp": 1234567890
}
```

### Push Changes
```
POST /sync/push
```
Body:
```json
{
  "changes": {
    "categories": [...],
    "tasks": [...],
    "subtasks": [...]
  },
  "lastPulledAt": 1234567890
}
```

## Configuration

### Environment Variables
Create `.env` file:
```
EXPO_PUBLIC_API_URL=http://your-api-url/api
```

### App Config
Modify `app.json` for:
- App name, slug, version
- Icon, splash screen
- Permissions (notifications, etc.)
- Orientation, theme

## Visual Style Guide

- **Background**: White (#FFFFFF)
- **Primary Accent**: #E53935 (Pink/Red)
- **Typography**: Black (#212121) primary, #757575 secondary, #9E9E9E tertiary
- **Borders**: Thin (#E0E0E0), selected #E53935
- **Radius**: 16-20px for cards/buttons/inputs
- **Spacing**: 8px grid system
- **Shadows**: Minimal (elevation 1-3)
- **Animations**: 150-250ms, cubic easing

## Offline-First Architecture

```
┌─────────────┐     ┌──────────────┐     ┌─────────────┐
│   Expo App  │────▶│ WatermelonDB │────▶│  Your API   │
│ (iOS/Android│     │  (SQLite)    │     │  (Postgres) │
│    Web)     │◀───▶│  + Sync      │◀───▶│             │
└─────────────┘     └──────────────┘     └─────────────┘
```

1. All writes go to local SQLite first
2. Reactive queries update UI instantly
3. Background sync pushes/pulls changes
4. Conflict resolution: last-write-wins (customizable)

## Contributing

1. Follow existing code conventions
2. Use TypeScript strict mode
3. Write components with React Hook Form + Zod
4. Use WatermelonDB decorators for models
5. Test offline scenarios

## License

MIT