52 Commits
Author SHA1 Message Date
darken 70b9c2981e fix(upgrade): Align the androidx.hilt declarations with the resolved 1.2.0
addWorkerManager() needed androidx.hilt 1.2.0 for its KSP compiler, which left
addDagger() asking for 1.0.0 while conflict resolution silently handed it 1.2.0,
and hilt-compiler declared twice at two different versions.

The version moves to Versions.AndroidX.Hilt.core, addDagger() stays the single
place that registers hilt-common and the hilt-compiler, and addWorkerManager()
declares only hilt-work. Declared and resolved versions now match, so the
dependency report no longer shows a 1.0.0 -> 1.2.0 substitution.

No dependency graph change: 1.2.0 is what already resolved.
2026-08-18 17:55:19 +02:00
darken 971fcbd34c fix(upgrade): Add a persistent acknowledgement safety net for Play purchases
Play auto-refunds (and revokes) purchases not acknowledged within 3 days.
The in-process ack machinery covers every case where the process lives
long enough; what it cannot cover is a process death around the Play
sheet (aggressive OEM task killers) followed by the user not reopening
the app before the deadline.

Add a gplay-only WorkManager safety net:
- PurchaseAckWorker: self-completing sweep via a new bounded
  BillingManager.ensureAllAcknowledged() that refreshes and acknowledges
  in the same coroutine (the reactive ack collector is async, so a worker
  cannot prove its acks happened through it). Retries with exponential
  backoff until the purchase's refund deadline, then gives up visibly.
- PurchaseAckScheduler: two unique work identities. A launch watch
  (REPLACE, armed and awaited before launchBillingFlow with a 30min delay
  so it cannot complete while the user is still in the sheet) and a
  discovered-purchase rescue (KEEP, 1min delay, armed directly from an
  ack pass that finds unacknowledged purchases, pre-attempt). Separate
  identities so a new purchase flow can never displace a pending rescue.
  Both triggers are fail-open: a broken WorkManager never blocks a
  purchase or an ack. WorkManager resolves via Provider at first arm so
  eager Application-time construction of the billing stack cannot
  trigger WorkManager's on-demand initialization prematurely.
- Nothing cancels the work from the foreground path: an ack pass can see
  zero unacked purchases while the sheet is still open, so the worker
  completes itself after its own reconciliation instead.

The ack pass now runs under a mutex (the worker sweep and the reactive
collector would otherwise race the token bookkeeping) and reports
per-outcome counts for the sweep result mapping.

This is a port of d4rken-org/sdmaid-se#2685; the ported sources are
byte-identical to the donor apart from the package rename.

CAPod had no explicit WorkManager wiring at all (work-runtime only
arrived transitively through Glance), so this also adds it:
- addWorkerManager() pinning androidx.work 2.7.1, the version already
  resolved via Glance, plus androidx.hilt:hilt-work and its KSP
  compiler. work-runtime-ktx is required at 2.7.1: CoroutineWorker,
  Operation.await, OneTimeWorkRequestBuilder and workDataOf all still
  live in the ktx artifact at that version. androidx.hilt moves 1.0.0 ->
  1.2.0 (by conflict resolution) because 1.0.0's hilt-compiler ships no
  KSP SymbolProcessorProvider, so @HiltWorker would generate nothing.
- WorkManagerModule providing the singleton WorkManager.
- App implements Configuration.Provider with the injected
  HiltWorkerFactory. WorkManager 2.7.1 still declares that interface as
  getWorkManagerConfiguration(), not the later property form.
- The manifest removes androidx.work's startup initializer so the
  on-demand configuration is the one that takes effect.

FOSS stays untouched behaviour-wise: all new billing types live in
src/gplay, workers need no manifest entry, and the worker factory
resolves the worker only in gplay variants.
2026-08-18 17:55:19 +02:00
darken 3651bb3d55 refactor(upgrade): Converge GPlay billing on the canonical stack
Replaces capod's older billing core, upgrade UI and their tests with the
canonical sdmaid-se stack at the pinned revision.

Core (gplay): BillingManager/BillingConnection/BillingConnectionProvider on
billing 8.3 with the centralized connect loop, merging purchases-listener
overlay and the canonical ack pipeline; the dying ack collector, the
ackedTokens gate and the in-billing foreground loop are gone. Full canonical
exception set (internal/network/offer-unavailable added), OurSku with capod's
product ids, BillingCache with snapshot()/episode-guarded stampLastProState.

