A simple and easy to use personal medical notes app.
This project is intended as a demo app for a-navigator and a-provider library usage. The app works as a production app even though it is a demo app.
- Medical Notes - Easily add and manage your medical notes with date tracking
- Multiple Profiles - Keep track of elderly and family members' medical history
- Medicine Tracking - Add medicine information with detailed descriptions
- Medicine Reminders - Set up notifications to remind you to take medicine
- Medicine Intake History - Log and review past medicine intakes
- Note Attachments - Attach files and images to your notes
- Note Tags - Tag your notes for better organization
- Search - Search through your notes and profiles
- Dark/Light Mode - Support for both dark mode and light mode themes
- Multi-language - Available in English, German, French, Italian, Indonesian, Estonian, Icelandic, Norwegian (Bokmål & Nynorsk), and Romansh
| Component | Detail |
|---|---|
| Language | Java 17 |
| Min SDK | 21 (Android 5.0) |
| Target SDK | 36 (Android 16) |
| Compile SDK | 36 |
| Build System | Gradle (AGP 9.2.1) |
| Architecture | Single-Activity + StatefulView |
| Navigation | a-navigator |
| Dependency Injection | a-provider |
| Database | Room (SQLite) |
| Reactive | RxJava3 / RxAndroid |
| Background Work | WorkManager |
The app uses a-navigator framework as navigator and StatefulView as base structure, combined with a-provider library for service locator, and finally RxAndroid to handle UI use cases.
The project is divided into two main modules:
app: Contains the UI logic, navigation, dependency injection wiring, and business logic implementation.base: Contains the Data Layer (Room Entities, DAOs), Repositories, and basic domain models.
The app utilizes a hierarchical provider structure to manage dependency scopes effectively:
- Global Scope (
AppProviderModule):- Lifecycle: Bound to
MainApplication. - Components:
AppDatabase,WorkManager,Notifiers(Singleton),ScheduledExecutorService.
- Lifecycle: Bound to
- Activity Scope (
ActivityProvider):- Lifecycle: Bound to
MainActivity. Created viaProvider.createNestedProvider. - Components:
AppNotificationHandler(UI-specific logic),INavigator(Context-aware).
- Lifecycle: Bound to
- View Scope (
StatefulViewProvider):- Lifecycle: Transient/Pooled.
- Usage: Provides dependencies needed strictly for View rendering or local logic.
- Single Activity:
MainActivityacts as the container. - StatefulView: All pages (e.g.,
HomePage,NotesPage) extendStatefulView. - Configuration:
NavConfigurationmaps String routes (e.g.,/home) toStatefulViewFactoryimplementations. - Back Stack:
Navigatormanages the stack of views.onBackPressedis intercepted and delegated to the Navigator.
- RxJava3 / RxAndroid: Used for all asynchronous operations and event handling.
- RxDisposer: A custom helper class that manages
Disposableobjects.- It is provided via DI and linked to the lifecycle of the Provider/Component.
- When a
StatefulViewis disposed, its associated Provider (and thusRxDisposer) cleans up all active subscriptions, preventing memory leaks.
graph TD
subgraph "Base Module"
DB[(Room Database)]
DAO[DAOs]
Entity[Entities]
end
subgraph "App Module"
subgraph "DI Layer"
AppProv[AppProvider]
ActProv[ActivityProvider]
CmdProv[CommandProvider]
end
subgraph "UI Layer"
Act[MainActivity]
Nav[Navigator]
View["StatefulView (Page)"]
end
subgraph "Logic Layer"
Cmd["Command (Business Logic)"]
Notif["Notifier (Event Bus)"]
end
end
AppProv --> ActProv
Act --> ActProv
ActProv --> Nav
Nav --> View
View -->|Injects| CmdProv
CmdProv -->|Creates| Cmd
Cmd -->|Updates| DAO
DAO -->|Persists| DB
Cmd -->|Triggers| Notif
Notif -->|Emits to| View
The app strictly separates UI from Data Logic using the Command Pattern.
- UI Action: User performs an action (e.g., "Save Note").
- Command Creation: View requests a Command instance (e.g.,
UpdateNoteCmd) fromCommandProvider. - Execution: Command runs on a background thread (
ExecutorService). - Persistence: Command calls
NoteDaoto write to SQLite. - Notification: Upon success, Command calls
NoteChangeNotifier. - Reaction: The Notifier emits an event. Active Views listening to this notifier (via
RxDisposer) update their state.
sequenceDiagram
participant User
participant View as StatefulView
participant Cmd as Command
participant DB as AppDatabase
participant Bus as Notifier
User->>View: Click Save
View->>Cmd: Execute(Data)
activate Cmd
Cmd->>DB: Insert/Update
DB-->>Cmd: Success
Cmd->>Bus: notifyChanged(Data)
deactivate Cmd
Bus-->>View: onNext(Data)
View->>View: updateUI()
The domain follows a strict hierarchy rooted in the Profile.
- Profile: Top-level entity. Represents a person.
- Note: Medical entry. Belongs to a Profile.
- Medicine: Medication details. Belongs to a Note.
- MedicineReminder: Schedule config. Belongs to a Medicine.
- MedicineIntake: History log. Belongs to a Medicine.
erDiagram
PROFILE ||--o{ NOTE : has
NOTE ||--o{ MEDICINE : contains
NOTE ||--o{ NOTE_ATTACHMENT : has
MEDICINE ||--o{ MEDICINE_REMINDER : schedules
MEDICINE ||--o{ MEDICINE_INTAKE : history
- JDK 17
- Android SDK with Compile SDK 36
./gradlew build # Build debug and release APKs
./gradlew assembleDebug # Build debug APK only
./gradlew assembleRelease # Build release APK only
./gradlew test # Run unit tests
./gradlew connectedCheck # Run instrumented tests (requires device/emulator)The project uses GitHub Actions for continuous integration and deployment:
| Workflow | Trigger | Description |
|---|---|---|
| Android CI | Push/PR to master |
Builds the project with Gradle |
| Emulator Test | Push/PR to master |
Runs instrumented tests on API 23 & 29 emulators |
| Release APKs | Tag push (v*) |
Builds signed APKs and creates a GitHub Release with changelog |
Consider donation to support this project
| https://trakteer.id/rh-id |
This project is licensed under the GNU General Public License v3.0.



