Merge branch 'main' into improve-notification

This commit is contained in:
Kavish Devar
2025-01-07 01:22:00 +05:30
committed by GitHub
5 changed files with 88 additions and 79 deletions

View File

@@ -18,6 +18,8 @@
package me.kavishdevar.aln.composables package me.kavishdevar.aln.composables
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.border import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement 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.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight 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.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import me.kavishdevar.aln.R import me.kavishdevar.aln.R
@Composable @Composable
fun BatteryIndicator(batteryPercentage: Int, charging: Boolean = false) { fun BatteryIndicator(batteryPercentage: Int, charging: Boolean = false) {
val batteryOutlineColor = Color(0xFFBFBFBF) val batteryOutlineColor = Color(0xFFBFBFBF)
val batteryFillColor = if (batteryPercentage > 30) Color(0xFF30D158) else Color(0xFFFC3C3C) val batteryFillColor = if (batteryPercentage > 30) Color(0xFF30D158) else Color(0xFFFC3C3C)
val batteryTextColor = MaterialTheme.colorScheme.onSurface val batteryTextColor = MaterialTheme.colorScheme.onSurface
// Battery indicator dimensions
val batteryWidth = 40.dp val batteryWidth = 40.dp
val batteryHeight = 15.dp val batteryHeight = 15.dp
val batteryCornerRadius = 4.dp val batteryCornerRadius = 4.dp
val tipWidth = 5.dp val tipWidth = 5.dp
val tipHeight = batteryHeight * 0.375f val tipHeight = batteryHeight * 0.375f
val animatedFillWidth by animateFloatAsState(targetValue = batteryPercentage / 100f)
val animatedScale by animateFloatAsState(targetValue = if (charging) 1.2f else 1f)
Column( Column(
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
Row( Row(
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(0.dp), 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( Box(
modifier = Modifier modifier = Modifier
.width(batteryWidth) .width(batteryWidth)
.height(batteryHeight) .height(batteryHeight)
.border(1.dp, batteryOutlineColor, RoundedCornerShape(batteryCornerRadius))
) { ) {
Box (
modifier = Modifier
.fillMaxSize()
.border(1.dp, batteryOutlineColor, RoundedCornerShape(batteryCornerRadius))
)
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxHeight() .fillMaxHeight()
.padding(2.dp) .padding(2.dp)
.width(batteryWidth * (batteryPercentage / 100f)) .width(batteryWidth * animatedFillWidth)
.background(batteryFillColor, RoundedCornerShape(2.dp)) .background(batteryFillColor, RoundedCornerShape(2.dp))
) )
if (charging) { if (charging) {
Box( Text(
text = "\uDBC0\uDEE6",
fontSize = 16.sp,
fontFamily = FontFamily(Font(R.font.sf_pro)),
color = Color.White,
modifier = Modifier modifier = Modifier
.padding(0.dp) .scale(animatedScale)
.fillMaxSize(), .fillMaxSize(),
contentAlignment = Alignment.Center textAlign = TextAlign.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)
)
}
} }
} }
Box( Box(
modifier = Modifier modifier = Modifier
.width(tipWidth) .width(tipWidth)

View File

@@ -127,21 +127,21 @@ fun BatteryView(service: AirPodsService, preview: Boolean = false) {
.fillMaxWidth(), .fillMaxWidth(),
horizontalArrangement = Arrangement.Center horizontalArrangement = Arrangement.Center
) { ) {
if (left?.status != BatteryStatus.DISCONNECTED) { // if (left?.status != BatteryStatus.DISCONNECTED) {
BatteryIndicator( BatteryIndicator(
left?.level ?: 0, left?.level ?: 0,
left?.status == BatteryStatus.CHARGING 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)) Spacer(modifier = Modifier.width(16.dp))
} // }
if (right?.status != BatteryStatus.DISCONNECTED) { // if (right?.status != BatteryStatus.DISCONNECTED) {
BatteryIndicator( BatteryIndicator(
right?.level ?: 0, right?.level ?: 0,
right?.status == BatteryStatus.CHARGING right?.status == BatteryStatus.CHARGING
) )
} // }
} }
} }
} }
@@ -160,9 +160,9 @@ fun BatteryView(service: AirPodsService, preview: Boolean = false) {
.fillMaxWidth() .fillMaxWidth()
.scale(1.25f) .scale(1.25f)
) )
if (case?.status != BatteryStatus.DISCONNECTED) { // if (case?.status != BatteryStatus.DISCONNECTED) {
BatteryIndicator(case?.level ?: 0, case?.status == BatteryStatus.CHARGING) BatteryIndicator(case?.level ?: 0, case?.status == BatteryStatus.CHARGING)
} // }
} }
} }
} }