FOSS: UpgradeControlFoss becomes UpgradeRepoFoss and exposes the canonical API
surface over capod's RETAINED FossUpgrade/FossCache schema — existing supporter
records must keep decoding.

Diagnostics: UpgradeDiagnostics + gplay/foss implementations, read by
RecorderModule next to CurriculumVitae's Pro history as two independent,
isolated header reads.

UI: canonical upgrade screens for both flavors under common/upgrade/ui with
capod chrome (M3 AlertDialog keeping rotation-safety, capod Scaffold, capod
previews). Nav.Main.Upgrade gains `forced`. Entitlement refresh moves to a
per-resume, unthrottled MainActivity call.

Strings reuse capod's existing translated ids wherever equivalent; only
referenced-but-missing ones are authored.

mockk 1.12.4 -> 1.14.9: 1.12.4 cannot synthesize a sealed-class return value
while recording, which the ported restore tests need.
2026-07-29 14:05:26 +02:00
darken a650405c2d chore: Bump Android Gradle Plugin to 9.1.0 2026-04-09 07:47:56 +02:00
darken 52433460be fix: Bump Compose BOM to fix ExposedDropdownMenuBox crash on detach 2026-03-20 17:48:55 +00:00
darken a79f6a0535 refactor: Replace Moshi with kotlinx.serialization
Remove Moshi dependency entirely, completing the migration to kotlinx.serialization. All JSON serialization now uses kotlinx with explicit @SerialName annotations for wire format stability.

- Migrate PodDeviceCache from Moshi to kotlinx Json injection

- Add MapIntByteArrayBase64Serializer for BleScanResult cache compat

- Strip @JsonClass/@Json annotations from all dual-annotated classes

- Delete Moshi adapters, ProGuard rules, and build config

- Convert compat tests to pure kotlinx round-trip tests
2026-03-09 20:29:19 +00:00
darken a92e364ca6 refactor(settings): Migrate preferences from SharedPreferences to DataStore
Replace FlowPreference<T> wrapping SharedPreferences with DataStoreValue<T> wrapping AndroidX DataStore. Includes SharedPreferencesMigration for preserving existing user data, kotlinx-serialization for complex types (replacing Moshi for preferences), and comprehensive unit tests for the new infrastructure.
2026-03-04 15:23:34 +00:00
darken cd6488a713 refactor(ui): Replace waitForState and shareLatest with lifecycle-aware state collection
Add collectAsStateWithLifecycle for all Compose state collection (except Glance widgets). Add asLiveState() extension to ViewModel2 as a simpler replacement for shareLatest(scope = vmScope). Remove custom waitForState helper and shareLatest utility.
2026-03-03 17:21:55 +00:00
darken c103c6adc9 feat(widget): Migrate from RemoteViews to Jetpack Glance
Replace the legacy AppWidgetProvider/RemoteViews implementation with Glance AppWidget for reactive updates, proper centering, and a unified render state model.

- Add BatteryGlanceWidget with collectAsState for live device/profile/upgrade data

- Add WidgetRenderState sealed class and WidgetRenderStateMapper

- Add GlanceWidgetContent (Glance composables) and ComposeWidgetPreview (config preview)

- Fix centering by passing spacing via modifier param (no trailing padding on last item)

- Remove old XML widget layouts and RemoteViews rendering code
2026-03-01 15:56:43 +01:00
darken fc9bcafae9 feat(screenshots): Set up localized Play Store screenshot pipeline
- Add Compose screenshot test infrastructure (build config, screenshotTest source set)

- Add 7 localized screenshots covering all key app screens

- Device spec set to Pixel 8 (1080x2400, 428dpi); batch size 4 for 1080p memory budget

- Add screen title heading and fix appearance card header layout in WidgetConfigurationScreen

- Balance padding on requires-Pro notice in widget config bottom bar
2026-02-25 22:57:34 +01:00
darken 63692595a8 refactor(ui): Migrate from Fragments to Jetpack Compose
Replace Fragment-based UI with Jetpack Compose screens, adopting
Navigation3 for type-safe routing and Material3 theming throughout.

