diff --git a/android/app/src/main/java/me/kavishdevar/aln/composables/BatteryIndicator.kt b/android/app/src/main/java/me/kavishdevar/aln/composables/BatteryIndicator.kt index 89b5d38..26248fa 100644 --- a/android/app/src/main/java/me/kavishdevar/aln/composables/BatteryIndicator.kt +++ b/android/app/src/main/java/me/kavishdevar/aln/composables/BatteryIndicator.kt @@ -18,6 +18,8 @@ package me.kavishdevar.aln.composables + +import androidx.compose.animation.core.animateFloatAsState import androidx.compose.foundation.background import androidx.compose.foundation.border import androidx.compose.foundation.layout.Arrangement @@ -33,74 +35,74 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.scale import androidx.compose.ui.graphics.Color import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import me.kavishdevar.aln.R - @Composable fun BatteryIndicator(batteryPercentage: Int, charging: Boolean = false) { val batteryOutlineColor = Color(0xFFBFBFBF) val batteryFillColor = if (batteryPercentage > 30) Color(0xFF30D158) else Color(0xFFFC3C3C) val batteryTextColor = MaterialTheme.colorScheme.onSurface - // Battery indicator dimensions val batteryWidth = 40.dp val batteryHeight = 15.dp val batteryCornerRadius = 4.dp val tipWidth = 5.dp val tipHeight = batteryHeight * 0.375f + val animatedFillWidth by animateFloatAsState(targetValue = batteryPercentage / 100f) + val animatedScale by animateFloatAsState(targetValue = if (charging) 1.2f else 1f) + Column( horizontalAlignment = Alignment.CenterHorizontally ) { Row( verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(0.dp), - modifier = Modifier.padding(bottom = 4.dp) // Padding between icon and percentage text + modifier = Modifier.padding(bottom = 4.dp) ) { - // Battery Icon Box( modifier = Modifier .width(batteryWidth) .height(batteryHeight) - .border(1.dp, batteryOutlineColor, RoundedCornerShape(batteryCornerRadius)) ) { + Box ( + modifier = Modifier + .fillMaxSize() + .border(1.dp, batteryOutlineColor, RoundedCornerShape(batteryCornerRadius)) + ) Box( modifier = Modifier .fillMaxHeight() .padding(2.dp) - .width(batteryWidth * (batteryPercentage / 100f)) + .width(batteryWidth * animatedFillWidth) .background(batteryFillColor, RoundedCornerShape(2.dp)) ) if (charging) { - Box( + Text( + text = "\uDBC0\uDEE6", + fontSize = 16.sp, + fontFamily = FontFamily(Font(R.font.sf_pro)), + color = Color.White, modifier = Modifier - .padding(0.dp) + .scale(animatedScale) .fillMaxSize(), - contentAlignment = Alignment.Center - ) { - Text( - text = "\uDBC0\uDEE6", - fontSize = 15.sp, - fontFamily = FontFamily(Font(R.font.sf_pro)), - color = Color.White, - modifier = Modifier - .align(Alignment.Center) - .padding(0.dp) - ) - } + textAlign = TextAlign.Center + ) } } - Box( modifier = Modifier .width(tipWidth) diff --git a/android/app/src/main/java/me/kavishdevar/aln/composables/BatteryView.kt b/android/app/src/main/java/me/kavishdevar/aln/composables/BatteryView.kt index 70de50d..e00e628 100644 --- a/android/app/src/main/java/me/kavishdevar/aln/composables/BatteryView.kt +++ b/android/app/src/main/java/me/kavishdevar/aln/composables/BatteryView.kt @@ -127,21 +127,21 @@ fun BatteryView(service: AirPodsService, preview: Boolean = false) { .fillMaxWidth(), horizontalArrangement = Arrangement.Center ) { - if (left?.status != BatteryStatus.DISCONNECTED) { +// if (left?.status != BatteryStatus.DISCONNECTED) { BatteryIndicator( left?.level ?: 0, left?.status == BatteryStatus.CHARGING ) - } - if (left?.status != BatteryStatus.DISCONNECTED && right?.status != BatteryStatus.DISCONNECTED) { +// } +// if (left?.status != BatteryStatus.DISCONNECTED && right?.status != BatteryStatus.DISCONNECTED) { Spacer(modifier = Modifier.width(16.dp)) - } - if (right?.status != BatteryStatus.DISCONNECTED) { +// } +// if (right?.status != BatteryStatus.DISCONNECTED) { BatteryIndicator( right?.level ?: 0, right?.status == BatteryStatus.CHARGING ) - } +// } } } } @@ -160,9 +160,9 @@ fun BatteryView(service: AirPodsService, preview: Boolean = false) { .fillMaxWidth() .scale(1.25f) ) - if (case?.status != BatteryStatus.DISCONNECTED) { +// if (case?.status != BatteryStatus.DISCONNECTED) { BatteryIndicator(case?.level ?: 0, case?.status == BatteryStatus.CHARGING) - } +// } } } } diff --git a/android/app/src/main/java/me/kavishdevar/aln/composables/NoiseControlSettings.kt b/android/app/src/main/java/me/kavishdevar/aln/composables/NoiseControlSettings.kt index aa76ff3..4e1689e 100644 --- a/android/app/src/main/java/me/kavishdevar/aln/composables/NoiseControlSettings.kt +++ b/android/app/src/main/java/me/kavishdevar/aln/composables/NoiseControlSettings.kt @@ -60,6 +60,10 @@ import me.kavishdevar.aln.utils.NoiseControlMode @SuppressLint("UnspecifiedRegisterReceiverFlag") @Composable fun NoiseControlSettings(service: AirPodsService) { + val context = LocalContext.current + val sharedPreferences = context.getSharedPreferences("settings", Context.MODE_PRIVATE) + val offListeningMode = sharedPreferences.getBoolean("off_listening_mode", true) + val isDarkTheme = isSystemInDarkTheme() val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFE3E3E8) val textColor = if (isDarkTheme) Color.White else Color.Black @@ -68,15 +72,18 @@ fun NoiseControlSettings(service: AirPodsService) { val noiseControlMode = remember { mutableStateOf(NoiseControlMode.OFF) } - val d1a = remember { mutableFloatStateOf(0f) } val d2a = remember { mutableFloatStateOf(0f) } val d3a = remember { mutableFloatStateOf(0f) } fun onModeSelected(mode: NoiseControlMode, received: Boolean = false) { - noiseControlMode.value = mode - if (!received) service.setANCMode(mode.ordinal+1) - when (mode) { + if (!received && !offListeningMode && mode == NoiseControlMode.OFF) { + noiseControlMode.value = NoiseControlMode.ADAPTIVE + } else { + noiseControlMode.value = mode + } + if (!received) service.setANCMode(mode.ordinal + 1) + when (noiseControlMode.value) { NoiseControlMode.NOISE_CANCELLATION -> { d1a.floatValue = 1f d2a.floatValue = 1f @@ -106,8 +113,7 @@ fun NoiseControlSettings(service: AirPodsService) { if (intent.action == AirPodsNotifications.ANC_DATA) { noiseControlMode.value = NoiseControlMode.entries.toTypedArray()[intent.getIntExtra("data", 3) - 1] onModeSelected(noiseControlMode.value, true) - } - else if (intent.action == AirPodsNotifications.DISCONNECT_RECEIVERS) { + } else if (intent.action == AirPodsNotifications.DISCONNECT_RECEIVERS) { try { context.unregisterReceiver(this) } catch (e: IllegalArgumentException) { @@ -118,16 +124,13 @@ fun NoiseControlSettings(service: AirPodsService) { } } - val context = LocalContext.current - val noiseControlIntentFilter = IntentFilter() - .apply { - addAction(AirPodsNotifications.ANC_DATA) - addAction(AirPodsNotifications.DISCONNECT_RECEIVERS) - } + val noiseControlIntentFilter = IntentFilter().apply { + addAction(AirPodsNotifications.ANC_DATA) + addAction(AirPodsNotifications.DISCONNECT_RECEIVERS) + } if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { context.registerReceiver(noiseControlReceiver, noiseControlIntentFilter, Context.RECEIVER_EXPORTED) - } - else { + } else { context.registerReceiver(noiseControlReceiver, noiseControlIntentFilter) } @@ -157,20 +160,22 @@ fun NoiseControlSettings(service: AirPodsService) { .fillMaxWidth() .background(backgroundColor, RoundedCornerShape(14.dp)) ) { - NoiseControlButton( - icon = ImageBitmap.imageResource(R.drawable.noise_cancellation), - onClick = { onModeSelected(NoiseControlMode.OFF) }, - textColor = if (noiseControlMode.value == NoiseControlMode.OFF) textColorSelected else textColor, - backgroundColor = if (noiseControlMode.value == NoiseControlMode.OFF) selectedBackground else Color.Transparent, - modifier = Modifier.weight(1f) - ) - VerticalDivider( - thickness = 1.dp, - modifier = Modifier - .padding(vertical = 10.dp) - .alpha(d1a.floatValue), - color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f), - ) + if (offListeningMode) { + NoiseControlButton( + icon = ImageBitmap.imageResource(R.drawable.noise_cancellation), + onClick = { onModeSelected(NoiseControlMode.OFF) }, + textColor = if (noiseControlMode.value == NoiseControlMode.OFF) textColorSelected else textColor, + backgroundColor = if (noiseControlMode.value == NoiseControlMode.OFF) selectedBackground else Color.Transparent, + modifier = Modifier.weight(1f) + ) + VerticalDivider( + thickness = 1.dp, + modifier = Modifier + .padding(vertical = 10.dp) + .alpha(d1a.floatValue), + color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f), + ) + } NoiseControlButton( icon = ImageBitmap.imageResource(R.drawable.transparency), onClick = { onModeSelected(NoiseControlMode.TRANSPARENCY) }, @@ -214,13 +219,15 @@ fun NoiseControlSettings(service: AirPodsService) { .padding(horizontal = 8.dp) .padding(top = 1.dp) ) { - Text( - text = "Off", - style = TextStyle(fontSize = 12.sp, color = textColor), - textAlign = TextAlign.Center, - fontWeight = FontWeight.Bold, - modifier = Modifier.weight(1f) - ) + if (offListeningMode) { + Text( + text = "Off", + style = TextStyle(fontSize = 12.sp, color = textColor), + textAlign = TextAlign.Center, + fontWeight = FontWeight.Bold, + modifier = Modifier.weight(1f) + ) + } Text( text = "Transparency", style = TextStyle(fontSize = 12.sp, color = textColor), diff --git a/android/app/src/main/java/me/kavishdevar/aln/screens/DebugScreen.kt b/android/app/src/main/java/me/kavishdevar/aln/screens/DebugScreen.kt index a71eaa5..ba9caac 100644 --- a/android/app/src/main/java/me/kavishdevar/aln/screens/DebugScreen.kt +++ b/android/app/src/main/java/me/kavishdevar/aln/screens/DebugScreen.kt @@ -49,6 +49,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft import androidx.compose.material.icons.filled.Send +import androidx.compose.material3.CenterAlignedTopAppBar import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Icon @@ -58,7 +59,6 @@ import androidx.compose.material3.Text import androidx.compose.material3.TextButton import androidx.compose.material3.TextField import androidx.compose.material3.TextFieldDefaults -import androidx.compose.material3.TopAppBar import androidx.compose.material3.TopAppBarDefaults import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect @@ -98,7 +98,7 @@ fun DebugScreen(navController: NavController) { Scaffold( topBar = { - TopAppBar( + CenterAlignedTopAppBar( title = { Text("Debug") }, navigationIcon = { TextButton( diff --git a/android/app/src/main/java/me/kavishdevar/aln/services/AirPodsService.kt b/android/app/src/main/java/me/kavishdevar/aln/services/AirPodsService.kt index d62082c..c75beed 100644 --- a/android/app/src/main/java/me/kavishdevar/aln/services/AirPodsService.kt +++ b/android/app/src/main/java/me/kavishdevar/aln/services/AirPodsService.kt @@ -171,31 +171,31 @@ class AirPodsService: Service() { it.setTextViewText( R.id.left_battery_widget, batteryNotification.getBattery().find { it.component == BatteryComponent.LEFT }?.let { - if (it.status != BatteryStatus.DISCONNECTED) { +// if (it.status != BatteryStatus.DISCONNECTED) { "${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%" - } else { - "" - } +// } else { +// "" +// } } ?: "" ) it.setTextViewText( R.id.right_battery_widget, batteryNotification.getBattery().find { it.component == BatteryComponent.RIGHT }?.let { - if (it.status != BatteryStatus.DISCONNECTED) { +// if (it.status != BatteryStatus.DISCONNECTED) { "${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%" - } else { - "" - } +// } else { +// "" +// } } ?: "" ) it.setTextViewText( R.id.case_battery_widget, batteryNotification.getBattery().find { it.component == BatteryComponent.CASE }?.let { - if (it.status != BatteryStatus.DISCONNECTED) { +// if (it.status != BatteryStatus.DISCONNECTED) { "${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%" - } else { - "" - } +// } else { +// "" +// } } ?: "" ) } @@ -205,7 +205,7 @@ class AirPodsService: Service() { fun updateNotificationContent(connected: Boolean, airpodsName: String? = null, batteryList: List? = null) { val notificationManager = getSystemService(NotificationManager::class.java) - val textColor = this.getSharedPreferences("settings", MODE_PRIVATE).getLong("textColor", 0) +// val textColor = this.getSharedPreferences("settings", MODE_PRIVATE).getLong("textColor", 0) var updatedNotification: Notification? = null if (connected) {