View File

@@ -60,6 +60,10 @@ import me.kavishdevar.aln.utils.NoiseControlMode
@SuppressLint("UnspecifiedRegisterReceiverFlag") @SuppressLint("UnspecifiedRegisterReceiverFlag")
@Composable @Composable
fun NoiseControlSettings(service: AirPodsService) { 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 isDarkTheme = isSystemInDarkTheme()
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFE3E3E8) val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFE3E3E8)
val textColor = if (isDarkTheme) Color.White else Color.Black val textColor = if (isDarkTheme) Color.White else Color.Black
@@ -68,15 +72,18 @@ fun NoiseControlSettings(service: AirPodsService) {
val noiseControlMode = remember { mutableStateOf(NoiseControlMode.OFF) } val noiseControlMode = remember { mutableStateOf(NoiseControlMode.OFF) }
val d1a = remember { mutableFloatStateOf(0f) } val d1a = remember { mutableFloatStateOf(0f) }
val d2a = remember { mutableFloatStateOf(0f) } val d2a = remember { mutableFloatStateOf(0f) }
val d3a = remember { mutableFloatStateOf(0f) } val d3a = remember { mutableFloatStateOf(0f) }
fun onModeSelected(mode: NoiseControlMode, received: Boolean = false) { fun onModeSelected(mode: NoiseControlMode, received: Boolean = false) {
noiseControlMode.value = mode if (!received && !offListeningMode && mode == NoiseControlMode.OFF) {
if (!received) service.setANCMode(mode.ordinal+1) noiseControlMode.value = NoiseControlMode.ADAPTIVE
when (mode) { } else {
noiseControlMode.value = mode
}
if (!received) service.setANCMode(mode.ordinal + 1)
when (noiseControlMode.value) {
NoiseControlMode.NOISE_CANCELLATION -> { NoiseControlMode.NOISE_CANCELLATION -> {
d1a.floatValue = 1f d1a.floatValue = 1f
d2a.floatValue = 1f d2a.floatValue = 1f
@@ -106,8 +113,7 @@ fun NoiseControlSettings(service: AirPodsService) {
if (intent.action == AirPodsNotifications.ANC_DATA) { if (intent.action == AirPodsNotifications.ANC_DATA) {
noiseControlMode.value = NoiseControlMode.entries.toTypedArray()[intent.getIntExtra("data", 3) - 1] noiseControlMode.value = NoiseControlMode.entries.toTypedArray()[intent.getIntExtra("data", 3) - 1]
onModeSelected(noiseControlMode.value, true) onModeSelected(noiseControlMode.value, true)
} } else if (intent.action == AirPodsNotifications.DISCONNECT_RECEIVERS) {
else if (intent.action == AirPodsNotifications.DISCONNECT_RECEIVERS) {
try { try {
context.unregisterReceiver(this) context.unregisterReceiver(this)
} catch (e: IllegalArgumentException) { } catch (e: IllegalArgumentException) {
@@ -118,16 +124,13 @@ fun NoiseControlSettings(service: AirPodsService) {
} }
} }
val context = LocalContext.current val noiseControlIntentFilter = IntentFilter().apply {
val noiseControlIntentFilter = IntentFilter() addAction(AirPodsNotifications.ANC_DATA)
.apply { addAction(AirPodsNotifications.DISCONNECT_RECEIVERS)
addAction(AirPodsNotifications.ANC_DATA) }
addAction(AirPodsNotifications.DISCONNECT_RECEIVERS)
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
context.registerReceiver(noiseControlReceiver, noiseControlIntentFilter, Context.RECEIVER_EXPORTED) context.registerReceiver(noiseControlReceiver, noiseControlIntentFilter, Context.RECEIVER_EXPORTED)
} } else {
else {
context.registerReceiver(noiseControlReceiver, noiseControlIntentFilter) context.registerReceiver(noiseControlReceiver, noiseControlIntentFilter)
} }
@@ -157,20 +160,22 @@ fun NoiseControlSettings(service: AirPodsService) {
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(14.dp))
) { ) {
NoiseControlButton( if (offListeningMode) {
icon = ImageBitmap.imageResource(R.drawable.noise_cancellation), NoiseControlButton(
onClick = { onModeSelected(NoiseControlMode.OFF) }, icon = ImageBitmap.imageResource(R.drawable.noise_cancellation),
textColor = if (noiseControlMode.value == NoiseControlMode.OFF) textColorSelected else textColor, onClick = { onModeSelected(NoiseControlMode.OFF) },
backgroundColor = if (noiseControlMode.value == NoiseControlMode.OFF) selectedBackground else Color.Transparent, textColor = if (noiseControlMode.value == NoiseControlMode.OFF) textColorSelected else textColor,
modifier = Modifier.weight(1f) backgroundColor = if (noiseControlMode.value == NoiseControlMode.OFF) selectedBackground else Color.Transparent,
) modifier = Modifier.weight(1f)
VerticalDivider( )
thickness = 1.dp, VerticalDivider(
modifier = Modifier thickness = 1.dp,
.padding(vertical = 10.dp) modifier = Modifier
.alpha(d1a.floatValue), .padding(vertical = 10.dp)
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f), .alpha(d1a.floatValue),
) color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.12f),
)
}
NoiseControlButton( NoiseControlButton(
icon = ImageBitmap.imageResource(R.drawable.transparency), icon = ImageBitmap.imageResource(R.drawable.transparency),
onClick = { onModeSelected(NoiseControlMode.TRANSPARENCY) }, onClick = { onModeSelected(NoiseControlMode.TRANSPARENCY) },
@@ -214,13 +219,15 @@ fun NoiseControlSettings(service: AirPodsService) {
.padding(horizontal = 8.dp) .padding(horizontal = 8.dp)
.padding(top = 1.dp) .padding(top = 1.dp)
) { ) {
Text( if (offListeningMode) {
text = "Off", Text(
style = TextStyle(fontSize = 12.sp, color = textColor), text = "Off",
textAlign = TextAlign.Center, style = TextStyle(fontSize = 12.sp, color = textColor),
fontWeight = FontWeight.Bold, textAlign = TextAlign.Center,
modifier = Modifier.weight(1f) fontWeight = FontWeight.Bold,
) modifier = Modifier.weight(1f)
)
}
Text( Text(
text = "Transparency", text = "Transparency",
style = TextStyle(fontSize = 12.sp, color = textColor), style = TextStyle(fontSize = 12.sp, color = textColor),

View File

@@ -49,6 +49,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
import androidx.compose.material.icons.filled.Send import androidx.compose.material.icons.filled.Send
import androidx.compose.material3.CenterAlignedTopAppBar
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@@ -58,7 +59,6 @@ import androidx.compose.material3.Text
import androidx.compose.material3.TextButton import androidx.compose.material3.TextButton
import androidx.compose.material3.TextField import androidx.compose.material3.TextField
import androidx.compose.material3.TextFieldDefaults import androidx.compose.material3.TextFieldDefaults
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
@@ -98,7 +98,7 @@ fun DebugScreen(navController: NavController) {
Scaffold( Scaffold(
topBar = { topBar = {
TopAppBar( CenterAlignedTopAppBar(
title = { Text("Debug") }, title = { Text("Debug") },
navigationIcon = { navigationIcon = {
TextButton( TextButton(

View File

@@ -171,31 +171,31 @@ class AirPodsService: Service() {
it.setTextViewText( it.setTextViewText(
R.id.left_battery_widget, R.id.left_battery_widget,
batteryNotification.getBattery().find { it.component == BatteryComponent.LEFT }?.let { 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}%" "${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%"
} else { // } else {
"" // ""
} // }
} ?: "" } ?: ""
) )
it.setTextViewText( it.setTextViewText(
R.id.right_battery_widget, R.id.right_battery_widget,
batteryNotification.getBattery().find { it.component == BatteryComponent.RIGHT }?.let { 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}%" "${if (it.status == BatteryStatus.CHARGING) "⚡" else ""} ${it.level}%"
} else { // } else {
"" // ""
} // }
} ?: "" } ?: ""
) )
it.setTextViewText( it.setTextViewText(
R.id.case_battery_widget, R.id.case_battery_widget,
batteryNotification.getBattery().find { it.component == BatteryComponent.CASE }?.let { 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}%" "${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<Battery>? = null) { fun updateNotificationContent(connected: Boolean, airpodsName: String? = null, batteryList: List<Battery>? = null) {
val notificationManager = getSystemService(NotificationManager::class.java) 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 var updatedNotification: Notification? = null
if (connected) { if (connected) {