feat: GPS workout UI polish and voice guidance improvements
All checks were successful
CI / update (push) Successful in 2m27s

- Start native GPS service in paused state during pre-start (notification
  shows "Waiting to start..." instead of running timer)
- Bump notification importance to IMPORTANCE_DEFAULT for lock screen
- Theme-aware glass blur overlay matching header style (dark/light mode)
- Dark Nord blue background for activity picker, audio stats panel
- Transparent overlay in pre-start, gradient fade for cancel button
- Use Toggle component for voice announcements checkbox
- Persist voice guidance settings to localStorage
- Derive voice language from page language, remove language selector
This commit is contained in:
2026-03-26 10:45:30 +01:00
parent 9e95179175
commit 3349187ebf
4 changed files with 111 additions and 60 deletions

View File

@@ -19,7 +19,7 @@ class AndroidBridge(private val context: Context) {
private var ttsForVoices: TextToSpeech? = null
@JavascriptInterface
fun startLocationService(ttsConfigJson: String) {
fun startLocationService(ttsConfigJson: String, startPaused: Boolean) {
if (context is Activity) {
// Request notification permission on Android 13+ (required for foreground service notification)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
@@ -50,6 +50,7 @@ class AndroidBridge(private val context: Context) {
val intent = Intent(context, LocationForegroundService::class.java).apply {
putExtra("ttsConfig", ttsConfigJson)
putExtra("startPaused", startPaused)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent)
@@ -58,10 +59,16 @@ class AndroidBridge(private val context: Context) {
}
}
/** Backwards-compatible overload for calls without TTS config */
/** Overload: TTS config only (not paused) */
@JavascriptInterface
fun startLocationService(ttsConfigJson: String) {
startLocationService(ttsConfigJson, false)
}
/** Overload: no args (not paused, no TTS) */
@JavascriptInterface
fun startLocationService() {
startLocationService("{}")
startLocationService("{}", false)
}
@JavascriptInterface

View File

@@ -127,10 +127,11 @@ class LocationForegroundService : Service(), TextToSpeech.OnInitListener {
}
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
val startPaused = intent?.getBooleanExtra("startPaused", false) ?: false
startTimeMs = System.currentTimeMillis()
pausedAccumulatedMs = 0L
pausedSinceMs = 0L
paused = false
pausedSinceMs = if (startPaused) startTimeMs else 0L
paused = startPaused
totalDistanceKm = 0.0
lastLat = Double.NaN
lastLng = Double.NaN
@@ -151,7 +152,11 @@ class LocationForegroundService : Service(), TextToSpeech.OnInitListener {
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
)
val notification = buildNotification("0:00", "0.00 km", "")
val notification = if (startPaused) {
buildNotification("Waiting to start...", "", "")
} else {
buildNotification("0:00", "0.00 km", "")
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(NOTIFICATION_ID, notification, android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION)
@@ -488,7 +493,7 @@ class LocationForegroundService : Service(), TextToSpeech.OnInitListener {
val channel = NotificationChannel(
CHANNEL_ID,
"GPS Tracking",
NotificationManager.IMPORTANCE_LOW
NotificationManager.IMPORTANCE_DEFAULT
).apply {
description = "Shows while GPS is recording your workout"
}