Skip to content

hellogunawan99/focus-mate

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

13 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Focus Mate icon

Focus Mate

Stay sharp. Don't drift.

An anti-drowsiness focus timer for work and study sessions. Set an interval; when it expires, a math problem blocks the screen. You can't dismiss it without solving the problem β€” so even if you start dozing off, the app forces a periodic cognitive break.

Install Β· Features Β· How it works Β· Architecture Β· Build from source Β· Contributing


✨ Why Focus Mate?

Common focus tools Focus Mate
❌ Play music and hope you don't drift βœ… Forces you to engage every interval
❌ Pomodoro timer with no engagement check βœ… Math challenge to prove you're still with it
❌ Silently buzzes while you doze βœ… Escalates to a continuous alarm if you don't respond
❌ All UI, no follow-through βœ… Unskippable challenges, real cognitive breaks

The science is simple: drowsiness is reversible with a 10-second engagement break. A stretch, a sip of water, or solving a math problem. Focus Mate makes that break non-negotiable and cognitively active β€” perfect for coding sessions, deep work, or study marathons.


πŸ“± Screenshots

Home (idle) Home (focusing) Math challenge
home-idle home-running challenge
Set interval, start session Live countdown with progress ring Math problem to solve
Settings Escalation alarm Editor (custom interval)
settings red pulsing UI + looping alarm scroll wheel + manual editor

πŸš€ Features

🎯 Core

  • Customizable intervals β€” 1 to 240 minutes via scroll wheel or manual editor
  • Math challenge β€” 5 difficulty tiers (single-digit β†’ 3-digit arithmetic) on a 60-second grace period
  • Anti-bypass lock β€” PopScope + wakelock + ongoing notification = can't swipe away or screen-off
  • Foreground service β€” math challenges survive backgrounding, app kill, even device reboot (Android 8+)

πŸ›‘οΈ Escalation

  • 60-second grace period (configurable: 15s/30s/60s/120s) to solve the challenge normally
  • Looping alarm + vibration kicks in if you don't respond β€” continues until you touch the screen
  • Visual urgency β€” red pulsing background overlay + "TOUCH SCREEN" pill + "STOP ALARM & SUBMIT" button
  • Bypasses Do Not Disturb β€” uses USAGE_ALARM audio attribute on Android

πŸ“Š Tracking

  • Today stats β€” focused time, problems solved, alarms triggered
  • Streak counter β€” consecutive days using the app
  • Persistent settings β€” everything in SharedPreferences, survives restart + reboot

🎨 Polish

  • Custom two-tone alarm β€” procedurally generated C5-E5 ascending bell (no copyrighted assets)
  • Aurora animated background β€” soft drifting gradients
  • Plus Jakarta Sans + JetBrains Mono typography
  • Haptic feedback on every interaction
  • Material 3 design language with custom dark theme

🧠 How it works

T = 0          [Start focus session]
                  ↓
T = 0..N       [Live countdown with progress ring]
                  ↓
T = N          [Alert fires, challenge starts]
                  ↓
T = N..N+60    [User has 60s to solve math problem]
                  ↓
T = N+60       [If unsolved: ESCALATION]
                  β”œβ”€ Looping alarm tone (C5-E5)
                  β”œβ”€ Vibration pattern (400ms on, 200ms off)
                  β”œβ”€ Red pulsing background
                  └─ "TOUCH SCREEN" indicator
                  ↓
[User touches screen OR types in answer]
                  ↓
                  β”œβ”€ Alarm silences
                  β”œβ”€ User gets another 60s to solve
                  ↓
[Correct answer submitted]
                  ↓
                  β”œβ”€ Stats updated (focus time, problems solved)
                  β”œβ”€ Next interval scheduled
                  └─ Return to T = 0..N

πŸ—οΈ Architecture

lib/
β”œβ”€β”€ main.dart                       # App entry, MaterialApp, timezone setup
β”œβ”€β”€ core/
β”‚   β”œβ”€β”€ math_problem.dart           # MathProblem + MathProblemGenerator
β”‚   β”œβ”€β”€ theme.dart                  # Brand colors, design tokens, Material 3 theme
β”‚   └── alarm_sound_registry.dart   # Preset alarm sound definitions
β”œβ”€β”€ services/
β”‚   β”œβ”€β”€ notification_service.dart   # flutter_local_notifications wrapper + MethodChannel
β”‚   β”œβ”€β”€ settings_repository.dart    # SharedPreferences-backed AppSettings + PomodoroSettings
β”‚   └── stats_repository.dart       # Daily stat persistence + streak tracking
β”œβ”€β”€ providers/
β”‚   └── focus_provider.dart         # ChangeNotifier state machine (idle β†’ running β†’ challengeActive β†’ escalated)
β”œβ”€β”€ screens/
β”‚   β”œβ”€β”€ home_screen.dart            # Idle + running views, today stats card
β”‚   β”œβ”€β”€ challenge_screen.dart       # Full-screen math problem + escalation UI
β”‚   └── settings_screen.dart        # Interval, difficulty, escalation, alarm toggles
└── widgets/
    β”œβ”€β”€ aurora_background.dart      # Animated mesh-gradient background
    β”œβ”€β”€ brand_mark.dart             # Custom-painted target/aperture logo
    β”œβ”€β”€ interval_wheel.dart         # Vertical scroll wheel with landmark values
    └── pulse_rings.dart            # Animated focus rings

