Meet Mario, my adorable furry friend who needs a bit of extra care! This app reminds us to give Mario his medicines on time: eye drops, ointments and painkillers, some of them one after the other with a wait in between.
- Σήμερα (Today) – what is due now, with big "Το έδωσα" / "Αργότερα" buttons, the next medicine, and the whole day. Go back to see what was given, or forward to see (and change) the coming days.
- Chains of medicines – a routine is a list of medicines given one after the other, e.g. Blinkdrops → 20′ → Tearshield (made-up names). The next reminder comes 20 minutes after you tap "Το έδωσα", not 20 minutes after the planned time. A quiet countdown shows how long is left.
- Every N hours – "Κάθε … ώρες" fills in the times from the first dose of the day (e.g. 07:00 · 15:00 · 23:00). Each later dose then counts from when the previous one was actually given: 07:00 given at 08:22 → next at 16:22, and the one after it moves along at once (00:22), then again when the second is given. The first dose of each day stays at its time. Any routine with two or more times can do this ("Μετράει από την προηγούμενη δόση").
- Change one reminder only – tap any future dose to move it to another time just that day, skip it, or put it back. "Αλλαγή ώρας για όλη τη μέρα" moves every dose of a day at once (e.g. when you woke up late).
- Sticky notifications – a reminder stays until you tap "Το έδωσα" or "Αργότερα". If it is swiped away it comes back quietly. If nobody answers it rings again every few minutes (you choose how often, up to 6 times), then stays quietly in the drawer. It only goes away by itself when the dose counts as missed (after 12 hours by default).
- No duplicates – each medicine of each dose has one notification id, so pressing a button twice (e.g. phone and watch) can't create extra reminders.
- Pause – one switch stops all reminders (e.g. while Mario stays at the vet) without changing the schedule.
- Buttons work with the app closed – "Το έδωσα" and "Αργότερα" on the notification (or on a smartwatch) work without opening the app, and the next medicine of the chain is scheduled right away.
- Πρόγραμμα (Schedule) – a preview of a normal day, the list of routines, and the next reminders.
- Συνταγή (Prescription) – the medicines with dose and instructions, treatment start/end dates (no reminders after the end), the vet's phone and next check-up, and free notes.
- Ρυθμίσεις (Settings) – pause, snooze time, repeat time, when a dose counts as missed, sticky on/off, countdown, alarm-like sound, plus a check of everything that can stop reminders from arriving (permissions, exact alarms, battery saving, phone-maker settings) with a button to fix each one, and a test notification.
- Ιστορικό (History) – the last 30 days, and how many doses were given.
- Φυσικοθεραπεία (Physio) – daily exercises at home: a card on Today with an "Έγινε" button, and a reminder at a set time if they aren't done yet ("Έγινε" and "Αργότερα 1 ώρα" also work from the notification and the watch). The last 4 weeks as paw prints, and how many days in a row. Visits to the physio with a note each, and a reminder an hour before. Open it from the card on Today or from Συνταγή.
- Backup – export all data as text and restore it later.
- Greek and English – the app follows the phone's language (a Greek phone gets Greek, any other gets English), and Ρυθμίσεις → Γλώσσα · Language can fix it to one. Reminders change language too. Every text is written in both languages in place, with
t('Σήμερα', 'Today')fromsrc/i18n. - Light and dark mode. Settings from the previous version are carried over on the first start, and the old "Οδηγίες" text is kept in the prescription notes.
- Notification texts use plain words (no ✓ or ′ symbols) so they show correctly on a smartwatch.
No laptop needed. Every change merged into main goes to the phone by itself (.github/workflows/deploy.yml → scripts/deploy.sh):
- Most changes (screens, texts, logic) arrive as an over-the-air update. The app downloads it on its own and shows "Υπάρχει νέα έκδοση" with a restart button.
- Changes to native code (new native library, permissions, app icon) need a new app. A new APK is built with EAS Build, and the link to install it is in the summary of the "Deploy to phone" run on GitHub.
Add the label test-build to a pull request. The "Test build" workflow makes a separate app, Mario TEST (com.altany.marioshelper.test), and puts its install link in the run summary. It installs next to the real app, with its own data and its own reminders, so Mario's real reminders are not touched. Each run is one EAS build.
One-time setup:
- On expo.dev: Account settings → Access tokens → create a token.
- On GitHub: this repo → Settings → Secrets and variables → Actions → New repository secret, name
EXPO_TOKEN, value the token. - The first run makes an APK. Install it on the phone once (open the link, tap Install). From then on, updates arrive by themselves.
- Expo SDK 57 (React Native 0.86, New Architecture) + expo-router. Notifications use
react-native-notify-kit, the maintained fork of Notifee (archived in April 2026), with the same API. It is imported only insrc/notify/driver.ts. - Instead of repeating alarms, the app works out the concrete doses ("runs") for the next 7 days from the routines (
src/engine/runs.ts), and schedules one exact alarm per dose. Physio (src/engine/physio.ts) adds one alarm per day for the exercises and one per visit. Every change goes throughact()(src/notify/commands.ts), which saves the data and then syncs the alarms with the plan (src/engine/plan.ts,src/notify/sync.ts). The 7 days are topped up every time the app opens or a notification fires. - Notification buttons are handled in
src/notify/events.ts. It is registered inindex.jsso it also runs when Android starts the app in the background. - All data is one JSON document in AsyncStorage (
src/store/store.ts). - The engine is plain TypeScript with tests in
__tests__/.
app/ screens (expo-router)
src/engine/ schedule logic, no React
src/notify/ notifications (notify-kit, the Notifee fork)
src/store/ saving data
src/model/ types, default data, migration from v2
src/ui/ components, theme, sheets
assets/fonts/ rounded title font (Latin + Greek subset, OFL)
plugins/ Expo config plugins: notification icon, notification sound
assets/sounds/ the bark played by dose notifications (copied into the Android app)
npm installnpm test # engine tests
npm run typecheck # TypeScriptnpx expo startThe screens also open in a browser (npm run web), but notifications only work on a phone.
The deploy workflow above builds it in the cloud. To build locally instead, generate the android/ folder (this version removes the old native files):
npx expo prebuild --clean -p android
cd android && ./gradlew assembleReleaseOutput: android/app/build/outputs/apk/release/app-release.apk
If you had changed anything by hand in android/ (e.g. your own signing key in android/app/build.gradle), copy it somewhere first, because --clean deletes the folder. An APK signed with a different key can't be installed over the old app without uninstalling it (which also deletes its data).
After installing, open the app once and look at Ρυθμίσεις → Έλεγχος. On Samsung / OnePlus / Xiaomi phones, allow the app to run in the background without battery limits.
