# Simplauncher **Keep this file under 100 lines.** Prefer terse descriptions. Don't duplicate what's in README.md or DEVELOPMENT.md. ## Development ```bash export ANDROID_HOME=/home/user/android-sdk ./gradlew assembleDebug # Build debug APK ./gradlew assembleRelease # Build release/production APK ./gradlew test # Run unit tests (JUnit 5) ``` Debug APK: `app/build/outputs/apk/debug/com.simplauncher.apk` Release APK: `app/build/outputs/apk/release/com.simplauncher.apk` ## Versioning Version tracked in `app/build.gradle.kts`: `versionName` (semver) + `versionCode` (integer). - **PATCH** (1.0.x): bug fixes, visual tweaks - **MINOR** (1.x.0): new features, settings, UI additions - **MAJOR** (x.0.0): breaking changes, major redesigns - Increment `versionCode` by 1 on every release regardless of semver bump. - Tag every release: `git tag -a v1.0.0 -m "description"` then `git push origin v1.0.0` - **IMPORTANT:** After any version bump, remind user to upload the release APK to Gogs releases page at https://gogs.altsol.dev/claude/simplauncher/releases ## Repository - Remote: `https://gogs.altsol.dev/claude/simplauncher.git` - Branch: `master` only - Forked from Unlauncher 2.1.1 (itself a fork of Slim Launcher) ## Architecture Single-activity (`MainActivity`), multi-fragment app using Navigation Component. MVVM-lite: fragments observe `DataRepository` via LiveData. Hilt DI throughout. **Package:** `com.simplauncher` — all source under `app/src/main/java/com/simplauncher/` ## Navigation (nav_graph.xml) ``` HomeFragment (start) → OptionsFragment → CustomizeHomeFragment → CustomizeHomeAppsAddAppFragment → CustomizeAppDrawerFragment → CustomizeVisibleAppsFragment → CustomizeSearchFieldFragment → CustomizeFoldersFragment → CustomizeFolderDetailFragment ``` ## Data Layer Three storage systems (migrating everything to Proto DataStore): 1. **Proto DataStore (primary):** `core_preferences.proto`, `unlauncher_apps.proto`, `quick_button_preferences.proto`, `app_drawer_folders.proto` 2. **Room DB (legacy):** `BaseDatabase` with `HomeApp` entity, 9 migrations 3. **SharedPreferences (legacy):** being migrated away **DataRepository** wraps DataStore with LiveData observation, sync `get()`, and `updateAsync()`. All new data should use Proto DataStore. ## Hilt DI - **SingletonComponent:** 4 DataStore instances (incl. AppDrawerFolders), BaseDatabase - **ActivityComponent:** CorePreferences repo (@WithActivityLifecycle) - **FragmentComponent:** All 4 repos (@WithFragmentLifecycle), FragmentManager, CoroutineScope ## UI Patterns - View Binding on all fragments - MotionLayout for home→drawer transition (swipe up) - Pub-sub: MainActivity (IPublisher) → Fragments (ISubscriber) for back/home events - App drawer folders: alignment-aware arrows, animated expand/collapse, auto-collapse on home - Folder detail settings: checkbox app selector with 3-dot menu (rename/delete) - Home screen: up to 6 apps, 3 quick buttons (call/options/camera), clock, date, search bar ## Themes 9 themes: system (light/dark), midnight, jupiter, teal, candy, pastel, noon, vlad, groovy. ## Permissions `QUERY_ALL_PACKAGES`, `REQUEST_DELETE_PACKAGES`, `EXPAND_STATUS_BAR`, `SET_WALLPAPER`, `SET_ALARM` ## Testing JUnit 5 + Kotest assertions + MockK. Coverage excludes generated proto/Hilt classes. ## Conventions - Kotlin only - New preferences → Proto DataStore (never SharedPreferences or Room) - Fragment lifecycle: onCreateView (inflate) → onViewCreated (setup) → onStart (attach pub-sub) → onStop (detach) - ProGuard keeps protobuf generated classes