Skip to content

Repository files navigation

a-medic-log

Languages Downloads GitHub release (by tag) Release Android CI Release Build Emulator Test

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.

Features

  • 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
  • Export & Import - Export all or selected profiles to a ZIP archive (JSON + attachment images), import profiles from an export file, export a profile to an Excel spreadsheet (XLSX, Android 8+) or a ZIP of CSV files on older versions
  • In-app License Viewer - Open-source licenses page generated at build time from actual app dependencies
  • 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

Tech Stack

Component Detail
Language Java 17
Min SDK 21 (Android 5.0)
Target SDK 37 (Android 17)
Compile SDK 37
Build System Gradle 9.4.1 (AGP 9.2.1)
Architecture Single-Activity + StatefulView
Navigation a-navigator
Dependency Injection a-provider
Database Room 2.7.2 (SQLite)
Reactive RxJava 3.1.12 / RxAndroid 3.0.2
Background Work WorkManager 2.10.5
UI Material Components 1.13.0, PhotoView
Desugaring coreLibraryDesugaring (desugar_jdk_libs 2.1.5)
Spreadsheets a-poi-spreadsheet

Project Structure

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.

Key Components & Technical Detail

1. Dependency Injection (a-provider)

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.
  • Activity Scope (ActivityProvider):
    • Lifecycle: Bound to MainActivity. Created via Provider.createNestedProvider.
    • Components: AppNotificationHandler (UI-specific logic), INavigator (Context-aware).
  • View Scope (StatefulViewProvider):
    • Lifecycle: Transient/Pooled.
    • Usage: Provides dependencies needed strictly for View rendering or local logic.

2. Navigation (a-navigator)

  • Single Activity: MainActivity acts as the container.
  • StatefulView: All pages (e.g., HomePage, NotesPage) extend StatefulView.
  • Configuration: NavConfiguration maps String routes (e.g., /home) to StatefulViewFactory implementations.
  • Back Stack: Navigator manages the stack of views. onBackPressed is intercepted and delegated to the Navigator.

3. Reactive Lifecycle Management

  • RxJava3 / RxAndroid: Used for all asynchronous operations and event handling.
  • RxDisposer: A custom helper class that manages Disposable objects.
    • It is provided via DI and linked to the lifecycle of the Provider/Component.
    • When a StatefulView is disposed, its associated Provider (and thus RxDisposer) cleans up all active subscriptions, preventing memory leaks.

4. Reminder Notifications

  • AndroidNotification: Room table that tracks posted reminder notifications so they can be cancelled/updated.

Architecture Diagram

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
Loading

Workflow & Logic Flow

1. Command Execution Pattern (Business Logic)

The app strictly separates UI from Data Logic using the Command Pattern.

  1. UI Action: User performs an action (e.g., "Save Note").
  2. Command Creation: View requests a Command instance (e.g., UpdateNoteCmd) from CommandProvider.
  3. Execution: Command runs on a background thread (ExecutorService).
  4. Persistence: Command calls NoteDao to write to SQLite.
  5. Notification: Upon success, Command calls NoteChangeNotifier.
  6. Reaction: The Notifier emits an event. Active Views listening to this notifier (via RxDisposer) update their state.

Sequence Diagram

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()
Loading

2. Domain Model Relationships

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.

Entity Relationship Diagram

erDiagram
    PROFILE ||--o{ NOTE : has
    NOTE ||--o{ MEDICINE : contains
    NOTE ||--o{ NOTE_ATTACHMENT : has
    MEDICINE ||--o{ MEDICINE_REMINDER : schedules
    MEDICINE ||--o{ MEDICINE_INTAKE : history
    NOTE ||--o{ NOTE_TAG : "tagged-with"
Loading

How Reminders Work

Reminders are scheduled with WorkManager. For each enabled reminder, a one-time work request is enqueued with an initial delay until the next occurrence. The worker posts the notification on the configured days of week and re-enqueues itself for the next day. Notification actions let the user log a medicine intake or disable the reminder directly from the notification.

Building

Prerequisites

  • JDK 17
  • Android SDK with Compile SDK 37
  • An internet connection on first build (Gradle fetches dependency POMs to generate the licenses page)
  • JitPack repository is required (already configured in settings.gradle)

Build commands

./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)

Licenses page

The generateLicenseHtml Gradle task (from gradle/license-html-generator.gradle) resolves all external dependencies' POMs and generates app/src/main/assets/licenses.html, which is shown in the in-app licenses page. It runs automatically before every build (preBuild). Per-artifact overrides live in app/licenses.yml. The generated file is committed to the repo.

Release signing

Release signing is configured via environment variables: SIGNING_KEY (base64 keystore), KEY_STORE_PASSWORD, ALIAS, and KEY_PASSWORD. When SIGNING_KEY is not set, the release build is unsigned (this is how CI signs release APKs).

CI/CD

The project uses GitHub Actions for continuous integration and deployment:

Workflow Trigger Description
Android CI Push/PR to master Builds the project with Gradle
Android Emulator Test Push/PR to master Runs instrumented tests on API 23, 26, 31 & 36 emulators
Android Release APKs Tag push (v*) Builds signed debug and release APKs and creates a GitHub Release with the changelog from fastlane/metadata/android/en-US/changelogs/<versionCode>.txt

The release body is produced automatically: a Gradle hook copies the fastlane changelog file for the current versionCode to app/build/changelog.txt, which the release workflow uses as the GitHub Release body.

Screenshots

Support this project

Consider donation to support this project

https://trakteer.id/rh-id

License

This project is licensed under the GNU General Public License v3.0.

About

A simple and easy to use personal medical notes.

Topics

Resources

Stars

18 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages