2026-08-07 01:06:03 +02:00
2026-08-07 01:06:03 +02:00
2026-08-07 01:06:03 +02:00
2026-08-07 01:06:03 +02:00

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

{
  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

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

Subtask

{
  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

cd carry-your-live
npm install

Development

# 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)

# 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).

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:

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:

{
  "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:

{
  "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

S
Description
No description provided
Readme
1.3 MiB
v1.0.0
Latest
2026-08-10 10:27:28 +00:00
Languages
TypeScript 98.3%
JavaScript 1.6%