A minimal, battery-aware Intention Repeater built with Kotlin + Jetpack Compose. It “broadcasts” a user-provided intention in timed bursts, keeps accurate iteration counts, and survives rotation/background/screen-off via a Foreground Service.
- Intention textbox (5 lines, scrollable)
- Burst Count (positive ints, default 888888)
- Frequency:
Max,3 Hz,8 Hz,Hourly(one burst, then sleep) - Load File → appends SHA-512 hash of the chosen file to the intention
- Start / Stop control
- Live metrics: iterations, timer
HH:MM:SS; atMaxalso shows iterations/sec - Status: “Ready” / “Broadcasting…”
- Light/Dark Mode checkbox (overrides system)
- Duration (seconds) with bounds: 1..86400 (24h default)
- Auto-persist settings with DataStore
- ForegroundService keeps running through rotation, app switch, and screen off
- Nature-inspired theme (spruce/moss palette)
Add images later in
/docsand link them here.
- Main screen with inputs, status, metrics
- File picker (Storage Access Framework)
- Foreground notification while broadcasting
- Language: Kotlin
- UI: Jetpack Compose + Material 3
- State: Compose state +
StateFlowfrom the service - Persistence: AndroidX DataStore (Preferences)
- Background work: ForegroundService + coroutines
- Min SDK: 26, Target SDK: 36 (compileSdk 36)
applicationId = com.anthroteacher.servitorconnect
POST_NOTIFICATIONS(Android 13+, for foreground notification)FOREGROUND_SERVICE_DATA_SYNC(Android 14+, declares service type)
No network, location, storage reads beyond the file you explicitly pick.
- Android Studio Koala or newer
- JDK 11
- Android SDK Platforms: API 34/35/36 (as available)
- SDK Tools: Android Emulator (if you use an AVD)
git clone https://github.com/<you>/ServitorConnect.git
cd ServitorConnect- Open the project in Android Studio.
- Let Gradle sync.
- Run on a device or emulator.
- Tools → Device Manager → Create Device → pick Pixel 6a.
- Choose a Google APIs (x86_64) system image (or Google Play if you need Play Services).
- Start the AVD and select it as the run target.
app/
├─ src/main/
│ ├─ AndroidManifest.xml
│ ├─ java/com/anthroteacher/servitorconnect/
│ │ ├─ MainActivity.kt # Compose UI & intents
│ │ ├─ data/
│ │ │ └─ Prefs.kt # DataStore, Frequency enum, SavedSettings
│ │ ├─ service/
│ │ │ └─ ServitorService.kt # ForegroundService, broadcasting loop
│ │ └─ ui/theme/
│ │ ├─ Color.kt # Spruce/Moss palette
│ │ ├─ Theme.kt # Material theme wrapper
│ │ └─ Type.kt # Typography
│ └─ res/… # icons, strings, styles
└─ build.gradle.kts
-
Start:
- Saves current settings to DataStore.
- Starts
ServitorServicein the foreground. - Disables inputs, shows “Broadcasting…”, changes button to Stop.
-
Burst Loop (inside the service):
-
Repeats
burstCounttimes:val placeholder = intention // intentional no-op assignment iterations++
-
Frequency:
Max: cooperativeyield()(fast enough, throttling-friendly)3 Hz:delay(333ms)8 Hz:delay(125ms)Hourly:delay(3600000ms)(one burst, then sleep)
-
Updates metrics every second; shows iter/s only for
Max.
-
-
Stop:
- Cancels the job, keeps the last iterations and timer, sets status to “Ready”.
- Re-enables controls; button label returns to Start.
-
Load File:
- Opens system picker; if a file is chosen, computes
SHA-512and appends:SHA512:<128-hex-chars>to the Intention box (on a new line if needed).
- Opens system picker; if a file is chosen, computes
-
Adaptive launcher icon recommended via New → Image Asset.
-
Palette:
- Spruce700
#1C4631, Spruce500#2E6B4B, Spruce300#63A37F, - Moss100
#E8F3EC, Earth900#1C1B1F.
- Spruce700
-
No devices listed: install an AVD (Device Manager), or plug in a phone with USB debugging.
-
Gradle can’t find DataStore alias:
-
Ensure
gradle/libs.versions.tomlhas:[versions] datastore = "1.1.7" [libraries] androidx-datastore-preferences = { group = "androidx.datastore", name = "datastore-preferences", version.ref = "datastore" }
-
Then use:
implementation(libs.androidx.datastore.preferences) -
Sync Gradle; if Studio still marks red, Invalidate Caches / Restart.
-
-
Deprecated
getSerializableExtrawarning: code uses the 33+ overload and a pre-33 fallback.
- The app does not send data anywhere.
- File access happens only for the file you pick, to compute a local SHA-512 hash.
- Optional “Eco mode” for
Max(tinydelay(1)cap) - Align “Hourly” to top-of-hour (optional mode)
- Export/import settings
- Wake lock toggle for deep Doze scenarios
PRs welcome. Keep changes small and focused:
- Compose-first UI
- No breaking changes to
applicationId - Maintain minSdk 26 unless there’s a strong case
GPLv3
Issues/ideas? Open a GitHub issue or drop feedback in the repo discussions.