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),