From cdd9d26339c62c50d53827280b097174315d0bd2 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 17 Jun 2026 16:26:54 +0000 Subject: [PATCH] Refactor whole app UI to strict Material Design 3 - Add standard Material 3 Typography and Shape definitions. - Hook up Typography and Shapes to the root MaterialTheme. - Migrate TrackingScreen to standard M3 Cards and remove legacy text colors. - Migrate HistoryScreen to M3 Cards with surfaceVariant coloration for tonal elevation. - Migrate SettingsScreen grouped sections to M3 Cards. - Migrate RoutineAnalysisScreen to M3 Cards. - Migrate PermissionScreen elements to M3 Cards. - Clean up unused string/variables triggered during cleanup. Co-authored-by: Max97k <14903047+Max97k@users.noreply.github.com> --- .../gpstracker/ui/screens/HistoryScreen.kt | 13 +- .../gpstracker/ui/screens/MainScreen.kt | 1 - .../gpstracker/ui/screens/PermissionScreen.kt | 77 +++++++----- .../ui/screens/RoutineAnalysisScreen.kt | 115 ++++++++++-------- .../gpstracker/ui/screens/SettingsScreen.kt | 25 +++- .../gpstracker/ui/screens/TrackingScreen.kt | 109 ++++++++++------- .../com/gpsspy/gpstracker/ui/theme/Shape.kt | 13 ++ .../com/gpsspy/gpstracker/ui/theme/Theme.kt | 2 + .../com/gpsspy/gpstracker/ui/theme/Type.kt | 115 ++++++++++++++++++ 9 files changed, 331 insertions(+), 139 deletions(-) create mode 100644 app/src/main/java/com/gpsspy/gpstracker/ui/theme/Shape.kt create mode 100644 app/src/main/java/com/gpsspy/gpstracker/ui/theme/Type.kt diff --git a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/HistoryScreen.kt b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/HistoryScreen.kt index 7b1a918..9b8704d 100644 --- a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/HistoryScreen.kt +++ b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/HistoryScreen.kt @@ -78,12 +78,15 @@ fun SessionItem(session: SessionSummary, onExport: () -> Unit, onDelete: () -> U val durationRemSec = durationSec % 60 val durationStr = String.format("%02d:%02d", durationMin, durationRemSec) - Card(modifier = Modifier.fillMaxWidth()) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) + ) { Column(modifier = Modifier.padding(16.dp)) { - Text(text = stringResource(R.string.history_session_num, session.sessionId), style = MaterialTheme.typography.titleMedium) + Text(text = stringResource(R.string.history_session_num, session.sessionId), style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) Spacer(modifier = Modifier.height(4.dp)) - Text(text = stringResource(R.string.history_start, startTimeStr), style = MaterialTheme.typography.bodyMedium) - Text(text = stringResource(R.string.history_duration, durationStr), style = MaterialTheme.typography.bodyMedium) + Text(text = stringResource(R.string.history_start, startTimeStr), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + Text(text = stringResource(R.string.history_duration, durationStr), style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) Spacer(modifier = Modifier.height(8.dp)) Row(modifier = Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.End) { @@ -91,7 +94,7 @@ fun SessionItem(session: SessionSummary, onExport: () -> Unit, onDelete: () -> U Text(stringResource(R.string.history_export)) } Spacer(modifier = Modifier.width(8.dp)) - Button(onClick = onDelete, colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error)) { + Button(onClick = onDelete, colors = ButtonDefaults.buttonColors(containerColor = MaterialTheme.colorScheme.error, contentColor = MaterialTheme.colorScheme.onError)) { Text(stringResource(R.string.history_delete)) } } diff --git a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/MainScreen.kt b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/MainScreen.kt index 8e1b72e..2dcc73b 100644 --- a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/MainScreen.kt +++ b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/MainScreen.kt @@ -41,7 +41,6 @@ fun MainScreen() { } } ) { innerPadding -> - Modifier.padding(innerPadding) when (selectedTab) { 0 -> TrackingScreen(modifier = Modifier.padding(innerPadding)) 1 -> HistoryScreen(modifier = Modifier.padding(innerPadding)) diff --git a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/PermissionScreen.kt b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/PermissionScreen.kt index f99c80f..79f7e27 100644 --- a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/PermissionScreen.kt +++ b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/PermissionScreen.kt @@ -72,29 +72,34 @@ fun PermissionScreen( Spacer(modifier = Modifier.height(32.dp)) // Educational Checklist - Column(modifier = Modifier.fillMaxWidth()) { - PermissionItem( - icon = Icons.Default.LocationOn, - title = stringResource(R.string.perm_loc_title), - description = stringResource(R.string.perm_loc_desc) - ) - Spacer(modifier = Modifier.height(16.dp)) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) + ) { + Column(modifier = Modifier.fillMaxWidth().padding(16.dp)) { PermissionItem( - icon = Icons.Default.Info, - title = stringResource(R.string.perm_act_title), - description = stringResource(R.string.perm_act_desc) + icon = Icons.Default.LocationOn, + title = stringResource(R.string.perm_loc_title), + description = stringResource(R.string.perm_loc_desc) ) Spacer(modifier = Modifier.height(16.dp)) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + PermissionItem( + icon = Icons.Default.Info, + title = stringResource(R.string.perm_act_title), + description = stringResource(R.string.perm_act_desc) + ) + Spacer(modifier = Modifier.height(16.dp)) + } + PermissionItem( + icon = Icons.Default.Notifications, + title = stringResource(R.string.perm_notif_title), + description = stringResource(R.string.perm_notif_desc) + ) } - PermissionItem( - icon = Icons.Default.Notifications, - title = stringResource(R.string.perm_notif_title), - description = stringResource(R.string.perm_notif_desc) - ) } - Spacer(modifier = Modifier.height(48.dp)) + Spacer(modifier = Modifier.height(32.dp)) Button(onClick = { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { notificationPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) @@ -115,17 +120,29 @@ fun PermissionScreen( } } else { // PROMINENT DISCLOSURE SCREEN (Crucial for Google Play Policy) - Text( - text = stringResource(R.string.perm_bg_title), - style = MaterialTheme.typography.headlineMedium, - textAlign = TextAlign.Center - ) - Spacer(modifier = Modifier.height(16.dp)) - Text( - text = stringResource(R.string.perm_bg_description), - style = MaterialTheme.typography.bodyLarge, - textAlign = TextAlign.Center - ) + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) + ) { + Column( + modifier = Modifier.fillMaxWidth().padding(24.dp), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text( + text = stringResource(R.string.perm_bg_title), + style = MaterialTheme.typography.headlineMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center + ) + Spacer(modifier = Modifier.height(16.dp)) + Text( + text = stringResource(R.string.perm_bg_description), + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + textAlign = TextAlign.Center + ) + } + } Spacer(modifier = Modifier.height(32.dp)) Button(onClick = { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { @@ -160,8 +177,8 @@ fun PermissionItem(icon: ImageVector, title: String, description: String) { ) Spacer(modifier = Modifier.width(16.dp)) Column { - Text(text = title, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold) - Text(text = description, style = MaterialTheme.typography.bodyMedium) + Text(text = title, style = MaterialTheme.typography.titleMedium, fontWeight = FontWeight.Bold, color = MaterialTheme.colorScheme.onSurfaceVariant) + Text(text = description, style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) } } } diff --git a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/RoutineAnalysisScreen.kt b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/RoutineAnalysisScreen.kt index 06d477f..94392a1 100644 --- a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/RoutineAnalysisScreen.kt +++ b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/RoutineAnalysisScreen.kt @@ -85,66 +85,77 @@ fun RoutineAnalysisScreen( Spacer(modifier = Modifier.height(32.dp)) - // Pie Chart - val currentSummary = summary - if (currentSummary != null && currentSummary.stateDurations.isNotEmpty()) { - val totalDuration = currentSummary.stateDurations.values.sum() - if (totalDuration > 0) { - Box(modifier = Modifier.fillMaxWidth().height(250.dp), contentAlignment = Alignment.Center) { - Canvas(modifier = Modifier.fillMaxSize()) { - var startAngle = -90f - currentSummary.stateDurations.forEach { (state, duration) -> - val sweepAngle = (duration.toFloat() / totalDuration) * 360f - val color = when (state) { - RoutineState.HOME -> Color(0xFF42A5F5) // Blue - RoutineState.WORK -> Color(0xFF66BB6A) // Green - RoutineState.MOVING -> Color(0xFFEF5350) // Red - RoutineState.OUTDOOR_STAY -> Color(0xFFFFA726) // Orange + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) + ) { + Column( + modifier = Modifier.padding(16.dp).fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + // Pie Chart + val currentSummary = summary + if (currentSummary != null && currentSummary.stateDurations.isNotEmpty()) { + val totalDuration = currentSummary.stateDurations.values.sum() + if (totalDuration > 0) { + Box(modifier = Modifier.fillMaxWidth().height(250.dp), contentAlignment = Alignment.Center) { + Canvas(modifier = Modifier.fillMaxSize()) { + var startAngle = -90f + currentSummary.stateDurations.forEach { (state, duration) -> + val sweepAngle = (duration.toFloat() / totalDuration) * 360f + val color = when (state) { + RoutineState.HOME -> Color(0xFF42A5F5) // Blue + RoutineState.WORK -> Color(0xFF66BB6A) // Green + RoutineState.MOVING -> Color(0xFFEF5350) // Red + RoutineState.OUTDOOR_STAY -> Color(0xFFFFA726) // Orange + } + drawArc( + color = color, + startAngle = startAngle, + sweepAngle = sweepAngle, + useCenter = true + ) + startAngle += sweepAngle + } } - drawArc( - color = color, - startAngle = startAngle, - sweepAngle = sweepAngle, - useCenter = true - ) - startAngle += sweepAngle } - } - } - Spacer(modifier = Modifier.height(32.dp)) + Spacer(modifier = Modifier.height(32.dp)) - // Legend and Details - Column(modifier = Modifier.fillMaxWidth()) { - currentSummary.stateDurations.forEach { (state, durationMs) -> - val hours = TimeUnit.MILLISECONDS.toHours(durationMs) - val minutes = TimeUnit.MILLISECONDS.toMinutes(durationMs) % 60 - val color = when (state) { - RoutineState.HOME -> Color(0xFF42A5F5) - RoutineState.WORK -> Color(0xFF66BB6A) - RoutineState.MOVING -> Color(0xFFEF5350) - RoutineState.OUTDOOR_STAY -> Color(0xFFFFA726) + // Legend and Details + Column(modifier = Modifier.fillMaxWidth()) { + currentSummary.stateDurations.forEach { (state, durationMs) -> + val hours = TimeUnit.MILLISECONDS.toHours(durationMs) + val minutes = TimeUnit.MILLISECONDS.toMinutes(durationMs) % 60 + val color = when (state) { + RoutineState.HOME -> Color(0xFF42A5F5) + RoutineState.WORK -> Color(0xFF66BB6A) + RoutineState.MOVING -> Color(0xFFEF5350) + RoutineState.OUTDOOR_STAY -> Color(0xFFFFA726) + } + Row(verticalAlignment = Alignment.CenterVertically) { + // Color block + Surface(color = color, modifier = Modifier.size(16.dp), shape = MaterialTheme.shapes.small) {} + Spacer(modifier = Modifier.width(8.dp)) + Text( + text = "${state.name}: $hours h $minutes min", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onSurfaceVariant, + modifier = Modifier.padding(vertical = 4.dp) + ) + } + } } - Row(verticalAlignment = Alignment.CenterVertically) { - // Color block - Surface(color = color, modifier = Modifier.size(16.dp)) {} - Spacer(modifier = Modifier.width(8.dp)) - Text( - text = "${state.name}: $hours h $minutes min", - style = MaterialTheme.typography.bodyLarge, - modifier = Modifier.padding(vertical = 4.dp) - ) + } else { + Box(modifier = Modifier.fillMaxWidth().height(250.dp), contentAlignment = Alignment.Center) { + Text("No tracking time accumulated", style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) } } + } else { + Box(modifier = Modifier.fillMaxWidth().height(250.dp), contentAlignment = Alignment.Center) { + Text("No data for this day", style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + } } - } else { - Box(modifier = Modifier.fillMaxWidth().height(250.dp), contentAlignment = Alignment.Center) { - Text("No tracking time accumulated", style = MaterialTheme.typography.titleMedium) - } - } - } else { - Box(modifier = Modifier.fillMaxWidth().height(250.dp), contentAlignment = Alignment.Center) { - Text("No data for this day", style = MaterialTheme.typography.titleMedium) } } diff --git a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/SettingsScreen.kt b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/SettingsScreen.kt index 1c0e570..829647e 100644 --- a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/SettingsScreen.kt +++ b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/SettingsScreen.kt @@ -44,11 +44,15 @@ fun SettingsScreen( ) // Home Location Section - Card(modifier = Modifier.fillMaxWidth()) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) + ) { Column(modifier = Modifier.padding(16.dp)) { Text( text = stringResource(id = R.string.settings_home_location), style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(bottom = 8.dp) ) @@ -58,12 +62,14 @@ fun SettingsScreen( Text( text = stringResource(id = R.string.settings_location_current, String.format(java.util.Locale.getDefault(), "%.5f", lat), String.format(java.util.Locale.getDefault(), "%.5f", lng)), style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(bottom = 8.dp) ) } else { Text( text = stringResource(id = R.string.settings_location_not_set), style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(bottom = 8.dp) ) } @@ -78,7 +84,6 @@ fun SettingsScreen( Spacer(modifier = Modifier.height(8.dp)) val toastHomeUpdated = stringResource(id = R.string.settings_toast_home_updated) - val toastErrorMsg = stringResource(id = R.string.settings_toast_error, "") Button( onClick = { @@ -113,11 +118,15 @@ fun SettingsScreen( } // Work Location Section - Card(modifier = Modifier.fillMaxWidth()) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) + ) { Column(modifier = Modifier.padding(16.dp)) { Text( text = stringResource(id = R.string.settings_work_location), style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(bottom = 8.dp) ) @@ -127,12 +136,14 @@ fun SettingsScreen( Text( text = stringResource(id = R.string.settings_location_current, String.format(java.util.Locale.getDefault(), "%.5f", lat), String.format(java.util.Locale.getDefault(), "%.5f", lng)), style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(bottom = 8.dp) ) } else { Text( text = stringResource(id = R.string.settings_location_not_set), style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(bottom = 8.dp) ) } @@ -147,7 +158,6 @@ fun SettingsScreen( Spacer(modifier = Modifier.height(8.dp)) val toastWorkUpdated = stringResource(id = R.string.settings_toast_work_updated) - val toastErrorMsg = stringResource(id = R.string.settings_toast_error, "") Button( onClick = { @@ -182,17 +192,22 @@ fun SettingsScreen( } // Analysis Radius Section - Card(modifier = Modifier.fillMaxWidth()) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant) + ) { Column(modifier = Modifier.padding(16.dp)) { Text( text = stringResource(id = R.string.settings_analysis_radius), style = MaterialTheme.typography.titleMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(bottom = 8.dp) ) Text( text = stringResource(id = R.string.settings_radius_meters, analysisRadius.toInt()), style = MaterialTheme.typography.bodyMedium, + color = MaterialTheme.colorScheme.onSurfaceVariant, modifier = Modifier.padding(bottom = 8.dp) ) diff --git a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/TrackingScreen.kt b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/TrackingScreen.kt index e94a19d..36da9f9 100644 --- a/app/src/main/java/com/gpsspy/gpstracker/ui/screens/TrackingScreen.kt +++ b/app/src/main/java/com/gpsspy/gpstracker/ui/screens/TrackingScreen.kt @@ -109,59 +109,76 @@ fun TrackingScreen(viewModel: TrackingViewModel = viewModel(), modifier: Modifie ) // Main Controls - Column(horizontalAlignment = Alignment.CenterHorizontally) { - Text( - text = if (isTracking) stringResource(R.string.track_status_recording) else stringResource(R.string.track_status_idle), - style = MaterialTheme.typography.titleMedium, - color = if (isTracking) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurface - ) - Spacer(modifier = Modifier.height(16.dp)) - Button( - onClick = { - haptic.performHapticFeedback(HapticFeedbackType.LongPress) - val intent = Intent(context, LocationTrackingService::class.java).apply { - action = if (isTracking) LocationTrackingService.ACTION_STOP else LocationTrackingService.ACTION_START - } - if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { - context.startForegroundService(intent) - } else { - context.startService(intent) - } - }, - modifier = Modifier.size(width = 200.dp, height = 50.dp) + Card( + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant), + modifier = Modifier.fillMaxWidth() + ) { + Column( + modifier = Modifier.padding(16.dp).fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally ) { - Icon( - imageVector = if (isTracking) Icons.Default.Close else Icons.Default.PlayArrow, - contentDescription = if (isTracking) stringResource(R.string.track_button_stop) else stringResource(R.string.track_button_start) + Text( + text = if (isTracking) stringResource(R.string.track_status_recording) else stringResource(R.string.track_status_idle), + style = MaterialTheme.typography.titleLarge, + color = if (isTracking) MaterialTheme.colorScheme.error else MaterialTheme.colorScheme.onSurfaceVariant ) - Spacer(modifier = Modifier.width(8.dp)) - Text(text = if (isTracking) stringResource(R.string.track_button_stop) else stringResource(R.string.track_button_start)) + Spacer(modifier = Modifier.height(16.dp)) + Button( + onClick = { + haptic.performHapticFeedback(HapticFeedbackType.LongPress) + val intent = Intent(context, LocationTrackingService::class.java).apply { + action = if (isTracking) LocationTrackingService.ACTION_STOP else LocationTrackingService.ACTION_START + } + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { + context.startForegroundService(intent) + } else { + context.startService(intent) + } + }, + modifier = Modifier.size(width = 200.dp, height = 50.dp) + ) { + Icon( + imageVector = if (isTracking) Icons.Default.Close else Icons.Default.PlayArrow, + contentDescription = if (isTracking) stringResource(R.string.track_button_stop) else stringResource(R.string.track_button_start) + ) + Spacer(modifier = Modifier.width(8.dp)) + Text(text = if (isTracking) stringResource(R.string.track_button_stop) else stringResource(R.string.track_button_start)) + } } } if (isTracking && currentLocation != null) { - Column( - modifier = Modifier.fillMaxWidth(), - horizontalAlignment = Alignment.CenterHorizontally + Card( + colors = CardDefaults.cardColors(containerColor = MaterialTheme.colorScheme.surfaceVariant), + modifier = Modifier.fillMaxWidth() ) { - Text(text = stringResource(R.string.track_data_title), style = MaterialTheme.typography.titleMedium) - Text(text = "Lat: ${currentLocation?.latitude}, Lon: ${currentLocation?.longitude}", style = MaterialTheme.typography.bodyMedium) - Text(text = "Alt: ${currentLocation?.altitude}m, Speed: ${currentLocation?.speed}m/s", style = MaterialTheme.typography.bodyMedium) - - Spacer(modifier = Modifier.height(8.dp)) - - Text(text = stringResource(R.string.track_gnss_title), style = MaterialTheme.typography.titleMedium) - val usedConstellations = remember(satellites) { satellites.filter { it.usedInFix }.map { it.constellationType }.toSet() } - val availableConstellations = remember(satellites) { satellites.map { it.constellationType }.toSet() } - - Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) { - availableConstellations.forEach { type -> - val name = CONSTELLATION_MAP[type] ?: "Unknown ($type)" - val color = if (usedConstellations.contains(type)) Color.Green else Color.Red - Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(horizontal = 4.dp)) { - Box(modifier = Modifier.size(10.dp).background(color, CircleShape)) - Spacer(modifier = Modifier.width(4.dp)) - Text(text = name, style = MaterialTheme.typography.bodySmall) + Column( + modifier = Modifier.padding(16.dp).fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally + ) { + Text(text = stringResource(R.string.track_data_title), style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + Spacer(modifier = Modifier.height(4.dp)) + Text(text = "Lat: ${currentLocation?.latitude}, Lon: ${currentLocation?.longitude}", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + Text(text = "Alt: ${currentLocation?.altitude}m, Speed: ${currentLocation?.speed}m/s", style = MaterialTheme.typography.bodyMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + + Spacer(modifier = Modifier.height(16.dp)) + + Text(text = stringResource(R.string.track_gnss_title), style = MaterialTheme.typography.titleMedium, color = MaterialTheme.colorScheme.onSurfaceVariant) + Spacer(modifier = Modifier.height(4.dp)) + val usedConstellations = remember(satellites) { satellites.filter { it.usedInFix }.map { it.constellationType }.toSet() } + val availableConstellations = remember(satellites) { satellites.map { it.constellationType }.toSet() } + + Row(horizontalArrangement = Arrangement.Center, modifier = Modifier.fillMaxWidth()) { + availableConstellations.forEach { type -> + val name = CONSTELLATION_MAP[type] ?: "Unknown ($type)" + // Instead of hardcoded Color.Green/Color.Red, using semantic colors if possible, but for satellite status red/green is fairly universal. + // However, we can use MaterialTheme colors to make it more M3 compliant, e.g. primary for active, error for inactive. + val color = if (usedConstellations.contains(type)) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.error + Row(verticalAlignment = Alignment.CenterVertically, modifier = Modifier.padding(horizontal = 4.dp)) { + Box(modifier = Modifier.size(10.dp).background(color, CircleShape)) + Spacer(modifier = Modifier.width(4.dp)) + Text(text = name, style = MaterialTheme.typography.bodySmall, color = MaterialTheme.colorScheme.onSurfaceVariant) + } } } } diff --git a/app/src/main/java/com/gpsspy/gpstracker/ui/theme/Shape.kt b/app/src/main/java/com/gpsspy/gpstracker/ui/theme/Shape.kt new file mode 100644 index 0000000..c9b43cd --- /dev/null +++ b/app/src/main/java/com/gpsspy/gpstracker/ui/theme/Shape.kt @@ -0,0 +1,13 @@ +package com.gpsspy.gpstracker.ui.theme + +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.Shapes +import androidx.compose.ui.unit.dp + +val Shapes = Shapes( + extraSmall = RoundedCornerShape(4.dp), + small = RoundedCornerShape(8.dp), + medium = RoundedCornerShape(12.dp), + large = RoundedCornerShape(16.dp), + extraLarge = RoundedCornerShape(28.dp) +) \ No newline at end of file diff --git a/app/src/main/java/com/gpsspy/gpstracker/ui/theme/Theme.kt b/app/src/main/java/com/gpsspy/gpstracker/ui/theme/Theme.kt index 48c4d25..08bbff5 100644 --- a/app/src/main/java/com/gpsspy/gpstracker/ui/theme/Theme.kt +++ b/app/src/main/java/com/gpsspy/gpstracker/ui/theme/Theme.kt @@ -33,6 +33,8 @@ fun GpsTrackerTheme( MaterialTheme( colorScheme = colorScheme, + typography = Typography, + shapes = Shapes, content = content ) } diff --git a/app/src/main/java/com/gpsspy/gpstracker/ui/theme/Type.kt b/app/src/main/java/com/gpsspy/gpstracker/ui/theme/Type.kt new file mode 100644 index 0000000..a9007f4 --- /dev/null +++ b/app/src/main/java/com/gpsspy/gpstracker/ui/theme/Type.kt @@ -0,0 +1,115 @@ +package com.gpsspy.gpstracker.ui.theme + +import androidx.compose.material3.Typography +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontFamily +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.unit.sp + +val Typography = Typography( + displayLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 57.sp, + lineHeight = 64.sp, + letterSpacing = (-0.25).sp + ), + displayMedium = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 45.sp, + lineHeight = 52.sp, + letterSpacing = 0.sp + ), + displaySmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 36.sp, + lineHeight = 44.sp, + letterSpacing = 0.sp + ), + headlineLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 32.sp, + lineHeight = 40.sp, + letterSpacing = 0.sp + ), + headlineMedium = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 28.sp, + lineHeight = 36.sp, + letterSpacing = 0.sp + ), + headlineSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 24.sp, + lineHeight = 32.sp, + letterSpacing = 0.sp + ), + titleLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 22.sp, + lineHeight = 28.sp, + letterSpacing = 0.sp + ), + titleMedium = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.15.sp + ), + titleSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.1.sp + ), + bodyLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 16.sp, + lineHeight = 24.sp, + letterSpacing = 0.5.sp + ), + bodyMedium = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.25.sp + ), + bodySmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Normal, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.4.sp + ), + labelLarge = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 14.sp, + lineHeight = 20.sp, + letterSpacing = 0.1.sp + ), + labelMedium = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 12.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ), + labelSmall = TextStyle( + fontFamily = FontFamily.Default, + fontWeight = FontWeight.Medium, + fontSize = 11.sp, + lineHeight = 16.sp, + letterSpacing = 0.5.sp + ) +) \ No newline at end of file