Native Android client for the TuxPlanner self-hosted calendar & todo app.
Find a file
Jonas van Leeuwen 38152c67d8
All checks were successful
Build APK / Build Android APK (push) Successful in 11m14s
Forgejo deploy.yml update
2026-05-10 15:34:36 +02:00
.forgejo/workflows Forgejo deploy.yml update 2026-05-10 15:34:36 +02:00
app Fix CI Kotlin compile errors by opting into experimental Material APIs 2026-05-08 06:39:57 +00:00
gradle Fix OkHttp JavaNetCookieJar dependency: use okhttp-urlconnection artifact 2026-05-01 08:39:45 +00:00
.gitignore Changes before error encountered 2026-04-30 20:12:32 +00:00
build.gradle.kts Changes before error encountered 2026-04-30 20:12:32 +00:00
gradle.properties fix: add gradle.properties with android.useAndroidX=true and android.enableJetifier=true 2026-05-01 08:25:21 +00:00
README.md test 2026-05-10 00:05:24 +02:00
settings.gradle.kts Changes before error encountered 2026-04-30 20:12:32 +00:00

TuxPlanner Android

Native Android client for the TuxPlanner self-hosted calendar & todo app.

Built with Kotlin + Jetpack Compose + Material 3


Features

Feature Status
Login / First-run setup
Configurable backend URL
Dashboard with live clock & greeting
Today's events on dashboard
Today's tasks (with toggle) on dashboard
Work sessions summary on dashboard
Events list (create, edit, delete)
Event detail bottom sheet
Full event form (title, desc, location, datetime, all-day, color, calendar)
Calendar list management (create, edit, delete, visibility toggle)
Filter events by calendar list
Todos list (create, edit, toggle, delete)
Todo detail bottom sheet
Full todo form (title, desc, priority, due date, list)
Filter todos by status (All / Pending / Completed)
Filter todos by todo list
Work session management per todo (add, delete)
Todo list management (create, edit, delete) via API
Material 3 UI + dark mode
GitHub Actions release build

Stack

Layer Technology
Language Kotlin
UI Jetpack Compose + Material 3
Networking Retrofit 2 + OkHttp 4
JSON Gson
Auth Cookie-based (HttpOnly JWT via OkHttp CookieJar)
Preferences Jetpack DataStore
Navigation Navigation Compose
Min SDK 24 (Android 7.0)
Target SDK 35 (Android 15)

Running Locally

Prerequisites

  • Android Studio Hedgehog (2023.1.1) or newer
  • JDK 17
  • Android SDK with API 35

Steps

  1. Clone the repo

    git clone https://github.com/jonasvanleeuwen19/tuxplanner-android.git
    cd tuxplanner-android
    
  2. Open in Android Studio Open the root folder (tuxplanner-android/) as an Android Studio project.

  3. Set the backend URL (first launch)

    • The app defaults to http://10.0.2.2:8000 which routes to localhost:8000 on the host machine when using the Android Emulator.
    • If running a real device, use your machine's LAN IP (e.g., http://192.168.1.x:8000).
    • You can change the URL at any time in Settings → Backend URL.
  4. Start the TuxPlanner backend

    # In the TuxPlanner repo
    docker compose up --build
    
  5. Run the app via Android Studio (▶) or:

    ./gradlew installDebug
    

First-run setup

If no users exist on the backend yet, the app shows a "Create Account" screen instead of the login form. Enter a username and password (min 8 characters) to create the first admin account.


Project Structure

app/src/main/java/com/tuxplanner/app/
├── TuxPlannerApp.kt          # Application class + AppContainer (service locator)
├── MainActivity.kt
├── data/
│   ├── model/
│   │   └── Models.kt         # Data classes matching the API
│   ├── network/
│   │   ├── TuxPlannerApiService.kt  # Retrofit interface
│   │   └── ApiClient.kt      # OkHttp + Retrofit factory (cookie jar, dynamic URL)
│   ├── preferences/
│   │   └── AppPreferences.kt # DataStore wrapper (base URL, login state)
│   └── repository/
│       ├── AuthRepository.kt
│       ├── CalendarListRepository.kt
│       ├── EventRepository.kt
│       ├── TaskSessionRepository.kt
│       ├── TodoListRepository.kt
│       └── TodoRepository.kt
└── ui/
    ├── navigation/
    │   ├── Screen.kt          # Route constants
    │   └── AppNavHost.kt      # Root NavHost
    ├── screens/
    │   ├── calendarlists/     # CalendarListsScreen + CalendarListsViewModel
    │   ├── dashboard/         # DashboardScreen + DashboardViewModel
    │   ├── events/            # EventsScreen + EventsViewModel + EventDetailSheet
    │   ├── home/              # HomeScreen (bottom navigation host)
    │   ├── login/             # LoginScreen + LoginViewModel
    │   ├── serverconfig/      # ServerConfigScreen + ServerConfigViewModel
    │   ├── settings/          # SettingsScreen + SettingsViewModel
    │   └── todos/             # TodosScreen + TodosViewModel + TodoDetailSheet
    └── theme/                 # Material 3 colors, typography, theme

GitHub Actions Release Build

The workflow file is at .github/workflows/android-release.yml.

What it does

Trigger Action
Push to main Builds release APK, uploads as workflow artifact
Pull request to main Same (build check)
Tag v* (e.g., v1.0.0) Builds release APK + creates a GitHub Release with the APK attached

Creating a release

git tag v1.0.0
git push origin v1.0.0

The workflow will automatically create a GitHub Release named "TuxPlanner Android v1.0.0" with:

  • Auto-generated release notes
  • The signed APK attached

Signing

By default the release APK is signed with the debug key (installable on any device for testing, but not suitable for Play Store).

To use a real signing key:

  1. Generate a keystore:

    keytool -genkey -v -keystore my-release-key.jks \
      -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000
    
  2. Base64-encode it:

    base64 -i my-release-key.jks | tr -d '\n'
    
  3. Add these repository secrets (Settings → Secrets → Actions):

    Secret Value
    KEYSTORE_BASE64 base64 output from step 2
    KEYSTORE_PASSWORD your keystore password
    KEY_ALIAS your key alias
    KEY_PASSWORD your key password

Backend API Summary

Endpoint Method Description
/api/auth/setup-status GET Check if first-run setup is needed
/api/auth/setup POST Create first admin account
/api/auth/login POST Login (form-encoded) → sets httpOnly cookie
/api/auth/logout POST Clear auth cookie
/api/auth/me GET Get current user info
/api/calendar-lists/ GET/POST List or create calendar lists
/api/calendar-lists/{id} PUT/DELETE Update or delete calendar list
/api/events/ GET/POST List or create events
/api/events/{id} GET/PUT/DELETE Read, update, or delete event
/api/todos/ GET/POST List or create todos
/api/todos/{id} GET/PUT/DELETE Read, update, or delete todo
/api/todo-lists/ GET/POST List or create todo lists
/api/todo-lists/{id} PUT/DELETE Update or delete todo list
/api/todos/{id}/sessions/ GET/POST List or create work sessions
/api/todos/{id}/sessions/{sid} PUT/DELETE Update or delete work session

Authentication uses an httpOnly JWT cookie (access_token). OkHttp's JavaNetCookieJar handles this transparently.


License

MIT