v0.2.4: fix countdown notification not appearing + wrong time-remaining
All checks were successful
build-apk / build (push) Successful in 28m23s

Countdown notification "nothing appears" on session start:
- The small icon was the adaptive launcher mipmap (applicationInfo.icon),
  which Android 13+/GrapheneOS rejects as an invalid notification small icon
  and drops the post silently. Ship a proper white-on-transparent vector
  small icon (bbp_stat_parking) inside the module and use it.
- showCountdown now returns a diagnostic string (posted / notifications
  disabled / exception) instead of swallowing failures; JS logs the branch,
  permission result, and native outcome to the in-app diagnostics log.
- Log the raw active-session payload in refreshSessionStatus (element shape
  was previously unconfirmed).

Time remaining showed "7694 min":
- API's TimeRemaining is SECONDS, not minutes. Format it as hours+minutes
  in SessionDetail; annotate the type.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Erik 2026-07-15 21:55:45 +00:00
parent 9323bbd6c6
commit 2b973348bc
7 changed files with 73 additions and 16 deletions

View file

@ -21,14 +21,21 @@ class BbpNotifyModule : Module() {
override fun definition() = ModuleDefinition {
Name("BbpNotify")
// Returns a short diagnostic string so the JS layer can log exactly what
// happened (posted / notifications-disabled / exception). "Nothing appears"
// bugs are otherwise invisible because notify() fails silently.
AsyncFunction("showCountdown") { title: String, body: String, endTimeMillis: Double ->
val ctx = appContext.reactContext ?: return@AsyncFunction
val ctx = appContext.reactContext
?: return@AsyncFunction "no-context"
ensureChannel(ctx)
val mgr = NotificationManagerCompat.from(ctx)
val enabled = mgr.areNotificationsEnabled()
val builder = NotificationCompat.Builder(ctx, CHANNEL_ID)
.setContentTitle(title)
.setContentText(body)
.setSmallIcon(ctx.applicationInfo.icon)
.setSmallIcon(R.drawable.bbp_stat_parking)
.setOngoing(true)
.setOnlyAlertOnce(true)
.setShowWhen(true)
@ -52,10 +59,14 @@ class BbpNotifyModule : Module() {
)
}
try {
NotificationManagerCompat.from(ctx).notify(NOTIF_ID, builder.build())
} catch (_: SecurityException) {
// POST_NOTIFICATIONS not granted yet; caller requests it separately.
return@AsyncFunction try {
mgr.notify(NOTIF_ID, builder.build())
"posted enabled=$enabled sdk=${Build.VERSION.SDK_INT}"
} catch (e: SecurityException) {
// POST_NOTIFICATIONS not granted.
"security-exception enabled=$enabled msg=${e.message}"
} catch (e: Exception) {
"exception enabled=$enabled ${e.javaClass.simpleName}=${e.message}"
}
}

View file

@ -0,0 +1,15 @@
<!--
Notification small icon: a white-on-transparent timer glyph (Material "timer").
Small icons MUST be a simple monochrome drawable — the app launcher mipmap
(applicationInfo.icon) is an adaptive/full-colour icon and is dropped as an
invalid small icon on Android 13+/GrapheneOS, so we ship our own here.
-->
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FFFFFFFF"
android:pathData="M15,1L9,1L9,3L15,3L15,1ZM11,14L13,14L13,8L11,8L11,14ZM19.03,7.39L20.45,5.97C20.02,5.46 19.55,4.98 19.04,4.56L17.62,5.98C16.07,4.74 14.12,4 12,4C7.03,4 3,8.03 3,13C3,17.97 7.02,22 12,22C16.98,22 21,17.97 21,13C21,10.88 20.26,8.93 19.03,7.39ZM12,20C8.13,20 5,16.87 5,13C5,9.13 8.13,6 12,6C15.87,6 19,9.13 19,13C19,16.87 15.87,20 12,20Z" />
</vector>