Native (Android) β€” android/app/src/main/kotlin/id/focusmate/focus_mate/MainActivity.kt

  • MethodChannel handler for id.focusmate.alarm
  • MediaPlayer with isLooping = true for the alarm sound
  • Vibrator with repeating pattern
  • AudioAttributes.USAGE_ALARM to bypass silent mode

Native (iOS) β€” ios/Runner/AppDelegate.swift

  • Same MethodChannel pattern
  • AVAudioPlayer with numberOfLoops = -1 (loop forever)

State machine

  • FocusState enum: idle, running, challengeActive, escalated
  • State transitions are explicit and gated (e.g. can only escalate from challengeActive)
  • All timers cancelled on state transition to prevent leaks

πŸ“¦ Install

Android (sideload)

  1. Download the latest FocusMate-arm64-vX.Y.Z-release-signed.apk from Releases
  2. Transfer to your Android device
  3. Enable "Install unknown apps" for your file manager / browser (Settings β†’ Apps β†’ Special access β†’ Install unknown apps)
  4. Open the APK and tap Install

Note on signing: v1.0.0–v1.0.5 used the Android debug key. v1.1.0+ use a proper release keystore. If you have an older version installed, uninstall it first (signatures don't match).

iOS

Build from source β€” see Build from source below. (TestFlight / App Store distribution not yet set up.)

Permissions

First launch will request:

  • Notifications β€” required for the math challenge alert
  • Exact alarms β€” required for interval-accurate scheduling
  • Battery optimization exemption β€” prevents Android from killing the timer

πŸ› οΈ Build from source

Prerequisites

  • Flutter 3.44+ (Dart 3.12+)
  • Android SDK 34+ (for Android builds)
  • Xcode 15+ (for iOS builds)
  • Java 17+ (for Android Gradle builds)

Setup

git clone https://github.com/hellogunawan99/focus-mate.git
cd focus-mate
flutter pub get

Android

flutter build apk --release --target-platform android-arm64
# Output: build/app/outputs/flutter-apk/app-arm64-v8a-release.apk

iOS

cd ios && pod install && cd ..
flutter build ios --release
# Then open ios/Runner.xcworkspace in Xcode for device deployment

Run in debug mode

flutter run                    # picks first connected device
flutter run -d <device-id>     # specific device

Run tests

flutter test                   # all unit + widget tests
flutter test test/math_test.dart  # specific file

πŸ§ͺ Testing

  • Unit tests for MathProblemGenerator (problem difficulty, operator distribution)
  • Widget tests for IntervalWheel (centering, scroll range, editor behavior, fling-bound clamps)
  • All tests run on every commit via widget test suite
$ flutter test
+0: All tests passed!

🀝 Contributing

This is a personal-use project, but PRs and bug reports are welcome!

Reporting bugs

  1. Check Issues first
  2. Open a new issue with:
    • Device model + Android version
    • Focus Mate version (Settings β†’ About)
    • Reproduction steps
    • Expected vs actual behavior

Submitting PRs

  1. Fork the repo
  2. Create a feature branch (git checkout -b feature/awesome-thing)
  3. Add tests for new behavior
  4. Run flutter analyze + flutter test β€” must pass clean
  5. Open a PR with a clear description

Code style

  • flutter analyze clean
  • Prefer widget tests for any picker/scroll/offset math
  • Document any new design tokens in lib/core/theme.dart

πŸ“„ License

MIT β€” see LICENSE for details.


πŸ™ Credits

  • App icon β€” procedurally generated target/aperture mark (custom)
  • Alarm sound β€” procedurally generated C5-E5 sine wave (custom)
  • Fonts β€” Plus Jakarta Sans, JetBrains Mono (both open-source)
  • Built with β€” Flutter, Dart, Material 3, and a lot of flutter_local_notifications debugging

Focus Mate v1.1.3 Β· hellogunawan99 Β· 2026

⬆ Back to top

About

Anti-drowsiness focus timer with math-challenge enforcement. Flutter.

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors