Remember
what matters.
DYF (Do You Forget) is a distraction-free reminder app with an intelligent notification engine that stays quiet when you have time — and pulses more urgently as your deadline closes in.
Open source · No accounts · No trackers · No cloud
The core algorithm
Adaptive Pulse Scheduler
APS distributes notifications geometrically across the time window between task creation and deadline. The parameter k controls how aggressively alerts cluster near the end — higher priority means steeper concentration. Interact with the controls below to see the live distribution.
What makes DYF different
Designed to stay
out of your way
Gesture-Based Theme
No toggle. No settings. Swipe left or right anywhere across the top bar area and the app instantly switches between light and dark mode. A brief haptic confirms it — then it disappears, like it was never there.
Requires >70 px drag distance or >600 px/s fling velocity — so accidental scrolling never triggers it.
Voice Input via RegExp
Speak naturally. The OS transcribes on-device, and a pure-Dart RegExp engine extracts task, date, and time with surgical precision — zero AI cloud calls, zero model downloads, zero JNI crashes.
"Remind me to call the dentist tomorrow at 3 PM"
Replaced google_mlkit_entity_extraction — eliminating the native JNI crash on Android 16.
Source code discoveries
Two things worth
a closer look
Two architectural decisions buried in the Flutter codebase that reflect a bias toward surgical precision over brute force.
// Fires only on deliberate, heavy swipes void _onDragEnd(DragEndDetails details) { final velocity = details.primaryVelocity ?? 0; final isDeliberate = _accumulatedDelta.abs() >= 70.0 // px threshold || velocity.abs() >= 600.0; // px/s threshold if (isDeliberate) { HapticFeedback.mediumImpact(); ThemeController.toggle(); } _accumulatedDelta = 0; }
// Track exact char spans — not replaceFirst() String _removeSpans( String text, List<_Span> spans) { final sorted = [...spans] ..sort((a, b) => a.start.compareTo(b.start)); final buffer = StringBuffer(); var cursor = 0; for (final s in sorted) { buffer.write(text.substring(cursor, s.start)); buffer.write(' '); // placeholder gap cursor = s.end; } return buffer.toString().trim(); }
replaceFirst() — which silently removes the wrong occurrence when a word repeats — the engine records the exact [start, end] character indices of every extracted datetime token, then surgically removes them in one sorted pass. A downstream sweep then cleans up orphaned prepositions like "at", "on", and "by" that get stranded after their date expressions are cut.
Give it a try.
Your garden awaits.
Free, open source, and built with one purpose: making sure you actually remember.
Split APKs for minimal install size · View source on GitHub ↗