A Pomodoro-style productivity app built with React Native + Expo. Create tasks, run timed focus sessions, track streaks and stats β all stored locally on your device with full dark mode support.
app.demo.mp4
Add your screenshots here after final build
- Create, edit and delete focus tasks
- Mark tasks complete with animated checkbox
- Filter by All / Active / Done
- Session count per task
- Animated card entrance on load
- Time-based greeting (morning / afternoon / evening)
- Pomodoro countdown with animated progress ring
- Duration picker β 15 / 25 / 50 min or custom (1β180 min)
- Pause, Resume and Reset controls
- Auto 5-minute break mode after each session
- Background timer β stays accurate when app is minimised
- Haptic feedback on every interaction
- Push notification when session ends (real APK build only)
- Sessions and minutes tracked today
- Daily streak counter with motivational banner
- 7-day bar chart of focus sessions
- All-time total focus hours and sessions
- Recent session history list (last 20)
- Stats update in real time after every session
- Dark mode / Light mode / System theme toggle
- Persistent theme preference saved to device
- App info and how-it-works guide
| Layer | Technology |
|---|---|
| Framework | React Native 0.74 (Expo SDK 51 managed workflow) |
| Navigation | React Navigation v6 (Bottom Tabs + Stack) |
| Storage | @react-native-async-storage/async-storage |
| Notifications | expo-notifications |
| Haptics | expo-haptics |
| Theme System | React Context API (light / dark / system) |
| Build Tool | EAS Build (Expo Application Services) |
| Language | JavaScript ES2022 |
FocusTimer/
βββ App.js # Entry point with providers
βββ app.json # Expo config + build settings
βββ eas.json # EAS build profiles
βββ assets/
β βββ icon.png # App icon (1024Γ1024)
β βββ notification-icon.png # Notification icon (white, 96Γ96)
β βββ splash-icon.png # Splash screen
β βββ adaptive-icon.png # Android adaptive icon
βββ src/
βββ context/
β βββ ThemeContext.js # Dark/light/system theme context
β βββ TimerContext.js # Timer context
βββ navigation/
β βββ RootNavigator.js # Tab + stack navigation setup
βββ screens/
β βββ TasksScreen.js # Task list with filters + animations
β βββ TimerScreen.js # Pomodoro timer with progress ring
β βββ StatsScreen.js # Session stats + 7-day chart
β βββ SettingsScreen.js # Theme toggle + app info
βββ components/
β βββ TaskCard.js # Animated task card with edit/delete
β βββ AddTaskModal.js # Bottom sheet to add tasks
β βββ EditTaskModal.js # Bottom sheet to edit tasks
β βββ EmptyState.js # Empty list placeholder
βββ storage/
β βββ index.js # All AsyncStorage CRUD helpers
βββ services/
β βββ notifications.js # Push notification setup + handlers
βββ theme/
βββ index.js # Colors, spacing, typography, shadows
- Node.js 18+
- Expo Go app on your Android device
- Both device and laptop on the same WiFi
# Clone the repository
git clone https://github.com/yourusername/FocusTimer.git
# Navigate into the project
cd FocusTimer
# Install dependencies
npm install# Start the development server
npx expo start
# Scan the QR code with Expo Go on your Android phone
# The app hot-reloads every time you save a file# Android only
npx expo start --android
# iOS only
npx expo start --ios
# Web (limited β no haptics/notifications)
npx expo start --webWe use EAS Build (Expo Application Services) to generate real APK/IPA files. Builds run on Expo's cloud servers β no Android Studio or Xcode needed.
# Install EAS CLI globally
npm install -g eas-cli
# Login to your Expo account (create one free at expo.dev)
eas login
# Configure EAS for this project (run once)
eas build:configure# Preview build β fast, for testing on real device (~68MB)
# Generates a downloadable APK link
eas build -p android --profile preview
# Production build β optimised, smaller (~20MB), for Play Store
eas build -p android --profile production
# Check build status / download link
eas build:list# Preview build β requires Apple Developer account ($99/year)
eas build -p ios --profile preview
# Production build β for App Store submission
eas build -p ios --profile productionAfter the build finishes EAS gives you a download link. Either:
- Open the link on your phone browser β download β install
- Or run:
eas build:run -p android(installs via USB)
Note: When installing outside the Play Store, Android will ask to allow installs from unknown sources. Go to Settings β Security β enable it.
Notifications require a real device build (not Expo Go). They are already configured β just build the APK and they work automatically.
The notification channel is set up in src/services/notifications.js:
- Channel name:
Focus Timer - Priority: MAX
- Vibration pattern: enabled
- Sound: enabled
For the notification icon, add a white PNG at assets/notification-icon.png (96Γ96, transparent background) and reference it in app.json:
"plugins": [
["expo-notifications", {
"icon": "./assets/notification-icon.png",
"color": "#6C63FF"
}]
]Context API for theming
A ThemeContext wraps the entire app providing colors, isDark, and setTheme to every component. Theme preference persists to AsyncStorage so it survives app restarts.
AsyncStorage with typed wrappers
All storage logic lives in src/storage/index.js with named exports (getTasks, addTask, editTask, deleteTask, addSession, getStreak etc). Screens never call AsyncStorage directly β easy to swap to MMKV later.
Background timer via AppState
When the app is backgrounded we record Date.now(). On foreground return we subtract elapsed time from the countdown β the timer stays accurate even if the phone locks for 20 minutes.
Task edit syncs sessions
When you rename a task, editTask() also updates taskTitle in all stored sessions for that task β so Stats always shows the current name.
EAS Build for notifications
expo-notifications requires a development build for full Android notification support. Expo Go removed push notification support in SDK 53+. We use eas build --profile preview to generate a real APK with proper notification channels.
{
"expo": "~51.0.0",
"react": "18.2.0",
"react-native": "0.74.5",
"@react-navigation/native": "^6.0.0",
"@react-navigation/bottom-tabs": "^6.0.0",
"@react-navigation/stack": "^6.0.0",
"@react-native-async-storage/async-storage": "^1.0.0",
"react-native-gesture-handler": "^2.0.0",
"react-native-screens": "^3.0.0",
"react-native-safe-area-context": "^4.0.0",
"expo-haptics": "^13.0.0",
"expo-notifications": "^0.28.0",
"expo-device": "^6.0.0",
"eas-cli": "latest"
}Built by Zain.
- GitHub: @mzaintariqdev
- LinkedIn: Zain Tariq
MIT β free to use and modify.