- Replace all Fragments/ViewHolders with Compose screens and cards
- Introduce NavigationController with Navigation3 runtime
- Add CapodTheme with Material3 design system
- Migrate PopUpWindow overlay to ComposeView with proper lifecycle
- Rewrite WidgetConfigurationActivity in Compose
- Add reusable settings composables (switch, slider, list preference)
- Update Kotlin to 2.2.10, add Compose BOM 2025.06.01
- Fix reactive state for unmatched devices toggle
- Add safety timeout for BT device enumeration
- Fix profile name validation error message
2026-02-24 15:05:09 +01:00
darken 7efcafbc71 chore: Bump Android Gradle Plugin to 9.0.1 2026-02-19 00:20:43 +01:00
darken 12d2c4dd06 fix: Pre-release cleanup of manifest, resource leaks, and dependencies
- Fix BleScanResultReceiver package name in manifest (.bluetooth → .common.bluetooth)
- Fix HandlerThread leak in BluetoothManager2 when registerReceiver() throws
- Cache battery values in MonitorNotifications to match hardening pattern
- Remove duplicate fragment-ktx dependency and align fragment-testing version
- Remove deprecated lifecycle-extensions dependency
2026-02-09 15:50:39 +01:00
darken 6223524a1e chore: Upgrade to AGP 9.0.0 and Gradle 9.3.1 2026-02-08 17:31:19 +01:00
darken ebfffb1536 fix: Replace WorkManager with ForegroundService to eliminate excessive wakelocks
Replace MonitorWorker (CoroutineWorker) with MonitorService (ForegroundService)
to eliminate persistent ProcessorForegroundLck wakelock reported in Android Vitals.
Add BootCompletedReceiver for post-reboot auto-start.
Remove WorkManager dependency entirely.
2026-02-08 14:19:11 +01:00
darken 221f3ccbed Refactor: Convert build configuration to Gradle plugin pattern
- Migrate ProjectConfig from static object to proper Gradle plugin
- Add version type support (beta/rc) to version.properties
- Clean up legacy fastlane changelogs
- Update release script to support version types
- Remove automatic fastlane changelog generation from release script
- Add BuildConfig field injection for version info
2025-10-07 13:54:24 +02:00
darken e2014a26fc Gradle update to 8.13.0 2025-09-29 14:06:34 +02:00
darken df88399e7a Remove BUILDTIME BuildConfig field
This commit removes the `BUILDTIME` field from `BuildConfig` across all modules. This change improves build caching and reproducibility by eliminating a value that changed with every build.

The `BUILDTIME` was previously used in `VERSION_DESCRIPTION_LONG` but is no longer included.
2025-08-31 15:30:12 +02:00
darken 16392d5721 Refactor buildSrc and update dependencies
This commit refactors the `buildSrc` module by:
- Removing the `setupLibraryDefaults()` extension function from `ProjectConfig.kt` as its functionality is largely covered by standard Gradle plugin configurations.
- Inlining version numbers for Moshi and various testing libraries directly into `Dependencies.kt`, removing them from `Versions.kt`. This simplifies version management for these specific libraries.
- Removing unused version declarations from `Versions.kt`.

Additionally, this commit updates the following dependencies:
- Kotlin from 2.1.21 to 2.2.10
- Android Gradle Plugin from 8.11.0 to 8.12.2
- KSP from 2.1.21-2.0.1 to 2.2.10-2.0.2
- Dagger from 2.56.2 to 2.57.1
- AndroidX Navigation from 2.8.9 to 2.9.3

The `targetSdk` was also removed from the `app-common` module's `defaultConfig` as it's typically inherited or set at the app level.
2025-08-31 15:30:12 +02:00
darken 6b2073eff2 Update AGP, SDK, and BillingClient
This commit updates:
- Android Gradle Plugin to 8.11.0
- Compile/Target SDK to 36
- Google Play Billing Library to 8.0.0

The `BillingClient` is updated to use the new `PendingPurchasesParams` and `QueryPurchasesParams` APIs.
2025-07-03 00:14:58 +02:00
darken 4c7eac870d Dependencies: Downgrade Navigation Core to 2.8.9
Navigation Core version 2.9.0 seems to have a bug causing an `ConcurrentModificationException`.

