diff --git a/.idea/deploymentTargetSelector.xml b/.idea/deploymentTargetSelector.xml index c512029..a469331 100644 --- a/.idea/deploymentTargetSelector.xml +++ b/.idea/deploymentTargetSelector.xml @@ -15,6 +15,14 @@ diff --git a/wear/src/main/java/de/tstratmann/gpstracker/GPXManager.kt b/wear/src/main/java/de/tstratmann/gpstracker/GPXManager.kt index 7d4cdfa..3808239 100644 --- a/wear/src/main/java/de/tstratmann/gpstracker/GPXManager.kt +++ b/wear/src/main/java/de/tstratmann/gpstracker/GPXManager.kt @@ -25,15 +25,20 @@ class GPXManager(private val context: Context) { timeZone = TimeZone.getTimeZone("UTC") }.format(Date(location.time)) - val trkpt = """ - - ${location.altitude} - - - """.trimIndent() + val sb = StringBuilder() + sb.append("") + sb.append("${location.altitude}") + sb.append("") + if (location.speed > 0 || location.bearing > 0) { + sb.append("") + if (location.speed > 0) sb.append("${location.speed}") + if (location.bearing > 0) sb.append("${location.bearing}") + sb.append("") + } + sb.append("") val content = file.readText().removeSuffix(getGpxFooter()) - file.writeText(content + trkpt + getGpxFooter()) + file.writeText(content + sb.toString() + getGpxFooter()) } } @@ -45,6 +50,12 @@ class GPXManager(private val context: Context) { return context.filesDir.listFiles { _, name -> name.endsWith(".gpx") }?.toList() ?: emptyList() } + fun deleteAllFiles(): Int { + val files = getAllFiles() + files.forEach { it.delete() } + return files.size + } + private fun getGpxHeader() = """ diff --git a/wear/src/main/java/de/tstratmann/gpstracker/TrackingService.kt b/wear/src/main/java/de/tstratmann/gpstracker/TrackingService.kt index 5a56f3d..069c45f 100644 --- a/wear/src/main/java/de/tstratmann/gpstracker/TrackingService.kt +++ b/wear/src/main/java/de/tstratmann/gpstracker/TrackingService.kt @@ -25,11 +25,14 @@ class TrackingService : Service() { private var startTime = 0L private var lastLocation: Location? = null private var job: Job? = null + private var speedSumKmh = 0.0 + private var speedCount = 0 data class TrackingData( val durationSeconds: Long = 0, val distanceKm: Double = 0.0, - val speedKmh: Double = 0.0 + val speedKmh: Double = 0.0, + val avgSpeedKmh: Double = 0.0 ) inner class LocalBinder : Binder() { @@ -65,9 +68,16 @@ class TrackingService : Service() { lastLocation = location val speedKmh = location.speed * 3.6 + if (speedKmh > 0) { + speedSumKmh += speedKmh + speedCount++ + } + val avgSpeedKmh = if (speedCount > 0) speedSumKmh / speedCount else 0.0 + _trackingState.value = currentData.copy( distanceKm = newDistance, - speedKmh = speedKmh + speedKmh = speedKmh, + avgSpeedKmh = avgSpeedKmh ) } @@ -86,6 +96,8 @@ class TrackingService : Service() { gpxManager.startNewSession() startTime = System.currentTimeMillis() lastLocation = null + speedSumKmh = 0.0 + speedCount = 0 _trackingState.value = TrackingData() val locationRequest = LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 1000) diff --git a/wear/src/main/java/de/tstratmann/gpstracker/presentation/MainActivity.kt b/wear/src/main/java/de/tstratmann/gpstracker/presentation/MainActivity.kt index 0943713..5a819aa 100644 --- a/wear/src/main/java/de/tstratmann/gpstracker/presentation/MainActivity.kt +++ b/wear/src/main/java/de/tstratmann/gpstracker/presentation/MainActivity.kt @@ -14,6 +14,8 @@ import androidx.activity.compose.rememberLauncherForActivityResult import androidx.activity.compose.setContent import androidx.activity.result.contract.ActivityResultContracts import androidx.compose.foundation.layout.* +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.* import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier @@ -154,16 +156,18 @@ fun TrackingScreen(navController: NavHostController) { Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Column( horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center + verticalArrangement = Arrangement.Center, + modifier = Modifier.padding(horizontal = 16.dp) ) { val hours = trackingData.durationSeconds / 3600 val minutes = (trackingData.durationSeconds % 3600) / 60 val seconds = trackingData.durationSeconds % 60 val timeString = String.format("%02d:%02d:%02d", hours, minutes, seconds) - Text(text = timeString, style = MaterialTheme.typography.display1) + Text(text = timeString, style = MaterialTheme.typography.title1) Text(text = String.format("%.2f km", trackingData.distanceKm), style = MaterialTheme.typography.body1) Text(text = String.format("%.1f km/h", trackingData.speedKmh), style = MaterialTheme.typography.body1) + Text(text = String.format("Ø %.1f km/h", trackingData.avgSpeedKmh), style = MaterialTheme.typography.body2) Spacer(modifier = Modifier.height(12.dp)) @@ -200,11 +204,47 @@ fun ActivitiesScreen(navController: NavHostController) { val gpxManager = remember { GPXManager(context) } val syncManager = remember { WearSyncManager(context) } var count by remember { mutableIntStateOf(gpxManager.getActivitiesCount()) } + var showDeleteConfirm by remember { mutableStateOf(false) } + if (showDeleteConfirm) { + Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center + ) { + Text(text = "Alle löschen?", style = MaterialTheme.typography.title3) + Spacer(modifier = Modifier.height(12.dp)) + Button( + onClick = { + val deleted = gpxManager.deleteAllFiles() + count = 0 + showDeleteConfirm = false + Toast.makeText(context, "$deleted Aktivitäten gelöscht", Toast.LENGTH_SHORT).show() + }, + colors = ButtonDefaults.buttonColors(backgroundColor = Color.Red), + modifier = Modifier.fillMaxWidth(0.8f) + ) { + Text("Ja, löschen", color = Color.White) + } + Spacer(modifier = Modifier.height(8.dp)) + Button( + onClick = { showDeleteConfirm = false }, + modifier = Modifier.fillMaxWidth(0.8f), + colors = ButtonDefaults.secondaryButtonColors() + ) { + Text("Abbrechen") + } + } + } + return + } + + val scrollState = rememberScrollState() Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) { Column( horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.Center + verticalArrangement = Arrangement.Center, + modifier = Modifier.verticalScroll(scrollState).padding(vertical = 16.dp) ) { Text(text = "$count Aktivitäten", style = MaterialTheme.typography.title3) Spacer(modifier = Modifier.height(12.dp)) @@ -230,6 +270,14 @@ fun ActivitiesScreen(navController: NavHostController) { Text("GPX Sync") } Spacer(modifier = Modifier.height(8.dp)) + Button( + onClick = { showDeleteConfirm = true }, + modifier = Modifier.fillMaxWidth(0.8f), + colors = ButtonDefaults.buttonColors(backgroundColor = Color.Red) + ) { + Text("Alle löschen", color = Color.White) + } + Spacer(modifier = Modifier.height(8.dp)) Button( onClick = { navController.popBackStack() }, modifier = Modifier.fillMaxWidth(0.8f),