diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index e39f632..6acef07 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -28,7 +28,7 @@ android { applicationId = "me.kavishdevar.librepods" minSdk = 33 targetSdk = 37 - versionCode = 27 + versionCode = 28 versionName = "0.2.0" } buildTypes { diff --git a/android/app/src/main/java/me/kavishdevar/librepods/MainActivity.kt b/android/app/src/main/java/me/kavishdevar/librepods/MainActivity.kt index 57c86e9..b48f92f 100644 --- a/android/app/src/main/java/me/kavishdevar/librepods/MainActivity.kt +++ b/android/app/src/main/java/me/kavishdevar/librepods/MainActivity.kt @@ -144,6 +144,7 @@ import me.kavishdevar.librepods.presentation.screens.OpenSourceLicensesScreen import me.kavishdevar.librepods.presentation.screens.PurchaseScreen import me.kavishdevar.librepods.presentation.screens.RenameScreen import me.kavishdevar.librepods.presentation.screens.TransparencySettingsScreen +import me.kavishdevar.librepods.presentation.screens.TroubleshootingScreen import me.kavishdevar.librepods.presentation.screens.UpdateHearingTestScreen import me.kavishdevar.librepods.presentation.screens.VersionScreen import me.kavishdevar.librepods.presentation.viewmodel.AirPodsViewModel @@ -473,9 +474,9 @@ fun Main() { val appSettingsViewModel: AppSettingsViewModel = viewModel() AppSettingsScreen(navController, appSettingsViewModel) } -// composable("troubleshooting") { -// TroubleshootingScreen(navController) -// } + composable("troubleshooting") { + TroubleshootingScreen(navController) + } composable("head_tracking") { if (airPodsViewModel != null) HeadTrackingScreen(airPodsViewModel, navController) } diff --git a/android/app/src/main/java/me/kavishdevar/librepods/bluetooth/AACPManager.kt b/android/app/src/main/java/me/kavishdevar/librepods/bluetooth/AACPManager.kt index 5edee79..b9c7333 100644 --- a/android/app/src/main/java/me/kavishdevar/librepods/bluetooth/AACPManager.kt +++ b/android/app/src/main/java/me/kavishdevar/librepods/bluetooth/AACPManager.kt @@ -1261,7 +1261,7 @@ class AACPManager { val start = index // find next 0x00 byte while (index < data.size && data[index] != 0x00.toByte()) index++ - val str = data.sliceArray(start..index).decodeToString() + val str = data.sliceArray(start until index).decodeToString() strings.add(str) } diff --git a/android/app/src/main/java/me/kavishdevar/librepods/presentation/components/BatteryIndicator.kt b/android/app/src/main/java/me/kavishdevar/librepods/presentation/components/BatteryIndicator.kt index c2bff84..a2a5804 100644 --- a/android/app/src/main/java/me/kavishdevar/librepods/presentation/components/BatteryIndicator.kt +++ b/android/app/src/main/java/me/kavishdevar/librepods/presentation/components/BatteryIndicator.kt @@ -31,7 +31,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size -import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -40,8 +39,10 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.scale import androidx.compose.ui.geometry.Offset +import androidx.compose.ui.geometry.Rect import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.StrokeCap +import androidx.compose.ui.graphics.drawscope.Stroke import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.Font @@ -53,6 +54,7 @@ import androidx.compose.ui.unit.sp import me.kavishdevar.librepods.R import me.kavishdevar.librepods.data.BatteryStatus import kotlin.math.cos +import kotlin.math.min import kotlin.math.sin import kotlin.math.sqrt @@ -66,8 +68,8 @@ fun BatteryIndicator( val isDarkTheme = isSystemInDarkTheme() val backgroundColor = if (isDarkTheme) Color.Black else Color(0xFFF2F2F7) val batteryTextColor = if (isDarkTheme) Color.White else Color.Black - val batteryFillColor = if (batteryPercentage > 25) - if (isDarkTheme) Color(0xFF2ED158) else Color(0xFF35C759) + val batteryFillColor = + if (batteryPercentage > 25) if (isDarkTheme) Color(0xFF2ED158) else Color(0xFF35C759) else if (isDarkTheme) Color(0xFFFC4244) else Color(0xFFfe373C) val initialScale = if (previousCharging) 1f else 0f @@ -80,27 +82,57 @@ fun BatteryIndicator( } Column( - modifier = Modifier - .background(backgroundColor), // just for haze to work + modifier = Modifier.background(backgroundColor).padding(4.dp), // just for haze to work horizontalAlignment = Alignment.CenterHorizontally ) { Box( - modifier = Modifier.padding(bottom = 4.dp), - contentAlignment = Alignment.Center + modifier = Modifier.padding(bottom = 4.dp), contentAlignment = Alignment.Center ) { val strokeWidthPx = with(LocalDensity.current) { 4.dp.toPx() } val gapFromCenterPx = with(LocalDensity.current) { 8.sp.toPx() } - if (status == BatteryStatus.OPTIMIZED_CHARGING) { - Canvas(modifier = Modifier.size(40.dp)) { - val radius = size.minDimension / 2 - val progress = batteryPercentage / 100f + val trackColor = if (isDarkTheme) Color(0xFF272728) else Color(0xFFE3E3E8) + val optimizedLimit = 0.8f + val progress = batteryPercentage / 100f - val angleDeg = -90f + 360f * progress + Canvas(modifier = Modifier.size(34.dp)) { + val startAngle = -90f + val stroke = Stroke(width = strokeWidthPx, cap = StrokeCap.Round) + val inset = strokeWidthPx / 2 + Rect( + left = inset, + top = inset, + right = size.width - inset, + bottom = size.height - inset + ) + val radius = size.minDimension / 2 + + if (status == BatteryStatus.OPTIMIZED_CHARGING) { + drawArc( + color = trackColor, + startAngle = startAngle, + sweepAngle = 360f * optimizedLimit, + useCenter = false, + style = stroke + ) + + val sweep = 360f * min(progress, optimizedLimit) + drawArc( + color = batteryFillColor, + startAngle = startAngle, + sweepAngle = sweep, + useCenter = false, + style = stroke + ) + + // ---- PILL MARKER AT 80% ---- + val angleDeg = startAngle + 360f * optimizedLimit val angleRad = Math.toRadians(angleDeg.toDouble()) - val outerX = center.x + (radius - strokeWidthPx) * cos(angleRad).toFloat() - val outerY = center.y + (radius - strokeWidthPx) * sin(angleRad).toFloat() + val arcRadius = radius - strokeWidthPx + + val outerX = center.x + arcRadius * cos(angleRad).toFloat() + val outerY = center.y + arcRadius * sin(angleRad).toFloat() val dirX = center.x - outerX val dirY = center.y - outerY @@ -116,34 +148,38 @@ fun BatteryIndicator( val endY = center.y - normY * gapFromCenterPx drawLine( - color = batteryFillColor, + color = if (batteryPercentage >= 80) batteryFillColor else trackColor, start = Offset(startX, startY), end = Offset(endX, endY), strokeWidth = strokeWidthPx, cap = StrokeCap.Round ) + } else { + drawArc( + color = trackColor, + startAngle = 0f, + sweepAngle = 360f, + useCenter = false, + style = stroke + ) + + drawArc( + color = batteryFillColor, + startAngle = startAngle, + sweepAngle = 360f * progress, + useCenter = false, + style = stroke + ) } } - CircularProgressIndicator( - progress = { batteryPercentage / 100f }, - modifier = Modifier.size(40.dp), - color = batteryFillColor, - gapSize = 0.dp, - strokeCap = StrokeCap.Round, - strokeWidth = 4.dp, - trackColor = if (isDarkTheme) Color(0xFF0E0E0F) else Color(0xFFE3E3E8) - ) - Text( - text = "\uDBC0\uDEE6", - style = TextStyle( - fontSize = 12.sp, + text = "\uDBC0\uDEE6", style = TextStyle( + fontSize = 14.sp, fontFamily = FontFamily(Font(R.font.sf_pro)), color = batteryFillColor, textAlign = TextAlign.Center - ), - modifier = Modifier.scale(scaleAnim.value) + ), modifier = Modifier.scale(scaleAnim.value) ) } @@ -153,7 +189,7 @@ fun BatteryIndicator( text = "$prefix $batteryPercentage%", color = batteryTextColor, style = TextStyle( - fontSize = 16.sp, + fontSize = 14.sp, fontFamily = FontFamily(Font(R.font.sf_pro)), textAlign = TextAlign.Center ), @@ -168,6 +204,11 @@ fun BatteryIndicatorPreview() { Box( modifier = Modifier.background(bg) ) { - BatteryIndicator(batteryPercentage = 80, status = BatteryStatus.CHARGING, prefix = "\uDBC6\uDCE5", previousCharging = false) + BatteryIndicator( + batteryPercentage = 50, + status = BatteryStatus.OPTIMIZED_CHARGING, + prefix = "\uDBC6\uDCE5", + previousCharging = false + ) } } diff --git a/android/app/src/main/java/me/kavishdevar/librepods/presentation/screens/AirPodsSettingsScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/presentation/screens/AirPodsSettingsScreen.kt index fb20234..d1b9605 100644 --- a/android/app/src/main/java/me/kavishdevar/librepods/presentation/screens/AirPodsSettingsScreen.kt +++ b/android/app/src/main/java/me/kavishdevar/librepods/presentation/screens/AirPodsSettingsScreen.kt @@ -500,23 +500,25 @@ fun AirPodsSettingsScreen(viewModel: AirPodsViewModel, navController: NavControl } Spacer(Modifier.height(32.dp)) -// StyledButton( -// onClick = { navController.navigate("troubleshooting") }, -// backdrop = backdrop, -// modifier = Modifier -// .fillMaxWidth(0.9f) -// ) { -// Text( -// text = stringResource(R.string.troubleshooting), -// style = TextStyle( -// fontSize = 16.sp, -// fontWeight = FontWeight.Medium, -// fontFamily = FontFamily(Font(R.font.sf_pro)), -// color = if (isSystemInDarkTheme()) Color.White else Color.Black -// ) -// ) -// } -// Spacer(Modifier.height(16.dp)) + if (!BuildConfig.PLAY_BUILD) { + StyledButton( + onClick = { navController.navigate("troubleshooting") }, + backdrop = backdrop, + modifier = Modifier + .fillMaxWidth(0.9f) + ) { + Text( + text = stringResource(R.string.troubleshooting), + style = TextStyle( + fontSize = 16.sp, + fontWeight = FontWeight.Medium, + fontFamily = FontFamily(Font(R.font.sf_pro)), + color = if (isSystemInDarkTheme()) Color.White else Color.Black + ) + ) + } + Spacer(Modifier.height(16.dp)) + } StyledButton( onClick = { viewModel.reconnectFromSavedMac() diff --git a/android/app/src/main/java/me/kavishdevar/librepods/presentation/screens/AppSettingsScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/presentation/screens/AppSettingsScreen.kt index 2cb741c..f46cac1 100644 --- a/android/app/src/main/java/me/kavishdevar/librepods/presentation/screens/AppSettingsScreen.kt +++ b/android/app/src/main/java/me/kavishdevar/librepods/presentation/screens/AppSettingsScreen.kt @@ -382,13 +382,15 @@ fun AppSettingsScreen( } -// NavigationButton( -// to = "troubleshooting", -// name = stringResource(R.string.troubleshooting), -// navController = navController, -// independent = true, -// description = stringResource(R.string.troubleshooting_description) -// ) + if (!BuildConfig.PLAY_BUILD) { + NavigationButton( + to = "troubleshooting", + name = stringResource(R.string.troubleshooting), + navController = navController, + independent = true, + description = stringResource(R.string.troubleshooting_description) + ) + } Spacer(modifier = Modifier.height(8.dp))