See:
https://issuetracker.google.com/issues/188860458
https://issuetracker.google.com/issues/417784831
2025-06-23 14:04:39 +02:00
darken 6712ba78ba Update app translations 2025-06-22 19:20:47 +02:00
darken c6cd8d68f7 Upgrade Android Gradle Plugin and KSP
This commit updates the Android Gradle Plugin (AGP) from version 8.10.0 to 8.10.1 and the Kotlin Symbol Processing (KSP) plugin from version 2.1.20-2.0.0 to 2.1.21-2.0.1.

These changes are applied in the root `build.gradle.kts` file and the `buildSrc/build.gradle.kts` file.
2025-06-22 18:08:22 +02:00
darken c88c57e856 Update gradle dependencies and configurations 2025-05-13 19:02:02 +02:00
Ricky Cheung 8544983984 Update com.google.android.material to 1.12.0
Signed-off-by: Ricky Cheung <rcheung844@gmail.com>
2024-07-12 12:18:24 +02:00
Matthias Urhahn 1e80d742cc Update build.gradle.kts 2024-02-25 13:04:38 +01:00
JerretQueen 3407370563 1. Fixed a typo in @string/onboarding_body2. The message now correctly says "implementation" instead of "implemtation".
2. Changed layout of overview_pods_dual_item.xml so that the left and right pod status are properly lined up with each other.
2023-12-30 00:14:24 -06:00
darken 82e8769407 Bump dependencies and API targets. 2023-10-28 17:58:09 +02:00
darken d8fb9cdd30 Remove bugsnag 2023-09-11 20:32:53 +02:00
darken 72f47bec1f Fix background execution errors.
Bump workmanager `2.7.1` -> `2.8.1` to fix

```java
android.app.ForegroundServiceStartNotAllowedException: startForegroundService() not allowed due to mAllowStartForeground false: service eu.darken.capod/androidx.work.impl.foreground.SystemForegroundService
```
2023-06-27 21:55:58 +02:00
darken ac29e28eda Fix "Missing app icon in splash screen"
> Your app does not show a 48x48dp app icon on a black background during app startup. For more information, see Branded launch.
2023-06-27 21:49:05 +02:00
darken c8aa591feb Update AGP 2023-06-27 20:28:21 +02:00
darken e0bc6dafa0 Bump gradle 2023-05-16 07:46:13 +02:00
Matthias Urhahn a3e2c9e61d Bump dependencies and gradle (#113) 2023-03-11 18:16:24 +01:00
Matthias Urhahn 0fc9716f06 Only apply Bugsnag to gplay build flavor (#88)
* wip

* Setup bugsnag only in gplay builds.

* Bugsnag does not support uploading mapping files or build information from library modules. This should be done from the application module which produces your APK instead.

* Only apply Bugsnag plugin for the right flavors.

* Run unit tests in debug, otherwise we run issues requiring api keys in the env
2023-02-01 11:17:50 +01:00
darken bddb20c5bb More version plumping 2022-10-27 17:38:50 +02:00
darken c3d4500e3a Version bump (v2.2.1-rc0) 2022-09-24 15:50:25 +02:00
darken b488a1be16 Version bump (v2.2.0-rc0) 2022-09-24 12:00:21 +02:00
darken ab619cb073 Version bump (2.1.1-rc0) 2022-09-19 22:26:43 +02:00
darken 4219bd02c5 Setup fastlane for uploading app and wearos AAB 2022-09-14 21:40:13 +02:00
darken 48544464ae Version bump 2022-09-14 21:19:07 +02:00
darken 95a8e0b125 Version bump 2022-09-14 19:55:56 +02:00
darken 84b7509f33 Adjust versioning for GPlay wear os bundle upload 2022-09-14 19:39:30 +02:00
darken a53baec9dc Version bump 2022-09-14 18:59:08 +02:00
darken 4b4bc86cf7 Fix Github release for WearOS APK 2022-09-14 18:31:34 +02:00
darken 6ea260a81f More resource cleanup 2022-09-14 18:00:18 +02:00
darken 26da600761 Fix module packagename 2022-09-14 18:00:18 +02:00
darken 87bef9cb9c Icon and reintroduce splash screen 2022-09-14 18:00:18 +02:00
darken 1d51c207f4 Basic working data display in wear-app 2022-09-14 18:00:18 +02:00
darken eb4d883194 More refactoring and modularization 2022-09-14 18:00:18 +02:00