diff --git a/android/app/libs/backdrop-debug.aar b/android/app/libs/backdrop-debug.aar
index d8d5bff..2a687c7 100644
Binary files a/android/app/libs/backdrop-debug.aar and b/android/app/libs/backdrop-debug.aar differ
diff --git a/android/app/libs/backdrop-release.aar b/android/app/libs/backdrop-release.aar
index 306297b..6aad2de 100644
Binary files a/android/app/libs/backdrop-release.aar and b/android/app/libs/backdrop-release.aar differ
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/AudioSettings.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/AudioSettings.kt
index ddf746b..d0df514 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/AudioSettings.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/AudioSettings.kt
@@ -51,22 +51,22 @@ fun AudioSettings(navController: NavController) {
val textColor = if (isDarkTheme) Color.White else Color.Black
Text(
- text = stringResource(R.string.audio).uppercase(),
+ text = stringResource(R.string.audio),
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f)
),
- modifier = Modifier.padding(8.dp, bottom = 2.dp)
+ modifier = Modifier.padding(16.dp, bottom = 4.dp)
)
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
Column(
modifier = Modifier
- .clip(RoundedCornerShape(14.dp))
+ .clip(RoundedCornerShape(28.dp))
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp))
+ .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(top = 2.dp)
) {
@@ -76,11 +76,12 @@ fun AudioSettings(navController: NavController) {
controlCommandIdentifier = AACPManager.Companion.ControlCommandIdentifiers.ADAPTIVE_VOLUME_CONFIG,
independent = false
)
+
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888),
modifier = Modifier
- .padding(start = 12.dp, end = 0.dp)
+ .padding(horizontal= 12.dp)
)
StyledToggle(
@@ -90,10 +91,10 @@ fun AudioSettings(navController: NavController) {
independent = false
)
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888),
modifier = Modifier
- .padding(start = 12.dp, end = 0.dp)
+ .padding(horizontal= 12.dp)
)
StyledToggle(
@@ -103,10 +104,10 @@ fun AudioSettings(navController: NavController) {
independent = false
)
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888),
modifier = Modifier
- .padding(start = 12.dp, end = 0.dp)
+ .padding(horizontal= 12.dp)
)
NavigationButton(
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/BatteryIndicator.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/BatteryIndicator.kt
index 8aba9a0..3beef1c 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/BatteryIndicator.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/BatteryIndicator.kt
@@ -27,7 +27,9 @@ import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.layout.height
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -71,7 +73,6 @@ fun BatteryIndicator(
Column(
modifier = Modifier
- .padding(12.dp)
.background(backgroundColor), // just for haze to work
horizontalAlignment = Alignment.CenterHorizontally
) {
@@ -85,7 +86,7 @@ fun BatteryIndicator(
color = batteryFillColor,
gapSize = 0.dp,
strokeCap = StrokeCap.Round,
- strokeWidth = 2.dp,
+ strokeWidth = 4.dp,
trackColor = if (isDarkTheme) Color(0xFF0E0E0F) else Color(0xFFE3E3E8)
)
@@ -101,6 +102,8 @@ fun BatteryIndicator(
)
}
+ Spacer(modifier = Modifier.height(4.dp))
+
Text(
text = "$prefix $batteryPercentage%",
color = batteryTextColor,
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/BatteryView.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/BatteryView.kt
index a993c17..992d1e6 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/BatteryView.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/BatteryView.kt
@@ -146,7 +146,7 @@ fun BatteryView(service: AirPodsService, preview: Boolean = false) {
contentDescription = stringResource(R.string.buds),
modifier = Modifier
.fillMaxWidth()
- .padding(12.dp)
+ .padding(8.dp)
)
if (
leftCharging == rightCharging &&
@@ -202,7 +202,7 @@ fun BatteryView(service: AirPodsService, preview: Boolean = false) {
contentDescription = stringResource(R.string.case_alt),
modifier = Modifier
.fillMaxWidth()
- .padding(12.dp)
+ .padding(8.dp)
)
if (caseLevel > 0 || case?.status != BatteryStatus.DISCONNECTED) {
BatteryIndicator(
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/CallControlSettings.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/CallControlSettings.kt
index 3a06981..e42b849 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/CallControlSettings.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/CallControlSettings.kt
@@ -32,12 +32,8 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material3.HorizontalDivider
-import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
@@ -57,6 +53,8 @@ import androidx.compose.ui.layout.positionInParent
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
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.tooling.preview.Preview
import androidx.compose.ui.unit.dp
@@ -76,19 +74,19 @@ fun CallControlSettings(hazeState: HazeState) {
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
Text(
- text = stringResource(R.string.call_controls).uppercase(),
+ text = stringResource(R.string.call_controls),
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f)
),
- modifier = Modifier.padding(8.dp, bottom = 2.dp)
+ modifier = Modifier.padding(16.dp, bottom = 4.dp)
)
Column(
modifier = Modifier
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp))
+ .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(top = 2.dp)
) {
val service = ServiceManager.getService()!!
@@ -169,8 +167,8 @@ fun CallControlSettings(hazeState: HazeState) {
Row(
modifier = Modifier
.fillMaxWidth()
- .padding(start = 12.dp, end = 12.dp)
- .height(50.dp),
+ .padding(horizontal = 16.dp)
+ .height(58.dp),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
@@ -187,17 +185,17 @@ fun CallControlSettings(hazeState: HazeState) {
)
}
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888),
modifier = Modifier
- .padding(start = 12.dp, end = 0.dp)
+ .padding(horizontal = 12.dp)
)
Row(
modifier = Modifier
.fillMaxWidth()
- .padding(start = 12.dp, end = 12.dp)
- .height(50.dp)
+ .padding(horizontal = 16.dp)
+ .height(58.dp)
.pointerInput(Unit) {
detectTapGestures { offset ->
val now = System.currentTimeMillis()
@@ -276,14 +274,21 @@ fun CallControlSettings(hazeState: HazeState) {
) {
Text(
text = singlePressAction,
- fontSize = 16.sp,
- color = textColor.copy(alpha = 0.8f)
+ style = TextStyle(
+ fontSize = 16.sp,
+ color = textColor.copy(alpha = 0.8f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ )
)
- Icon(
- Icons.Default.KeyboardArrowDown,
- contentDescription = null,
- modifier = Modifier.size(18.dp),
- tint = textColor.copy(alpha = 0.6f)
+ Text(
+ text = "",
+ style = TextStyle(
+ fontSize = 16.sp,
+ color = textColor.copy(alpha = 0.6f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ ),
+ modifier = Modifier
+ .padding(start = 6.dp)
)
}
@@ -315,17 +320,17 @@ fun CallControlSettings(hazeState: HazeState) {
}
}
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888),
modifier = Modifier
- .padding(start = 12.dp, end = 0.dp)
+ .padding(horizontal = 12.dp)
)
Row(
modifier = Modifier
.fillMaxWidth()
- .padding(start = 12.dp, end = 12.dp)
- .height(50.dp)
+ .padding(horizontal = 16.dp)
+ .height(58.dp)
.pointerInput(Unit) {
detectTapGestures { offset ->
val now = System.currentTimeMillis()
@@ -404,14 +409,21 @@ fun CallControlSettings(hazeState: HazeState) {
) {
Text(
text = doublePressAction,
- fontSize = 16.sp,
- color = textColor.copy(alpha = 0.8f)
+ style = TextStyle(
+ fontSize = 16.sp,
+ color = textColor.copy(alpha = 0.8f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ )
)
- Icon(
- Icons.Default.KeyboardArrowDown,
- contentDescription = null,
- modifier = Modifier.size(18.dp),
- tint = textColor.copy(alpha = 0.6f)
+ Text(
+ text = "",
+ style = TextStyle(
+ fontSize = 16.sp,
+ color = textColor.copy(alpha = 0.6f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ ),
+ modifier = Modifier
+ .padding(start = 6.dp)
)
}
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/ConfirmationDialog.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/ConfirmationDialog.kt
index 18139ec..f08f448 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/ConfirmationDialog.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/ConfirmationDialog.kt
@@ -74,7 +74,6 @@ import com.kyant.backdrop.effects.blur
import com.kyant.backdrop.effects.colorControls
import com.kyant.backdrop.effects.refraction
import com.kyant.backdrop.highlight.Highlight
-import com.kyant.backdrop.highlight.HighlightStyle
import kotlinx.coroutines.launch
import me.kavishdevar.librepods.R
import me.kavishdevar.librepods.utils.inspectDragGestures
@@ -143,7 +142,9 @@ half4 main(float2 coord) {
.drawBackdrop(
backdrop,
{ RoundedCornerShape(48f.dp) },
- highlight = { Highlight { HighlightStyle.Solid } },
+ highlight = {
+ Highlight.SolidDefault
+ },
onDrawSurface = { drawRect(containerColor) },
effects = {
colorControls(
@@ -153,7 +154,7 @@ half4 main(float2 coord) {
blur(if (isLightTheme) 16f.dp.toPx() else 8f.dp.toPx())
refraction(24f.dp.toPx(), 48f.dp.toPx(), true)
},
- layer = {
+ layerBlock = {
val width = size.width
val height = size.height
@@ -273,16 +274,6 @@ half4 main(float2 coord) {
horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically
) {
- // Box(
- // Modifier
- // .clip(RoundedCornerShape(50.dp))
- // .background(containerColor.copy(0.2f))
- // .clickable(onClick = onDismiss)
- // .height(48.dp)
- // .weight(1f)
- // .padding(horizontal = 16.dp),
- // contentAlignment = Alignment.Center
- // ) {
StyledButton(
onClick = onDismiss,
backdrop = backdrop,
@@ -295,16 +286,6 @@ half4 main(float2 coord) {
style = TextStyle(contentColor, 16.sp)
)
}
- // Box(
- // Modifier
- // .clip(RoundedCornerShape(50.dp))
- // .background(accentColor)
- // .clickable(onClick = onConfirm)
- // .height(48.dp)
- // .weight(1f)
- // .padding(horizontal = 16.dp),
- // contentAlignment = Alignment.Center
- // ) {
StyledButton(
onClick = onConfirm,
backdrop = backdrop,
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/ConnectionSettings.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/ConnectionSettings.kt
index 90106e4..9bf8417 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/ConnectionSettings.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/ConnectionSettings.kt
@@ -20,6 +20,7 @@
package me.kavishdevar.librepods.composables
+import android.content.Context.MODE_PRIVATE
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Column
@@ -34,11 +35,9 @@ import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
-import kotlin.io.encoding.ExperimentalEncodingApi
-import android.content.Context.MODE_PRIVATE
-import me.kavishdevar.librepods.composables.StyledToggle
-import me.kavishdevar.librepods.utils.AACPManager
import me.kavishdevar.librepods.R
+import me.kavishdevar.librepods.utils.AACPManager
+import kotlin.io.encoding.ExperimentalEncodingApi
@Composable
fun ConnectionSettings() {
@@ -48,7 +47,7 @@ fun ConnectionSettings() {
Column(
modifier = Modifier
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp))
+ .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(top = 2.dp)
) {
StyledToggle(
@@ -59,10 +58,10 @@ fun ConnectionSettings() {
independent = false
)
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888),
modifier = Modifier
- .padding(start = 12.dp, end = 0.dp)
+ .padding(horizontal= 12.dp)
)
StyledToggle(
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/MicrophoneSettings.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/MicrophoneSettings.kt
index 4f88af0..2c1b4a0 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/MicrophoneSettings.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/MicrophoneSettings.kt
@@ -32,11 +32,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.KeyboardArrowDown
-import androidx.compose.material3.Icon
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
@@ -55,6 +51,9 @@ import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInParent
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource
+import androidx.compose.ui.text.TextStyle
+import androidx.compose.ui.text.font.Font
+import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
@@ -75,7 +74,7 @@ fun MicrophoneSettings(hazeState: HazeState) {
Column(
modifier = Modifier
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp))
+ .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(top = 2.dp)
) {
val service = ServiceManager.getService()!!
@@ -141,8 +140,8 @@ fun MicrophoneSettings(hazeState: HazeState) {
Row(
modifier = Modifier
.fillMaxWidth()
- .padding(start = 12.dp, end = 12.dp)
- .height(55.dp)
+ .padding(horizontal = 16.dp)
+ .height(58.dp)
.pointerInput(Unit) {
detectTapGestures { offset ->
val now = System.currentTimeMillis()
@@ -214,8 +213,11 @@ fun MicrophoneSettings(hazeState: HazeState) {
) {
Text(
text = stringResource(R.string.microphone_mode),
- fontSize = 16.sp,
- color = textColor,
+ style = TextStyle(
+ fontSize = 16.sp,
+ color = textColor,
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ ),
modifier = Modifier.padding(bottom = 4.dp)
)
Box(
@@ -228,14 +230,21 @@ fun MicrophoneSettings(hazeState: HazeState) {
) {
Text(
text = selectedMode,
- fontSize = 16.sp,
- color = textColor.copy(alpha = 0.8f)
+ style = TextStyle(
+ fontSize = 16.sp,
+ color = textColor.copy(alpha = 0.8f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ )
)
- Icon(
- Icons.Default.KeyboardArrowDown,
- contentDescription = null,
- modifier = Modifier.size(16.dp),
- tint = textColor.copy(alpha = 0.6f)
+ Text(
+ text = "",
+ style = TextStyle(
+ fontSize = 16.sp,
+ color = textColor.copy(alpha = 0.6f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ ),
+ modifier = Modifier
+ .padding(start = 6.dp)
)
}
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/NameField.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/NameField.kt
deleted file mode 100644
index 399adc4..0000000
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/NameField.kt
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * LibrePods - AirPods liberated from Apple’s ecosystem
- *
- * Copyright (C) 2025 LibrePods contributors
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published
- * by the Free Software Foundation, either version 3 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see .
- */
-
-package me.kavishdevar.librepods.composables
-
-import androidx.compose.animation.animateColorAsState
-import androidx.compose.animation.core.tween
-import androidx.compose.foundation.background
-import androidx.compose.foundation.gestures.detectTapGestures
-import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
-import androidx.compose.foundation.layout.Row
-import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
-import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
-import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.foundation.text.BasicTextField
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
-import androidx.compose.material3.Icon
-import androidx.compose.material3.Text
-import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
-import androidx.compose.ui.Modifier
-import androidx.compose.ui.focus.onFocusChanged
-import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.graphics.SolidColor
-import androidx.compose.ui.input.pointer.pointerInput
-import androidx.compose.ui.text.TextStyle
-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 androidx.navigation.NavController
-import androidx.navigation.compose.rememberNavController
-
-@Composable
-fun NameField(
- name: String,
- value: String,
- navController: NavController
-) {
- var isFocused by remember { mutableStateOf(false) }
-
- val isDarkTheme = isSystemInDarkTheme()
-
- var backgroundColor by remember { mutableStateOf(if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
- val animatedBackgroundColor by animateColorAsState(targetValue = backgroundColor, animationSpec = tween(durationMillis = 500))
-
- val textColor = if (isDarkTheme) Color.White else Color.Black
- val cursorColor = if (isFocused) {
- if (isDarkTheme) Color.White else Color.Black
- } else {
- Color.Transparent
- }
-
- Box (
- modifier = Modifier
- .background(animatedBackgroundColor, RoundedCornerShape(14.dp))
- .pointerInput(Unit) {
- detectTapGestures(
- onPress = {
- backgroundColor = if (isDarkTheme) Color(0x40888888) else Color(0x40D9D9D9)
- tryAwaitRelease()
- backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
- },
- onTap = {
- navController.navigate("rename")
- }
- )
- }
- ) {
- Row(
- verticalAlignment = Alignment.CenterVertically,
- modifier = Modifier
- .fillMaxWidth()
- .height(55.dp)
- .background(
- animatedBackgroundColor,
- RoundedCornerShape(14.dp)
- )
- .padding(horizontal = 16.dp, vertical = 8.dp)
-
- ) {
- Text(
- text = name,
- style = TextStyle(
- fontSize = 16.sp,
- color = textColor
- )
- )
- BasicTextField(
- value = value,
- textStyle = TextStyle(
- color = textColor.copy(alpha = 0.75f),
- fontSize = 16.sp,
- textAlign = TextAlign.End
- ),
- onValueChange = {},
- singleLine = true,
- enabled = false,
- cursorBrush = SolidColor(cursorColor),
- modifier = Modifier
- .fillMaxWidth()
- .padding(start = 8.dp)
- .onFocusChanged { focusState ->
- isFocused = focusState.isFocused
- },
- decorationBox = { innerTextField ->
- Row(
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.End
- ) {
- innerTextField()
- Icon(
- imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
- contentDescription = "Edit name",
- tint = textColor.copy(alpha = 0.75f),
- modifier = Modifier
- .size(32.dp)
- )
- }
- }
- )
- }
- }
-}
-
-@Preview
-@Composable
-fun StyledTextFieldPreview() {
- NameField(name = "Name", value = "AirPods Pro", rememberNavController())
-}
\ No newline at end of file
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/NavigationButton.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/NavigationButton.kt
index 0baa894..8175654 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/NavigationButton.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/NavigationButton.kt
@@ -1,17 +1,17 @@
/*
* LibrePods - AirPods liberated from Apple’s ecosystem
- *
+ *
* Copyright (C) 2025 LibrePods contributors
- *
+ *
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License.
- *
+ *
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
- *
+ *
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see .
*/
@@ -23,75 +23,105 @@ import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.KeyboardArrowRight
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
-import androidx.compose.material3.IconButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
+import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
+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.tooling.preview.Preview
import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
-
+import me.kavishdevar.librepods.R
@Composable
-fun NavigationButton(to: String, name: String, navController: NavController, onClick: (() -> Unit)? = null, independent: Boolean = true) {
+fun NavigationButton(
+ to: String,
+ name: String,
+ navController: NavController, onClick: (() -> Unit)? = null,
+ independent: Boolean = true,
+ description: String? = null,
+ currentState: String? = null
+) {
val isDarkTheme = isSystemInDarkTheme()
var backgroundColor by remember { mutableStateOf(if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
val animatedBackgroundColor by animateColorAsState(targetValue = backgroundColor, animationSpec = tween(durationMillis = 500))
-
- Row(
- modifier = Modifier
- .background(animatedBackgroundColor, RoundedCornerShape(if (independent) 14.dp else 0.dp))
- .height(55.dp)
- .pointerInput(Unit) {
- detectTapGestures(
- onPress = {
- backgroundColor = if (isDarkTheme) Color(0x40888888) else Color(0x40D9D9D9)
- tryAwaitRelease()
- backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
- },
- onTap = {
- if (onClick != null) onClick() else navController.navigate(to)
- }
+ Column {
+ Row(
+ modifier = Modifier
+ .background(animatedBackgroundColor, RoundedCornerShape(if (independent) 28.dp else 0.dp))
+ .height(58.dp)
+ .pointerInput(Unit) {
+ detectTapGestures(
+ onPress = {
+ backgroundColor = if (isDarkTheme) Color(0x40888888) else Color(0x40D9D9D9)
+ tryAwaitRelease()
+ backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
+ },
+ onTap = {
+ if (onClick != null) onClick() else navController.navigate(to)
+ }
+ )
+ }
+ .padding(horizontal = 16.dp),
+ verticalAlignment = Alignment.CenterVertically,
+ ) {
+ Text(
+ text = name,
+ style = TextStyle(
+ fontSize = 16.sp,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ color = if (isDarkTheme) Color.White else Color.Black,
+ )
+ )
+ Spacer(modifier = Modifier.weight(1f))
+ if (currentState != null) {
+ Text(
+ text = currentState,
+ style = TextStyle(
+ fontSize = 16.sp,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ color = if (isDarkTheme) Color.White.copy(alpha = 0.6f) else Color.Black.copy(alpha = 0.8f),
+ )
)
}
- ) {
- Text(
- text = name,
- modifier = Modifier.padding(16.dp),
- color = if (isDarkTheme) Color.White else Color.Black
- )
- Spacer(modifier = Modifier.weight(1f))
- IconButton(
- onClick = { if (onClick != null) onClick() else navController.navigate(to) },
- colors = IconButtonDefaults.iconButtonColors(
- containerColor = Color.Transparent,
- contentColor = if (isDarkTheme) Color.White else Color.Black
- ),
- modifier = Modifier
- .padding(start = 16.dp)
- .fillMaxHeight()
- ) {
- @Suppress("DEPRECATION")
- Icon(
- imageVector = Icons.Default.KeyboardArrowRight,
- contentDescription = name
+ Text(
+ text = "",
+ style = TextStyle(
+ fontSize = 16.sp,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ color = if (isDarkTheme) Color.White.copy(alpha = 0.6f) else Color.Black.copy(alpha = 0.6f)
+ ),
+ modifier = Modifier
+ .padding(start = if (currentState != null) 6.dp else 0.dp)
+ )
+ }
+ if (description != null) {
+ Text(
+ text = description,
+ style = TextStyle(
+ fontSize = 12.sp,
+ fontWeight = FontWeight.Light,
+ color = if (isDarkTheme) Color.White.copy(alpha = 0.6f) else Color.Black.copy(alpha = 0.6f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ ),
+ modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp)
)
}
}
@@ -101,4 +131,4 @@ fun NavigationButton(to: String, name: String, navController: NavController, onC
@Composable
fun NavigationButtonPreview() {
NavigationButton("to", "Name", NavController(LocalContext.current))
-}
\ No newline at end of file
+}
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/NoiseControlSettings.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/NoiseControlSettings.kt
index 648e610..d031a8c 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/NoiseControlSettings.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/NoiseControlSettings.kt
@@ -181,10 +181,10 @@ fun NoiseControlSettings(
}
Text(
- text = stringResource(R.string.noise_control).uppercase(),
+ text = stringResource(R.string.noise_control),
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f),
),
modifier = Modifier.padding(8.dp, bottom = 2.dp)
@@ -241,7 +241,7 @@ fun NoiseControlSettings(
modifier = Modifier
.fillMaxWidth()
.height(60.dp)
- .background(backgroundColor, RoundedCornerShape(14.dp))
+ .background(backgroundColor, RoundedCornerShape(28.dp))
) {
Row(
modifier = Modifier.fillMaxWidth()
@@ -334,7 +334,7 @@ fun NoiseControlSettings(
modifier = Modifier
.fillMaxSize()
.padding(3.dp)
- .background(selectedBackground, RoundedCornerShape(12.dp))
+ .background(selectedBackground, RoundedCornerShape(26.dp))
)
}
@@ -400,7 +400,6 @@ fun NoiseControlSettings(
Row(
modifier = Modifier
.fillMaxWidth()
- .padding(horizontal = 4.dp)
.padding(top = 4.dp)
) {
if (offListeningMode.value) {
@@ -408,7 +407,6 @@ fun NoiseControlSettings(
text = stringResource(R.string.off),
style = TextStyle(fontSize = 12.sp, color = textColor),
textAlign = TextAlign.Center,
- fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f)
)
}
@@ -416,21 +414,18 @@ fun NoiseControlSettings(
text = stringResource(R.string.transparency),
style = TextStyle(fontSize = 12.sp, color = textColor),
textAlign = TextAlign.Center,
- fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f)
)
Text(
text = stringResource(R.string.adaptive),
style = TextStyle(fontSize = 12.sp, color = textColor),
textAlign = TextAlign.Center,
- fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f)
)
Text(
text = stringResource(R.string.noise_cancellation),
style = TextStyle(fontSize = 12.sp, color = textColor),
textAlign = TextAlign.Center,
- fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f)
)
}
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/PressAndHoldSettings.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/PressAndHoldSettings.kt
index 53af719..b4cb081 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/PressAndHoldSettings.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/PressAndHoldSettings.kt
@@ -19,34 +19,21 @@
package me.kavishdevar.librepods.composables
import android.content.Context
-import androidx.compose.animation.animateColorAsState
-import androidx.compose.animation.core.tween
+import android.content.res.Configuration
import androidx.compose.foundation.background
-import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.isSystemInDarkTheme
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material3.HorizontalDivider
-import androidx.compose.material3.Icon
-import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
-import androidx.compose.runtime.getValue
-import androidx.compose.runtime.mutableStateOf
-import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
+import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
@@ -65,12 +52,6 @@ fun PressAndHoldSettings(navController: NavController) {
val isDarkTheme = isSystemInDarkTheme()
val textColor = if (isDarkTheme) Color.White else Color.Black
val dividerColor = Color(0x40888888)
- var leftBackgroundColor by remember { mutableStateOf(if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
- var rightBackgroundColor by remember { mutableStateOf(if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
-
- val animationSpec = tween(durationMillis = 500)
- val animatedLeftBackgroundColor by animateColorAsState(targetValue = leftBackgroundColor, animationSpec = animationSpec)
- val animatedRightBackgroundColor by animateColorAsState(targetValue = rightBackgroundColor, animationSpec = animationSpec)
val context = LocalContext.current
val sharedPreferences = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
@@ -91,14 +72,14 @@ fun PressAndHoldSettings(navController: NavController) {
}
Text(
- text = stringResource(R.string.press_and_hold_airpods).uppercase(),
+ text = stringResource(R.string.press_and_hold_airpods),
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
- modifier = Modifier.padding(8.dp, bottom = 2.dp)
+ modifier = Modifier.padding(16.dp, bottom = 4.dp)
)
Spacer(modifier = Modifier.height(1.dp))
@@ -106,126 +87,33 @@ fun PressAndHoldSettings(navController: NavController) {
Column(
modifier = Modifier
.fillMaxWidth()
- .background(if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF), RoundedCornerShape(14.dp))
+ .background(if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF), RoundedCornerShape(28.dp))
+ .clip(RoundedCornerShape(28.dp))
) {
- Box(
- modifier = Modifier
- .fillMaxWidth()
- .height(50.dp)
- .background(animatedLeftBackgroundColor, RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp))
- .pointerInput(Unit) {
- detectTapGestures(
- onPress = {
- leftBackgroundColor = dividerColor
- tryAwaitRelease()
- leftBackgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
- },
- onTap = {
- navController.navigate("long_press/Left")
- }
- )
- },
- contentAlignment = Alignment.Center
- ) {
- Row(
- modifier = Modifier
- .padding(start = 16.dp),
- verticalAlignment = Alignment.CenterVertically
- ) {
- Text(
- text = stringResource(R.string.left),
- style = TextStyle(
- fontSize = 16.sp,
- color = textColor,
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- )
- Spacer(modifier = Modifier.weight(1f))
- Text(
- text = leftActionText,
- style = TextStyle(
- fontSize = 16.sp,
- color = textColor.copy(alpha = 0.6f),
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- )
- IconButton(
- onClick = {
- navController.navigate("long_press/Left")
- }
- ) {
- Icon(
- imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
- contentDescription = "go",
- tint = textColor
- )
- }
- }
- }
+ NavigationButton(
+ to = "long_press/Left",
+ name = stringResource(R.string.left),
+ navController = navController,
+ independent = false,
+ currentState = leftActionText,
+ )
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = dividerColor,
modifier = Modifier
- .padding(start = 16.dp)
+ .padding(horizontal = 16.dp)
+ )
+ NavigationButton(
+ to = "long_press/Right",
+ name = stringResource(R.string.right),
+ navController = navController,
+ independent = false,
+ currentState = rightActionText,
)
- Box(
- modifier = Modifier
- .fillMaxWidth()
- .height(50.dp)
- .background(animatedRightBackgroundColor, RoundedCornerShape(bottomEnd = 14.dp, bottomStart = 14.dp))
- .pointerInput(Unit) {
- detectTapGestures(
- onPress = {
- rightBackgroundColor = dividerColor
- tryAwaitRelease()
- rightBackgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
- },
- onTap = {
- navController.navigate("long_press/Right")
- }
- )
- },
- contentAlignment = Alignment.Center
- ) {
- Row(
- modifier = Modifier
- .padding(start = 16.dp),
- verticalAlignment = Alignment.CenterVertically
- ) {
- Text(
- text = stringResource(R.string.right),
- style = TextStyle(
- fontSize = 16.sp,
- color = textColor,
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- )
- Spacer(modifier = Modifier.weight(1f))
- Text(
- text = rightActionText,
- style = TextStyle(
- fontSize = 16.sp,
- color = textColor.copy(alpha = 0.6f),
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- )
- IconButton(
- onClick = {
- navController.navigate("long_press/Right")
- }
- ) {
- Icon(
- imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
- contentDescription = "go",
- tint = textColor
- )
- }
- }
- }
}
}
-@Preview
+@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@Composable
fun PressAndHoldSettingsPreview() {
PressAndHoldSettings(navController = NavController(LocalContext.current))
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledButton.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledButton.kt
index ce68372..41258bf 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledButton.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledButton.kt
@@ -74,7 +74,8 @@ fun StyledButton(
isInteractive: Boolean = true,
tint: Color = Color.Unspecified,
surfaceColor: Color = Color.Unspecified,
- content: @Composable RowScope.() -> Unit
+ maxScale: Float = 0.1f,
+ content: @Composable RowScope.() -> Unit,
) {
val animationScope = rememberCoroutineScope()
val progressAnimation = remember { Animatable(0f) }
@@ -113,7 +114,7 @@ half4 main(float2 coord) {
effects = {
blur(16f.dp.toPx())
},
- layer = null,
+ layerBlock = null,
onDrawSurface = {
if (tint.isSpecified) {
drawRect(tint, blendMode = BlendMode.Hue)
@@ -147,12 +148,11 @@ half4 main(float2 coord) {
blur(2f.dp.toPx())
refraction(12f.dp.toPx(), 24f.dp.toPx())
},
- layer = {
+ layerBlock = {
val width = size.width
val height = size.height
val progress = progressAnimation.value
- val maxScale = 0.1f
val scale = lerp(1f, 1f + maxScale, progress)
val maxOffset = size.minDimension
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledDropdown.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledDropdown.kt
index 46168b8..73cf744 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledDropdown.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledDropdown.kt
@@ -230,7 +230,7 @@ fun StyledDropdown(
if (index != options.lastIndex) {
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888),
modifier = Modifier.padding(start = 12.dp, end = 0.dp)
)
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledIconButton.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledIconButton.kt
index 4e94193..2f59f72 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledIconButton.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledIconButton.kt
@@ -24,6 +24,7 @@ import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.VisibilityThreshold
import androidx.compose.animation.core.spring
+import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
@@ -59,8 +60,10 @@ import androidx.compose.ui.unit.sp
import androidx.compose.ui.util.fastCoerceAtMost
import androidx.compose.ui.util.fastCoerceIn
import androidx.compose.ui.util.lerp
+import com.kyant.backdrop.backdrops.LayerBackdrop
import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import com.kyant.backdrop.drawBackdrop
+import com.kyant.backdrop.effects.blur
import com.kyant.backdrop.effects.refractionWithDispersion
import com.kyant.backdrop.highlight.Highlight
import com.kyant.backdrop.shadow.Shadow
@@ -79,6 +82,8 @@ fun StyledIconButton(
icon: String,
darkMode: Boolean,
tint: Color = Color.Unspecified,
+ backdrop: LayerBackdrop = rememberLayerBackdrop(),
+ modifier: Modifier = Modifier,
) {
val animationScope = rememberCoroutineScope()
val progressAnimationSpec = spring(0.5f, 300f, 0.001f)
@@ -110,26 +115,23 @@ half4 main(float2 coord) {
null
}
}
-
+ val isDarkTheme = isSystemInDarkTheme()
TextButton(
onClick = onClick,
shape = RoundedCornerShape(56.dp),
- modifier = Modifier
+ modifier = modifier
.padding(horizontal = 12.dp)
.drawBackdrop(
- backdrop = rememberLayerBackdrop(),
+ backdrop = backdrop,
shape = { RoundedCornerShape(56.dp) },
- highlight = {
- val progress = progressAnimation.value
- Highlight.AmbientDefault.copy(alpha = progress.coerceIn(0.45f, 1f))
- },
+ highlight = { Highlight.AmbientDefault.copy(alpha = if (isDarkTheme) 1f else 0f) },
shadow = {
Shadow(
- radius = 4f.dp,
- color = Color.Black.copy(0.08f)
+ radius = 48f.dp,
+ color = Color.Black.copy(if (isDarkTheme) 0.08f else 0.4f)
)
},
- layer = {
+ layerBlock = {
val width = size.width
val height = size.height
@@ -182,7 +184,7 @@ half4 main(float2 coord) {
drawLayer(innerShadowLayer)
drawRect(
- Color.White.copy(progress.coerceIn(0.15f, 0.35f))
+ (if (isDarkTheme) Color(0xFFAFAFAF) else Color.White).copy(progress.coerceIn(0.15f, 0.35f))
)
},
onDrawFront = {
@@ -218,6 +220,7 @@ half4 main(float2 coord) {
},
effects = {
refractionWithDispersion(6f.dp.toPx(), size.height / 2f)
+ blur(24f, TileMode.Decal)
},
)
.pointerInput(animationScope) {
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSlider.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSlider.kt
index b0544cd..caa1644 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSlider.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSlider.kt
@@ -31,12 +31,14 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
@@ -84,6 +86,7 @@ import com.kyant.backdrop.highlight.Highlight
import com.kyant.backdrop.shadow.Shadow
import kotlinx.coroutines.launch
import me.kavishdevar.librepods.R
+import kotlin.math.abs
import kotlin.math.roundToInt
@Composable
@@ -136,23 +139,26 @@ fun StyledSlider(
val content = @Composable {
Box(
- Modifier.fillMaxWidth(if (startIcon == null && endIcon == null) 0.95f else 1f)
- ) {
+ Modifier
+ .fillMaxWidth(if (startIcon == null && endIcon == null) 0.95f else 1f)
+ ) {
Box(
Modifier
+ .padding(vertical = 4.dp)
.layerBackdrop(sliderBackdrop)
- .fillMaxWidth()) {
+ .fillMaxWidth()
+ ) {
Column(
modifier = Modifier
.fillMaxWidth(1f)
.padding(vertical = 12.dp),
horizontalAlignment = Alignment.CenterHorizontally,
- verticalArrangement = Arrangement.spacedBy(12.dp)
) {
if (startLabel != null || endLabel != null) {
Row(
modifier = Modifier
- .fillMaxWidth(),
+ .fillMaxWidth()
+ .padding(horizontal = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
@@ -174,80 +180,119 @@ fun StyledSlider(
)
)
}
+ Spacer(modifier = Modifier.height(12.dp))
}
-
- Row(
+ Column(
modifier = Modifier
.fillMaxWidth()
.padding(vertical = 4.dp)
- .then(if (startIcon == null && endIcon == null) Modifier.padding(horizontal = 12.dp) else Modifier),
- verticalAlignment = Alignment.CenterVertically,
- horizontalArrangement = Arrangement.spacedBy(0.dp)
+ .then(if (startIcon == null && endIcon == null) Modifier.padding(horizontal = 8.dp) else Modifier),
) {
- if (startIcon != null) {
- Text(
- text = startIcon,
- style = TextStyle(
- fontSize = 18.sp,
- fontWeight = FontWeight.Normal,
- color = accentColor,
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- modifier = Modifier
- .padding(horizontal = 12.dp)
- .onGloballyPositioned {
- startIconWidthState.floatValue = it.size.width.toFloat()
- }
- )
- }
- Box(
- Modifier
- .weight(1f)
- .onSizeChanged { trackWidthState.floatValue = it.width.toFloat() }
- .onGloballyPositioned {
- trackPositionState.floatValue =
- it.positionInParent().y + it.size.height / 2f
- }
+ Row(
+ verticalAlignment = Alignment.CenterVertically,
+ horizontalArrangement = Arrangement.spacedBy(0.dp)
) {
- Box(
- Modifier
- .clip(RoundedCornerShape(28.dp))
- .background(trackColor)
- .height(6f.dp)
- .fillMaxWidth()
- )
-
- Box(
- Modifier
- .clip(RoundedCornerShape(28.dp))
- .background(accentColor)
- .height(6f.dp)
- .layout { measurable, constraints ->
- val placeable = measurable.measure(constraints)
- val fraction = fraction
- val width =
- (fraction * constraints.maxWidth).fastRoundToInt()
- layout(width, placeable.height) {
- placeable.place(0, 0)
+ if (startIcon != null) {
+ Text(
+ text = startIcon,
+ style = TextStyle(
+ fontSize = 18.sp,
+ fontWeight = FontWeight.Normal,
+ color = accentColor,
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ ),
+ modifier = Modifier
+ .padding(horizontal = 12.dp)
+ .onGloballyPositioned {
+ startIconWidthState.floatValue = it.size.width.toFloat()
}
- }
- )
- }
- if (endIcon != null) {
- Text(
- text = endIcon,
- style = TextStyle(
- fontSize = 18.sp,
- fontWeight = FontWeight.Normal,
- color = accentColor,
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- modifier = Modifier
- .padding(horizontal = 12.dp)
+ )
+ }
+ Box(
+ Modifier
+ .weight(1f)
+ .onSizeChanged { trackWidthState.floatValue = it.width.toFloat() }
.onGloballyPositioned {
- endIconWidthState.floatValue = it.size.width.toFloat()
+ trackPositionState.floatValue =
+ it.positionInParent().y + it.size.height / 2f
}
- )
+ ) {
+ Box(
+ Modifier
+ .clip(RoundedCornerShape(28.dp))
+ .background(trackColor)
+ .height(6f.dp)
+ .fillMaxWidth()
+ )
+
+ Box(
+ Modifier
+ .clip(RoundedCornerShape(28.dp))
+ .background(accentColor)
+ .height(6f.dp)
+ .layout { measurable, constraints ->
+ val placeable = measurable.measure(constraints)
+ val fraction = fraction
+ val width =
+ (fraction * constraints.maxWidth).fastRoundToInt()
+ layout(width, placeable.height) {
+ placeable.place(0, 0)
+ }
+ }
+ )
+ }
+ if (endIcon != null) {
+ Text(
+ text = endIcon,
+ style = TextStyle(
+ fontSize = 18.sp,
+ fontWeight = FontWeight.Normal,
+ color = accentColor,
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ ),
+ modifier = Modifier
+ .padding(horizontal = 12.dp)
+ .onGloballyPositioned {
+ endIconWidthState.floatValue = it.size.width.toFloat()
+ }
+ )
+ }
+ }
+ if (snapPoints.isNotEmpty() && startLabel != null && endLabel != null) Spacer(modifier = Modifier.height(4.dp))
+ Row(
+ modifier = Modifier
+ .fillMaxWidth(),
+ horizontalArrangement = Arrangement.Center
+ ) {
+ if (snapPoints.isNotEmpty()) {
+ val trackWidth = if (startIcon != null && endIcon != null) trackWidthState.floatValue - with(density) { 6.dp.toPx() } * 2 else trackWidthState.floatValue- with(density) { 22.dp.toPx() }
+ val startOffset =
+ if (startIcon != null) startIconWidthState.floatValue + with(
+ density
+ ) { 34.dp.toPx() } else with(density) { 14.dp.toPx() }
+ Box(
+ Modifier
+ .fillMaxWidth()
+ ) {
+ snapPoints.forEach { point ->
+ val pointFraction =
+ ((point - valueRange.start) / (valueRange.endInclusive - valueRange.start))
+ .fastCoerceIn(0f, 1f)
+ Box(
+ Modifier
+ .graphicsLayer {
+ translationX =
+ startOffset + pointFraction * trackWidth - 4.dp.toPx()
+ }
+ .size(2.dp)
+ .background(
+ trackColor,
+ CircleShape
+ )
+ )
+ }
+ }
+ }
}
}
}
@@ -257,10 +302,10 @@ fun StyledSlider(
Modifier
.graphicsLayer {
val startOffset =
- if (startIcon != null) startIconWidthState.floatValue + with(density) { 24.dp.toPx() } else with(density) { 8.dp.toPx() }
+ if (startIcon != null) startIconWidthState.floatValue + with(density) { 24.dp.toPx() } else with(density) { 12.dp.toPx() }
translationX =
startOffset + fraction * trackWidthState.floatValue - size.width / 2f
- translationY = if (startLabel != null || endLabel != null) trackPositionState.floatValue + with(density) { 22.dp.toPx() } + size.height / 2f else trackPositionState.floatValue + with(density) { 4.dp.toPx() }
+ translationY = if (startLabel != null || endLabel != null) trackPositionState.floatValue + with(density) { 26.dp.toPx() } + size.height / 2f else trackPositionState.floatValue + with(density) { 8.dp.toPx() }
}
.draggable(
rememberDraggableState { delta ->
@@ -305,7 +350,7 @@ fun StyledSlider(
color = Color.Black.copy(0.05f)
)
},
- layer = {
+ layerBlock = {
val progress = progressAnimation.value
val scale = lerp(1f, 1.5f, progress)
scaleX = scale
@@ -361,20 +406,20 @@ fun StyledSlider(
text = label,
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = labelTextColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
- modifier = Modifier.padding(8.dp)
+ modifier = Modifier.padding(horizontal = 18.dp, vertical = 4.dp)
)
}
Box(
modifier = Modifier
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp))
+ .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(horizontal = 8.dp, vertical = 0.dp)
- .heightIn(min = 55.dp),
+ .heightIn(min = 58.dp),
contentAlignment = Alignment.Center
) {
content()
@@ -390,7 +435,7 @@ fun StyledSlider(
fontFamily = FontFamily(Font(R.font.sf_pro))
),
modifier = Modifier
- .padding(horizontal = 12.dp, vertical = 4.dp)
+ .padding(horizontal = 18.dp, vertical = 4.dp)
)
}
}
@@ -402,8 +447,8 @@ fun StyledSlider(
}
private fun snapIfClose(value: Float, points: List, threshold: Float = 0.05f): Float {
- val nearest = points.minByOrNull { kotlin.math.abs(it - value) } ?: value
- return if (kotlin.math.abs(nearest - value) <= threshold) nearest else value
+ val nearest = points.minByOrNull { abs(it - value) } ?: value
+ return if (abs(nearest - value) <= threshold) nearest else value
}
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@@ -426,9 +471,11 @@ fun StyledSliderPreview() {
a.floatValue = it
},
valueRange = 0f..2f,
+ snapPoints = listOf(0f, 0.5f, 1f, 1.5f, 2f),
+ snapThreshold = 0.1f,
independent = true,
startLabel = "A",
- endLabel = "B"
+ endLabel = "B",
)
}
}
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSwitch.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSwitch.kt
index 4786c0f..94ea690 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSwitch.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSwitch.kt
@@ -48,8 +48,11 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.BlurEffect
import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.TileMode
import androidx.compose.ui.graphics.drawOutline
+import androidx.compose.ui.graphics.drawscope.drawIntoCanvas
+import androidx.compose.ui.graphics.drawscope.scale
import androidx.compose.ui.graphics.drawscope.translate
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.layer.CompositingStrategy
@@ -68,7 +71,7 @@ import com.kyant.backdrop.drawBackdrop
import com.kyant.backdrop.effects.refractionWithDispersion
import com.kyant.backdrop.highlight.Highlight
import com.kyant.backdrop.shadow.Shadow
-import kotlinx.coroutines.delay
+import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
@Composable
@@ -76,16 +79,17 @@ fun StyledSwitch(
checked: Boolean,
onCheckedChange: (Boolean) -> Unit,
enabled: Boolean = true,
+ indpendent: Boolean = true,
) {
val isDarkTheme = isSystemInDarkTheme()
val onColor = if (enabled) Color(0xFF34C759) else if (isDarkTheme) Color(0xFF5B5B5E) else Color(0xFFD1D1D6)
val offColor = if (enabled) if (isDarkTheme) Color(0xFF5B5B5E) else Color(0xFFD1D1D6) else if (isDarkTheme) Color(0xFF5B5B5E) else Color(0xFFD1D1D6)
- val trackWidth = 70.dp
- val trackHeight = 31.dp
- val thumbHeight = 27.dp
- val thumbWidth = 36.dp
+ val trackWidth = 64.dp
+ val trackHeight = 28.dp
+ val thumbHeight = 24.dp
+ val thumbWidth = 39.dp
val backdrop = rememberLayerBackdrop()
val switchBackdrop = rememberLayerBackdrop()
@@ -97,18 +101,23 @@ fun StyledSwitch(
val density = LocalDensity.current
val animationScope = rememberCoroutineScope()
val progressAnimationSpec = spring(0.5f, 300f, 0.001f)
- val colorAnimationSpec = tween(300, easing = FastOutSlowInEasing)
+ val colorAnimationSpec = tween(200, easing = FastOutSlowInEasing)
val progressAnimation = remember { Animatable(0f) }
val innerShadowLayer = rememberGraphicsLayer().apply {
compositingStrategy = CompositingStrategy.Offscreen
}
val animatedTrackColor = remember { Animatable(if (checked) onColor else offColor) }
-
LaunchedEffect(checked) {
- val targetColor = if (checked) onColor else offColor
- animatedTrackColor.animateTo(targetColor, colorAnimationSpec)
- val targetFrac = if (checked) 1f else 0f
- animatedFraction.animateTo(targetFrac, progressAnimationSpec)
+ coroutineScope {
+ launch {
+ val targetColor = if (checked) onColor else offColor
+ animatedTrackColor.animateTo(targetColor, colorAnimationSpec)
+ }
+ launch {
+ val targetFrac = if (checked) 1f else 0f
+ animatedFraction.animateTo(targetFrac, progressAnimationSpec)
+ }
+ }
}
Box(
@@ -136,7 +145,7 @@ fun StyledSwitch(
.then(if (enabled) Modifier.draggable(
rememberDraggableState { delta ->
if (trackWidthPx.floatValue > 0f) {
- val newFraction = (animatedFraction.value + delta / trackWidthPx.floatValue).fastCoerceIn(0f, 1f)
+ val newFraction = (animatedFraction.value + delta / trackWidthPx.floatValue).fastCoerceIn(-0.3f, 1.3f)
animationScope.launch {
animatedFraction.snapTo(newFraction)
}
@@ -155,10 +164,12 @@ fun StyledSwitch(
},
onDragStopped = {
animationScope.launch {
- progressAnimation.animateTo(0f, progressAnimationSpec)
val snappedFraction = if (animatedFraction.value >= 0.5f) 1f else 0f
- animatedFraction.animateTo(snappedFraction, progressAnimationSpec)
onCheckedChange(snappedFraction >= 0.5f)
+ coroutineScope {
+ launch { progressAnimation.animateTo(0f, progressAnimationSpec) }
+ launch { animatedFraction.animateTo(snappedFraction, progressAnimationSpec) }
+ }
}
}
) else Modifier)
@@ -175,12 +186,27 @@ fun StyledSwitch(
color = Color.Black.copy(0.05f)
)
},
- layer = {
+ layerBlock = {
val progress = progressAnimation.value
- val scale = lerp(1f, 2f, progress)
+ val scale = lerp(1f, 1.6f, progress)
scaleX = scale
scaleY = scale
},
+ onDrawBackdrop = { drawScope ->
+ drawIntoCanvas { canvas ->
+ canvas.save()
+ canvas.drawRect(0f, 0f, size.width, size.height, Paint().apply {
+ color = if (indpendent) {
+ if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7)
+ } else {
+ if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
+ }
+ })
+ scale(0.75f) {
+ drawScope()
+ }
+ }
+ },
onDrawSurface = {
val progress = progressAnimation.value.fastCoerceIn(0f, 1f)
@@ -224,12 +250,12 @@ fun StyledSwitch(
@Composable
fun StyledSwitchPreview() {
val isDarkTheme = isSystemInDarkTheme()
- val backgroundColor = if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7)
+ val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFF2F2F7)
Box(
modifier = Modifier
.background(backgroundColor)
.width(100.dp)
- .height(100.dp),
+ .height(400.dp),
contentAlignment = Alignment.Center
) {
val checked = remember { mutableStateOf(true) }
@@ -238,13 +264,14 @@ fun StyledSwitchPreview() {
onCheckedChange = {
checked.value = it
},
- enabled = true
+ enabled = true,
+ indpendent = false
)
- LaunchedEffect(Unit) {
- delay(1000)
- checked.value = false
- delay(1000)
- checked.value = true
- }
+// LaunchedEffect(Unit) {
+// delay(1000)
+// checked.value = false
+// delay(1000)
+// checked.value = true
+// }
}
}
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledToggle.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledToggle.kt
index 99567b9..920fe7f 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledToggle.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledToggle.kt
@@ -75,6 +75,7 @@ fun StyledToggle(
sharedPreferenceKey: String? = null,
sharedPreferences: SharedPreferences? = null,
independent: Boolean = true,
+ enabled: Boolean = true,
onCheckedChange: ((Boolean) -> Unit)? = null,
) {
val isDarkTheme = isSystemInDarkTheme()
@@ -82,7 +83,9 @@ fun StyledToggle(
var checked by checkedState
var backgroundColor by remember { mutableStateOf(if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
val animatedBackgroundColor by animateColorAsState(targetValue = backgroundColor, animationSpec = tween(durationMillis = 500))
-
+ if (sharedPreferenceKey != null && sharedPreferences != null) {
+ checked = sharedPreferences.getBoolean(sharedPreferenceKey, checked)
+ }
fun cb() {
if (sharedPreferences != null) {
if (sharedPreferenceKey == null) {
@@ -101,15 +104,16 @@ fun StyledToggle(
text = title,
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f)
),
- modifier = Modifier.padding(8.dp, bottom = 4.dp)
+ modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 4.dp)
)
}
Box(
modifier = Modifier
- .background(animatedBackgroundColor, RoundedCornerShape(14.dp))
+ .background(animatedBackgroundColor, RoundedCornerShape(28.dp))
+ .padding(4.dp)
.pointerInput(Unit) {
detectTapGestures(
onPress = {
@@ -120,8 +124,10 @@ fun StyledToggle(
if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
},
onTap = {
- checked = !checked
- cb()
+ if (enabled) {
+ checked = !checked
+ cb()
+ }
}
)
}
@@ -145,10 +151,14 @@ fun StyledToggle(
)
StyledSwitch(
checked = checked,
+ enabled = enabled,
onCheckedChange = {
- checked = it
- cb()
- }
+ if (enabled) {
+ checked = it
+ cb()
+ }
+ },
+ indpendent = true
)
}
}
@@ -156,7 +166,7 @@ fun StyledToggle(
Spacer(modifier = Modifier.height(8.dp))
Box(
modifier = Modifier
- .padding(horizontal = 8.dp)
+ .padding(horizontal = 16.dp)
.background(if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7))
) {
Text(
@@ -177,10 +187,10 @@ fun StyledToggle(
modifier = Modifier
.fillMaxWidth()
.background(
- shape = RoundedCornerShape(14.dp),
+ shape = RoundedCornerShape(28.dp),
color = if (isPressed.value) Color(0xFFE0E0E0) else Color.Transparent
)
- .padding(horizontal = 12.dp, vertical = 12.dp)
+ .padding(16.dp)
.pointerInput(Unit) {
detectTapGestures(
onPress = {
@@ -194,8 +204,10 @@ fun StyledToggle(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
- checked = !checked
- cb()
+ if (enabled) {
+ checked = !checked
+ cb()
+ }
},
verticalAlignment = Alignment.CenterVertically
) {
@@ -206,25 +218,35 @@ fun StyledToggle(
) {
Text(
text = label,
- fontSize = 16.sp,
- color = textColor
+ style = TextStyle(
+ fontSize = 16.sp,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ fontWeight = FontWeight.Normal,
+ color = textColor
+ )
)
Spacer(modifier = Modifier.height(4.dp))
if (description != null) {
Text(
text = description,
- fontSize = 12.sp,
- color = textColor.copy(0.6f),
- lineHeight = 14.sp,
+ style = TextStyle(
+ fontSize = 12.sp,
+ color = textColor.copy(0.6f),
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ )
)
}
}
StyledSwitch(
checked = checked,
+ enabled = enabled,
onCheckedChange = {
- checked = it
- cb()
- }
+ if (enabled) {
+ checked = it
+ cb()
+ }
+ },
+ indpendent = false
)
}
}
@@ -237,6 +259,7 @@ fun StyledToggle(
description: String? = null,
controlCommandIdentifier: AACPManager.Companion.ControlCommandIdentifiers,
independent: Boolean = true,
+ enabled: Boolean = true,
sharedPreferenceKey: String? = null,
sharedPreferences: SharedPreferences? = null,
onCheckedChange: ((Boolean) -> Unit)? = null,
@@ -291,15 +314,16 @@ fun StyledToggle(
text = title,
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f)
),
- modifier = Modifier.padding(8.dp, bottom = 4.dp)
+ modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 4.dp)
)
}
Box(
modifier = Modifier
- .background(animatedBackgroundColor, RoundedCornerShape(14.dp))
+ .background(animatedBackgroundColor, RoundedCornerShape(28.dp))
+ .padding(4.dp)
.pointerInput(Unit) {
detectTapGestures(
onPress = {
@@ -310,8 +334,10 @@ fun StyledToggle(
if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
},
onTap = {
- checked = !checked
- cb()
+ if (enabled) {
+ checked = !checked
+ cb()
+ }
}
)
}
@@ -335,10 +361,14 @@ fun StyledToggle(
)
StyledSwitch(
checked = checked,
+ enabled = enabled,
onCheckedChange = {
- checked = it
- cb()
- }
+ if (enabled) {
+ checked = it
+ cb()
+ }
+ },
+ indpendent = true
)
}
}
@@ -346,7 +376,7 @@ fun StyledToggle(
Spacer(modifier = Modifier.height(8.dp))
Box(
modifier = Modifier
- .padding(horizontal = 8.dp)
+ .padding(horizontal = 16.dp)
.background(if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7))
) {
Text(
@@ -367,10 +397,10 @@ fun StyledToggle(
modifier = Modifier
.fillMaxWidth()
.background(
- shape = RoundedCornerShape(14.dp),
+ shape = RoundedCornerShape(28.dp),
color = if (isPressed.value) Color(0xFFE0E0E0) else Color.Transparent
)
- .padding(horizontal = 12.dp, vertical = 12.dp)
+ .padding(16.dp)
.pointerInput(Unit) {
detectTapGestures(
onPress = {
@@ -384,8 +414,10 @@ fun StyledToggle(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
- checked = !checked
- cb()
+ if (enabled) {
+ checked = !checked
+ cb()
+ }
},
verticalAlignment = Alignment.CenterVertically
) {
@@ -396,25 +428,35 @@ fun StyledToggle(
) {
Text(
text = label,
- fontSize = 16.sp,
- color = textColor
+ style = TextStyle(
+ fontSize = 16.sp,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ fontWeight = FontWeight.Normal,
+ color = textColor
+ )
)
Spacer(modifier = Modifier.height(4.dp))
if (description != null) {
Text(
text = description,
- fontSize = 12.sp,
- color = textColor.copy(0.6f),
- lineHeight = 14.sp,
+ style = TextStyle(
+ fontSize = 12.sp,
+ color = textColor.copy(0.6f),
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ )
)
}
}
StyledSwitch(
checked = checked,
+ enabled = enabled,
onCheckedChange = {
- checked = it
- cb()
- }
+ if (enabled) {
+ checked = it
+ cb()
+ }
+ },
+ indpendent = false
)
}
}
@@ -427,6 +469,7 @@ fun StyledToggle(
description: String? = null,
attHandle: ATTHandles,
independent: Boolean = true,
+ enabled: Boolean = true,
sharedPreferenceKey: String? = null,
sharedPreferences: SharedPreferences? = null,
onCheckedChange: ((Boolean) -> Unit)? = null,
@@ -509,15 +552,16 @@ fun StyledToggle(
text = title,
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f)
),
- modifier = Modifier.padding(8.dp, bottom = 4.dp)
+ modifier = Modifier.padding(start = 16.dp, end = 16.dp, top = 8.dp, bottom = 4.dp)
)
}
Box(
modifier = Modifier
- .background(animatedBackgroundColor, RoundedCornerShape(14.dp))
+ .background(animatedBackgroundColor, RoundedCornerShape(28.dp))
+ .padding(4.dp)
.pointerInput(Unit) {
detectTapGestures(
onPress = {
@@ -528,8 +572,10 @@ fun StyledToggle(
if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
},
onTap = {
- checked = !checked
- cb()
+ if (enabled) {
+ checked = !checked
+ cb()
+ }
}
)
}
@@ -553,10 +599,14 @@ fun StyledToggle(
)
StyledSwitch(
checked = checked,
+ enabled = enabled,
onCheckedChange = {
- checked = it
- cb()
- }
+ if (enabled) {
+ checked = it
+ cb()
+ }
+ },
+ indpendent = true
)
}
}
@@ -564,7 +614,7 @@ fun StyledToggle(
Spacer(modifier = Modifier.height(8.dp))
Box(
modifier = Modifier
- .padding(horizontal = 8.dp)
+ .padding(horizontal = 16.dp)
.background(if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7))
) {
Text(
@@ -585,10 +635,10 @@ fun StyledToggle(
modifier = Modifier
.fillMaxWidth()
.background(
- shape = RoundedCornerShape(14.dp),
+ shape = RoundedCornerShape(28.dp),
color = if (isPressed.value) Color(0xFFE0E0E0) else Color.Transparent
)
- .padding(horizontal = 12.dp, vertical = 12.dp)
+ .padding(16.dp)
.pointerInput(Unit) {
detectTapGestures(
onPress = {
@@ -602,8 +652,10 @@ fun StyledToggle(
indication = null,
interactionSource = remember { MutableInteractionSource() }
) {
- checked = !checked
- cb()
+ if (enabled) {
+ checked = !checked
+ cb()
+ }
},
verticalAlignment = Alignment.CenterVertically
) {
@@ -629,10 +681,14 @@ fun StyledToggle(
}
StyledSwitch(
checked = checked,
+ enabled = enabled,
onCheckedChange = {
- checked = it
- cb()
- }
+ if (enabled) {
+ checked = it
+ cb()
+ }
+ },
+ indpendent = false
)
}
}
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/AccessibilitySettingsScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/AccessibilitySettingsScreen.kt
index 1e8a1c0..5e3be79 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/AccessibilitySettingsScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/AccessibilitySettingsScreen.kt
@@ -40,20 +40,16 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.KeyboardArrowDown
import androidx.compose.material3.Checkbox
import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
-import androidx.compose.material3.Icon
import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableLongStateOf
@@ -79,6 +75,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
+import com.kyant.backdrop.backdrops.layerBackdrop
+import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.HazeState
import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
@@ -149,13 +147,16 @@ fun AccessibilitySettingsScreen(navController: NavController) {
}
}
+ val backdrop = rememberLayerBackdrop()
+
StyledScaffold(
title = stringResource(R.string.accessibility),
navigationButton = {
StyledIconButton(
onClick = { navController.popBackStack() },
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
},
) { spacerHeight, hazeState ->
@@ -163,6 +164,7 @@ fun AccessibilitySettingsScreen(navController: NavController) {
modifier = Modifier
.fillMaxSize()
.hazeSource(hazeState)
+ .layerBackdrop(backdrop)
.verticalScroll(rememberScrollState())
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
@@ -370,7 +372,7 @@ fun AccessibilitySettingsScreen(navController: NavController) {
)
StyledToggle(
- title = stringResource(R.string.noise_control).uppercase(),
+ title = stringResource(R.string.noise_control),
label = stringResource(R.string.noise_cancellation_single_airpod),
description = stringResource(R.string.noise_cancellation_single_airpod_description),
controlCommandIdentifier = AACPManager.Companion.ControlCommandIdentifiers.ONE_BUD_ANC_MODE,
@@ -392,7 +394,7 @@ fun AccessibilitySettingsScreen(navController: NavController) {
}
StyledSlider(
- label = stringResource(R.string.tone_volume).uppercase(),
+ label = stringResource(R.string.tone_volume),
description = stringResource(R.string.tone_volume_description),
mutableFloatState = toneVolumeValue,
onValueChange = {
@@ -405,6 +407,12 @@ fun AccessibilitySettingsScreen(navController: NavController) {
independent = true
)
+ StyledToggle(
+ label = stringResource(R.string.volume_control),
+ description = stringResource(R.string.volume_control_description),
+ controlCommandIdentifier = AACPManager.Companion.ControlCommandIdentifiers.VOLUME_SWIPE_MODE,
+ )
+
DropdownMenuComponent(
label = stringResource(R.string.volume_swipe_speed),
description = stringResource(R.string.volume_swipe_speed_description),
@@ -425,10 +433,10 @@ fun AccessibilitySettingsScreen(navController: NavController) {
if (!hearingAidEnabled.value&& isSdpOffsetAvailable.value) {
Text(
- text = stringResource(R.string.apply_eq_to).uppercase(),
+ text = stringResource(R.string.apply_eq_to),
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
@@ -437,12 +445,12 @@ fun AccessibilitySettingsScreen(navController: NavController) {
Column(
modifier = Modifier
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp))
+ .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(vertical = 0.dp)
) {
val darkModeLocal = isSystemInDarkTheme()
- val phoneShape = RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp)
+ val phoneShape = RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp)
var phoneBackgroundColor by remember {
mutableStateOf(
if (darkModeLocal) Color(
@@ -500,11 +508,11 @@ fun AccessibilitySettingsScreen(navController: NavController) {
}
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888)
)
- val mediaShape = RoundedCornerShape(bottomStart = 14.dp, bottomEnd = 14.dp)
+ val mediaShape = RoundedCornerShape(bottomStart = 28.dp, bottomEnd = 28.dp)
var mediaBackgroundColor by remember {
mutableStateOf(
if (darkModeLocal) Color(
@@ -565,7 +573,7 @@ fun AccessibilitySettingsScreen(navController: NavController) {
Column(
modifier = Modifier
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp))
+ .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(12.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
@@ -686,15 +694,18 @@ private fun DropdownMenuComponent(
)
.background(
if (independent) (if (isSystemInDarkTheme()) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) else Color.Transparent,
- if (independent) RoundedCornerShape(14.dp) else RoundedCornerShape(0.dp)
+ if (independent) RoundedCornerShape(28.dp) else RoundedCornerShape(0.dp)
)
- .clip(if (independent) RoundedCornerShape(14.dp) else RoundedCornerShape(0.dp))
+ then(
+ if (independent) Modifier.padding(horizontal = 4.dp) else Modifier
+ )
+ .clip(if (independent) RoundedCornerShape(28.dp) else RoundedCornerShape(0.dp))
){
Row(
modifier = Modifier
.fillMaxWidth()
.padding(start = 12.dp, end = 12.dp)
- .height(55.dp)
+ .height(58.dp)
.pointerInput(Unit) {
detectTapGestures { offset ->
val now = System.currentTimeMillis()
@@ -766,7 +777,7 @@ private fun DropdownMenuComponent(
color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
- modifier = Modifier.padding(bottom = 2.dp)
+ modifier = Modifier.padding(16.dp, top = 0.dp, bottom = 2.dp)
)
}
}
@@ -780,14 +791,21 @@ private fun DropdownMenuComponent(
) {
Text(
text = selectedOption,
- fontSize = 16.sp,
- color = textColor.copy(alpha = 0.8f)
+ style = TextStyle(
+ fontSize = 16.sp,
+ color = textColor.copy(alpha = 0.8f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ )
)
- Icon(
- Icons.Default.KeyboardArrowDown,
- contentDescription = null,
- modifier = Modifier.size(18.dp),
- tint = textColor.copy(alpha = 0.6f)
+ Text(
+ text = "",
+ style = TextStyle(
+ fontSize = 16.sp,
+ color = textColor.copy(alpha = 0.6f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ ),
+ modifier = Modifier
+ .padding(start = 6.dp)
)
}
@@ -816,7 +834,7 @@ private fun DropdownMenuComponent(
Box(
modifier = Modifier
.fillMaxWidth()
- .padding(horizontal = 8.dp)
+ .padding(horizontal = 16.dp)
.background(if (isSystemInDarkTheme()) Color(0xFF000000) else Color(0xFFF2F2F7))
){
Text(
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/AdaptiveStrengthScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/AdaptiveStrengthScreen.kt
index da0605a..440e068 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/AdaptiveStrengthScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/AdaptiveStrengthScreen.kt
@@ -36,6 +36,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
+import com.kyant.backdrop.backdrops.layerBackdrop
+import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
@@ -94,6 +96,7 @@ fun AdaptiveStrengthScreen(navController: NavController) {
}
}
+ val backdrop = rememberLayerBackdrop()
StyledScaffold(
title = stringResource(R.string.customize_adaptive_audio),
@@ -101,19 +104,21 @@ fun AdaptiveStrengthScreen(navController: NavController) {
StyledIconButton(
onClick = { navController.popBackStack() },
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
}
) { spacerHeight ->
Column(
modifier = Modifier
.fillMaxSize()
+ .layerBackdrop(backdrop)
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
) {
Spacer(modifier = Modifier.height(spacerHeight))
StyledSlider(
- label = stringResource(R.string.customize_adaptive_audio).uppercase(),
+ label = stringResource(R.string.customize_adaptive_audio),
mutableFloatState = sliderValue,
onValueChange = {
sliderValue.floatValue = it
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/AirPodsSettingsScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/AirPodsSettingsScreen.kt
index c8242ea..62c700b 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/AirPodsSettingsScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/AirPodsSettingsScreen.kt
@@ -68,6 +68,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController
+import com.kyant.backdrop.backdrops.layerBackdrop
import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import com.kyant.backdrop.drawBackdrop
import com.kyant.backdrop.highlight.Highlight
@@ -80,7 +81,6 @@ import me.kavishdevar.librepods.composables.BatteryView
import me.kavishdevar.librepods.composables.CallControlSettings
import me.kavishdevar.librepods.composables.ConnectionSettings
import me.kavishdevar.librepods.composables.MicrophoneSettings
-import me.kavishdevar.librepods.composables.NameField
import me.kavishdevar.librepods.composables.NavigationButton
import me.kavishdevar.librepods.composables.NoiseControlSettings
import me.kavishdevar.librepods.composables.PressAndHoldSettings
@@ -199,13 +199,15 @@ fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
}
}
val darkMode = isSystemInDarkTheme()
+ val backdrop = rememberLayerBackdrop()
StyledScaffold(
title = deviceName.text,
actionButtons = listOf {
StyledIconButton(
onClick = { navController.navigate("app_settings") },
icon = "",
- darkMode = darkMode
+ darkMode = darkMode,
+ backdrop = backdrop
)
},
snackbarHostState = snackbarHostState
@@ -216,6 +218,7 @@ fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
.fillMaxSize()
.hazeSource(hazeState)
.padding(horizontal = 16.dp)
+ .layerBackdrop(backdrop)
.verticalScroll(rememberScrollState())
) {
Spacer(modifier = Modifier.height(spacerHeight))
@@ -249,28 +252,28 @@ fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
// Only show name field when not in BLE-only mode
if (!bleOnlyMode) {
- NameField(
+ NavigationButton(
+ to = "rename",
name = stringResource(R.string.name),
- value = deviceName.text,
- navController = navController
+ currentState = deviceName.text,
+ navController = navController,
+ independent = true
)
- }
- if (!bleOnlyMode) {
Spacer(modifier = Modifier.height(32.dp))
NavigationButton(to = "hearing_aid", stringResource(R.string.hearing_aid), navController)
Spacer(modifier = Modifier.height(16.dp))
NoiseControlSettings(service = service)
+ Spacer(modifier = Modifier.height(16.dp))
+ PressAndHoldSettings(navController = navController)
+
Spacer(modifier = Modifier.height(16.dp))
CallControlSettings(hazeState = hazeState)
// camera control goes here, airpods side is done, i just need to figure out how to listen to app open/close events
- Spacer(modifier = Modifier.height(16.dp))
- PressAndHoldSettings(navController = navController)
-
Spacer(modifier = Modifier.height(16.dp))
AudioSettings(navController = navController)
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/AppSettingsScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/AppSettingsScreen.kt
index 353e9c9..89cf866 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/AppSettingsScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/AppSettingsScreen.kt
@@ -26,7 +26,6 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
-import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -37,7 +36,6 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.KeyboardOptions
import androidx.compose.foundation.verticalScroll
@@ -47,25 +45,21 @@ import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.OutlinedTextFieldDefaults
-import androidx.compose.material3.Slider
-import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
-import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
-import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
@@ -79,13 +73,17 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.edit
import androidx.navigation.NavController
+import com.kyant.backdrop.backdrops.layerBackdrop
+import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.launch
import me.kavishdevar.librepods.R
+import me.kavishdevar.librepods.composables.NavigationButton
import me.kavishdevar.librepods.composables.StyledIconButton
import me.kavishdevar.librepods.composables.StyledScaffold
-import me.kavishdevar.librepods.composables.StyledSwitch
+import me.kavishdevar.librepods.composables.StyledSlider
+import me.kavishdevar.librepods.composables.StyledToggle
import me.kavishdevar.librepods.utils.AACPManager
import me.kavishdevar.librepods.utils.RadareOffsetFinder
import kotlin.io.encoding.Base64
@@ -102,13 +100,13 @@ fun AppSettingsScreen(navController: NavController) {
val coroutineScope = rememberCoroutineScope()
val scrollState = rememberScrollState()
- var showResetDialog by remember { mutableStateOf(false) }
- var showIrkDialog by remember { mutableStateOf(false) }
- var showEncKeyDialog by remember { mutableStateOf(false) }
- var irkValue by remember { mutableStateOf("") }
- var encKeyValue by remember { mutableStateOf("") }
- var irkError by remember { mutableStateOf(null) }
- var encKeyError by remember { mutableStateOf(null) }
+ val showResetDialog = remember { mutableStateOf(false) }
+ val showIrkDialog = remember { mutableStateOf(false) }
+ val showEncKeyDialog = remember { mutableStateOf(false) }
+ val irkValue = remember { mutableStateOf("") }
+ val encKeyValue = remember { mutableStateOf("") }
+ val irkError = remember { mutableStateOf(null) }
+ val encKeyError = remember { mutableStateOf(null) }
LaunchedEffect(Unit) {
val savedIrk = sharedPreferences.getString(AACPManager.Companion.ProximityKeyType.IRK.name, null)
@@ -117,9 +115,9 @@ fun AppSettingsScreen(navController: NavController) {
if (savedIrk != null) {
try {
val decoded = Base64.decode(savedIrk)
- irkValue = decoded.joinToString("") { "%02x".format(it) }
+ irkValue.value = decoded.joinToString("") { "%02x".format(it) }
} catch (e: Exception) {
- irkValue = ""
+ irkValue.value = ""
e.printStackTrace()
}
}
@@ -127,59 +125,58 @@ fun AppSettingsScreen(navController: NavController) {
if (savedEncKey != null) {
try {
val decoded = Base64.decode(savedEncKey)
- encKeyValue = decoded.joinToString("") { "%02x".format(it) }
+ encKeyValue.value = decoded.joinToString("") { "%02x".format(it) }
} catch (e: Exception) {
- encKeyValue = ""
+ encKeyValue.value = ""
e.printStackTrace()
}
}
}
- var showPhoneBatteryInWidget by remember {
+ val showPhoneBatteryInWidget = remember {
mutableStateOf(sharedPreferences.getBoolean("show_phone_battery_in_widget", true))
}
- var conversationalAwarenessPauseMusicEnabled by remember {
+ val conversationalAwarenessPauseMusicEnabled = remember {
mutableStateOf(sharedPreferences.getBoolean("conversational_awareness_pause_music", false))
}
- var relativeConversationalAwarenessVolumeEnabled by remember {
+ val relativeConversationalAwarenessVolumeEnabled = remember {
mutableStateOf(sharedPreferences.getBoolean("relative_conversational_awareness_volume", true))
}
- var openDialogForControlling by remember {
+ val openDialogForControlling = remember {
mutableStateOf(sharedPreferences.getString("qs_click_behavior", "dialog") == "dialog")
}
- var disconnectWhenNotWearing by remember {
+ val disconnectWhenNotWearing = remember {
mutableStateOf(sharedPreferences.getBoolean("disconnect_when_not_wearing", false))
}
- var takeoverWhenDisconnected by remember {
+ val takeoverWhenDisconnected = remember {
mutableStateOf(sharedPreferences.getBoolean("takeover_when_disconnected", true))
}
- var takeoverWhenIdle by remember {
+ val takeoverWhenIdle = remember {
mutableStateOf(sharedPreferences.getBoolean("takeover_when_idle", true))
}
- var takeoverWhenMusic by remember {
+ val takeoverWhenMusic = remember {
mutableStateOf(sharedPreferences.getBoolean("takeover_when_music", false))
}
- var takeoverWhenCall by remember {
+ val takeoverWhenCall = remember {
mutableStateOf(sharedPreferences.getBoolean("takeover_when_call", true))
}
- var takeoverWhenRingingCall by remember {
+ val takeoverWhenRingingCall = remember {
mutableStateOf(sharedPreferences.getBoolean("takeover_when_ringing_call", true))
}
- var takeoverWhenMediaStart by remember {
+ val takeoverWhenMediaStart = remember {
mutableStateOf(sharedPreferences.getBoolean("takeover_when_media_start", true))
}
- var useAlternateHeadTrackingPackets by remember {
+ val useAlternateHeadTrackingPackets = remember {
mutableStateOf(sharedPreferences.getBoolean("use_alternate_head_tracking_packets", false))
}
- var bleOnlyMode by remember {
+ val bleOnlyMode = remember {
mutableStateOf(sharedPreferences.getBoolean("ble_only_mode", false))
}
- // Ensure the default value is properly set if not exists
LaunchedEffect(Unit) {
if (!sharedPreferences.contains("ble_only_mode")) {
sharedPreferences.edit { putBoolean("ble_only_mode", false) }
@@ -191,10 +188,12 @@ fun AppSettingsScreen(navController: NavController) {
return hexPattern.matches(input)
}
- var isProcessingSdp by remember { mutableStateOf(false) }
- var actAsAppleDevice by remember { mutableStateOf(false) }
+ val isProcessingSdp = remember { mutableStateOf(false) }
+ val actAsAppleDevice = remember { mutableStateOf(false) }
- BackHandler(enabled = isProcessingSdp) {}
+ BackHandler(enabled = isProcessingSdp.value) {}
+
+ val backdrop = rememberLayerBackdrop()
StyledScaffold(
title = stringResource(R.string.app_settings),
@@ -202,15 +201,17 @@ fun AppSettingsScreen(navController: NavController) {
StyledIconButton(
onClick = { navController.popBackStack() },
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
}
) { spacerHeight, hazeState ->
Column(
modifier = Modifier
.fillMaxSize()
- .verticalScroll(scrollState)
+ .layerBackdrop(backdrop)
.hazeSource(state = hazeState)
+ .verticalScroll(scrollState)
.padding(horizontal = 16.dp)
) {
Spacer(modifier = Modifier.height(spacerHeight))
@@ -219,17 +220,33 @@ fun AppSettingsScreen(navController: NavController) {
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
val textColor = if (isDarkTheme) Color.White else Color.Black
- Spacer(modifier = Modifier.height(8.dp))
+ StyledToggle(
+ title = stringResource(R.string.widget),
+ label = stringResource(R.string.show_phone_battery_in_widget),
+ description = stringResource(R.string.show_phone_battery_in_widget_description),
+ checkedState = showPhoneBatteryInWidget,
+ sharedPreferenceKey = "show_phone_battery_in_widget",
+ sharedPreferences = sharedPreferences,
+ )
+
+ StyledToggle(
+ title = stringResource(R.string.connection_mode),
+ label = stringResource(R.string.ble_only_mode),
+ description = stringResource(R.string.ble_only_mode_description),
+ checkedState = bleOnlyMode,
+ sharedPreferenceKey = "ble_only_mode",
+ sharedPreferences = sharedPreferences,
+ )
Text(
- text = stringResource(R.string.widget).uppercase(),
+ text = stringResource(R.string.conversational_awareness),
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
- modifier = Modifier.padding(8.dp, bottom = 2.dp, top = 8.dp)
+ modifier = Modifier.padding(16.dp, bottom = 2.dp, top = 24.dp)
)
Spacer(modifier = Modifier.height(2.dp))
@@ -239,770 +256,251 @@ fun AppSettingsScreen(navController: NavController) {
.fillMaxWidth()
.background(
backgroundColor,
- RoundedCornerShape(14.dp)
+ RoundedCornerShape(28.dp)
)
- .padding(horizontal = 16.dp, vertical = 4.dp)
+ .padding(vertical = 4.dp)
) {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- showPhoneBatteryInWidget = !showPhoneBatteryInWidget
- sharedPreferences.edit { putBoolean("show_phone_battery_in_widget", showPhoneBatteryInWidget)}
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.show_phone_battery_in_widget),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.show_phone_battery_in_widget_description),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = showPhoneBatteryInWidget,
- onCheckedChange = {
- showPhoneBatteryInWidget = it
- sharedPreferences.edit { putBoolean("show_phone_battery_in_widget", it)}
- }
- )
- }
- }
-
- Text(
- text = stringResource(R.string.connection_mode).uppercase(),
- style = TextStyle(
- fontSize = 14.sp,
- fontWeight = FontWeight.Light,
- color = textColor.copy(alpha = 0.6f),
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- modifier = Modifier.padding(8.dp, bottom = 2.dp, top = 24.dp)
- )
-
- Spacer(modifier = Modifier.height(2.dp))
-
- Column (
- modifier = Modifier
- .fillMaxWidth()
- .background(
- backgroundColor,
- RoundedCornerShape(14.dp)
- )
- .padding(horizontal = 16.dp, vertical = 4.dp)
- ) {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- bleOnlyMode = !bleOnlyMode
- sharedPreferences.edit { putBoolean("ble_only_mode", bleOnlyMode)}
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.ble_only_mode),
- fontSize = 16.sp,
- color = textColor
- )
- Text(
- text = stringResource(R.string.ble_only_mode_description),
- fontSize = 13.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = bleOnlyMode,
- onCheckedChange = {
- bleOnlyMode = it
- sharedPreferences.edit { putBoolean("ble_only_mode", it)}
- }
- )
- }
- }
-
- Text(
- text = stringResource(R.string.conversational_awareness).uppercase(),
- style = TextStyle(
- fontSize = 14.sp,
- fontWeight = FontWeight.Light,
- color = textColor.copy(alpha = 0.6f),
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- modifier = Modifier.padding(8.dp, bottom = 2.dp, top = 24.dp)
- )
-
- Spacer(modifier = Modifier.height(2.dp))
-
- Column (
- modifier = Modifier
- .fillMaxWidth()
- .background(
- backgroundColor,
- RoundedCornerShape(14.dp)
- )
- .padding(horizontal = 16.dp, vertical = 4.dp)
- ) {
- val sliderValue = remember { mutableFloatStateOf(0f) }
- LaunchedEffect(sliderValue) {
- if (sharedPreferences.contains("conversational_awareness_volume")) {
- sliderValue.floatValue = sharedPreferences.getInt("conversational_awareness_volume", 43).toFloat()
- }
- }
-
fun updateConversationalAwarenessPauseMusic(enabled: Boolean) {
- conversationalAwarenessPauseMusicEnabled = enabled
+ conversationalAwarenessPauseMusicEnabled.value = enabled
sharedPreferences.edit { putBoolean("conversational_awareness_pause_music", enabled)}
}
fun updateRelativeConversationalAwarenessVolume(enabled: Boolean) {
- relativeConversationalAwarenessVolumeEnabled = enabled
+ relativeConversationalAwarenessVolumeEnabled.value = enabled
sharedPreferences.edit { putBoolean("relative_conversational_awareness_volume", enabled)}
}
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- updateConversationalAwarenessPauseMusic(!conversationalAwarenessPauseMusicEnabled)
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.conversational_awareness_pause_music),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.conversational_awareness_pause_music_description),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = conversationalAwarenessPauseMusicEnabled,
- onCheckedChange = {
- updateConversationalAwarenessPauseMusic(it)
- },
- )
- }
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- updateRelativeConversationalAwarenessVolume(!relativeConversationalAwarenessVolumeEnabled)
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.relative_conversational_awareness_volume),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.relative_conversational_awareness_volume_description),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = relativeConversationalAwarenessVolumeEnabled,
- onCheckedChange = {
- updateRelativeConversationalAwarenessVolume(it)
- }
- )
- }
-
- Text(
- text = stringResource(R.string.conversational_awareness_volume),
- fontSize = 16.sp,
- color = textColor,
- modifier = Modifier.padding(top = 8.dp, bottom = 4.dp)
+ StyledToggle(
+ label = stringResource(R.string.conversational_awareness_pause_music),
+ description = stringResource(R.string.conversational_awareness_pause_music_description),
+ checkedState = conversationalAwarenessPauseMusicEnabled,
+ onCheckedChange = { updateConversationalAwarenessPauseMusic(it) },
+ independent = false
)
- val trackColor = if (isDarkTheme) Color(0xFFB3B3B3) else Color(0xFFD9D9D9)
- val activeTrackColor = if (isDarkTheme) Color(0xFF007AFF) else Color(0xFF3C6DF5)
- val thumbColor = if (isDarkTheme) Color(0xFFFFFFFF) else Color(0xFFFFFFFF)
-
- Slider(
- value = sliderValue.floatValue,
- onValueChange = {
- sliderValue.floatValue = it
- sharedPreferences.edit { putInt("conversational_awareness_volume", it.toInt())}
- },
- valueRange = 10f..85f,
- onValueChangeFinished = {
- sliderValue.floatValue = sliderValue.floatValue.roundToInt().toFloat()
- },
+ HorizontalDivider(
+ thickness = 1.dp,
+ color = Color(0x40888888),
modifier = Modifier
- .fillMaxWidth()
- .height(36.dp)
- .padding(vertical = 4.dp),
- colors = SliderDefaults.colors(
- thumbColor = thumbColor,
- activeTrackColor = activeTrackColor,
- inactiveTrackColor = trackColor,
- ),
- thumb = {
- Box(
- modifier = Modifier
- .size(24.dp)
- .shadow(4.dp, CircleShape)
- .background(thumbColor, CircleShape)
- )
- },
- track = {
- Box (
- modifier = Modifier
- .fillMaxWidth()
- .height(12.dp),
- contentAlignment = Alignment.CenterStart
- )
- {
- Box(
- modifier = Modifier
- .fillMaxWidth()
- .height(4.dp)
- .background(trackColor, RoundedCornerShape(4.dp))
- )
- Box(
- modifier = Modifier
- .fillMaxWidth(((sliderValue.floatValue - 10) * 100) /7500)
- .height(4.dp)
- .background(if (conversationalAwarenessPauseMusicEnabled) trackColor else activeTrackColor, RoundedCornerShape(4.dp))
- )
- }
- }
+ .padding(horizontal = 12.dp)
)
+ StyledToggle(
+ label = stringResource(R.string.relative_conversational_awareness_volume),
+ description = stringResource(R.string.relative_conversational_awareness_volume_description),
+ checkedState = relativeConversationalAwarenessVolumeEnabled,
+ onCheckedChange = { updateRelativeConversationalAwarenessVolume(it) },
+ independent = false
+ )
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ val conversationalAwarenessVolume = remember { mutableFloatStateOf(sharedPreferences.getInt("conversational_awareness_volume", 43).toFloat()) }
+ LaunchedEffect(conversationalAwarenessVolume.floatValue) {
+ sharedPreferences.edit { putInt("conversational_awareness_volume", conversationalAwarenessVolume.floatValue.roundToInt()) }
+ }
+
+ StyledSlider(
+ label = stringResource(R.string.conversational_awareness_volume),
+ mutableFloatState = conversationalAwarenessVolume,
+ valueRange = 10f..85f,
+ startLabel = "10%",
+ endLabel = "85%",
+ onValueChange = { newValue -> conversationalAwarenessVolume.floatValue = newValue },
+ independent = true
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ StyledToggle(
+ title = stringResource(R.string.quick_settings_tile),
+ label = stringResource(R.string.open_dialog_for_controlling),
+ description = stringResource(R.string.open_dialog_for_controlling_description),
+ checkedState = openDialogForControlling,
+ onCheckedChange = {
+ openDialogForControlling.value = it
+ sharedPreferences.edit { putString("qs_click_behavior", if (it) "dialog" else "activity") }
+ },
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ StyledToggle(
+ title = stringResource(R.string.ear_detection),
+ label = stringResource(R.string.disconnect_when_not_wearing),
+ description = stringResource(R.string.disconnect_when_not_wearing_description),
+ checkedState = disconnectWhenNotWearing,
+ sharedPreferenceKey = "disconnect_when_not_wearing",
+ sharedPreferences = sharedPreferences,
+ )
+
+ Text(
+ text = stringResource(R.string.takeover_airpods_state),
+ style = TextStyle(
+ fontSize = 14.sp,
+ fontWeight = FontWeight.Bold,
+ color = textColor.copy(alpha = 0.6f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ ),
+ modifier = Modifier.padding(16.dp, bottom = 2.dp, top = 24.dp)
+ )
+
+ Spacer(modifier = Modifier.height(4.dp))
+
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .background(
+ backgroundColor,
+ RoundedCornerShape(28.dp)
+ )
+ .padding(vertical = 4.dp)
+ ) {
+ StyledToggle(
+ label = stringResource(R.string.takeover_disconnected),
+ description = stringResource(R.string.takeover_disconnected_desc),
+ checkedState = takeoverWhenDisconnected,
+ onCheckedChange = {
+ takeoverWhenDisconnected.value = it
+ sharedPreferences.edit { putBoolean("takeover_when_disconnected", it)}
+ },
+ independent = false
+ )
+ HorizontalDivider(
+ thickness = 1.dp,
+ color = Color(0x40888888),
+ modifier = Modifier
+ .padding(horizontal = 12.dp)
+ )
+
+ StyledToggle(
+ label = stringResource(R.string.takeover_idle),
+ description = stringResource(R.string.takeover_idle_desc),
+ checkedState = takeoverWhenIdle,
+ onCheckedChange = {
+ takeoverWhenIdle.value = it
+ sharedPreferences.edit { putBoolean("takeover_when_idle", it)}
+ },
+ independent = false
+ )
+ HorizontalDivider(
+ thickness = 1.dp,
+ color = Color(0x40888888),
+ modifier = Modifier
+ .padding(horizontal = 12.dp)
+ )
+
+ StyledToggle(
+ label = stringResource(R.string.takeover_music),
+ description = stringResource(R.string.takeover_music_desc),
+ checkedState = takeoverWhenMusic,
+ onCheckedChange = {
+ takeoverWhenMusic.value = it
+ sharedPreferences.edit { putBoolean("takeover_when_music", it)}
+ },
+ independent = false
+ )
+ HorizontalDivider(
+ thickness = 1.dp,
+ color = Color(0x40888888),
+ modifier = Modifier
+ .padding(horizontal = 12.dp)
+ )
+
+ StyledToggle(
+ label = stringResource(R.string.takeover_call),
+ description = stringResource(R.string.takeover_call_desc),
+ checkedState = takeoverWhenCall,
+ onCheckedChange = {
+ takeoverWhenCall.value = it
+ sharedPreferences.edit { putBoolean("takeover_when_call", it)}
+ },
+ independent = false
+ )
+ }
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ Text(
+ text = stringResource(R.string.takeover_phone_state),
+ style = TextStyle(
+ fontSize = 14.sp,
+ fontWeight = FontWeight.Bold,
+ color = textColor.copy(alpha = 0.6f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ ),
+ modifier = Modifier.padding(horizontal = 16.dp)
+ )
+ Spacer(modifier = Modifier.height(4.dp))
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .background(
+ backgroundColor,
+ RoundedCornerShape(28.dp)
+ )
+ .padding(vertical = 4.dp)
+ ){
+ StyledToggle(
+ label = stringResource(R.string.takeover_ringing_call),
+ description = stringResource(R.string.takeover_ringing_call_desc),
+ checkedState = takeoverWhenRingingCall,
+ onCheckedChange = {
+ takeoverWhenRingingCall.value = it
+ sharedPreferences.edit { putBoolean("takeover_when_ringing_call", it)}
+ },
+ independent = false
+ )
+ HorizontalDivider(
+ thickness = 1.dp,
+ color = Color(0x40888888),
+ modifier = Modifier
+ .padding(horizontal = 12.dp)
+ )
+
+ StyledToggle(
+ label = stringResource(R.string.takeover_media_start),
+ description = stringResource(R.string.takeover_media_start_desc),
+ checkedState = takeoverWhenMediaStart,
+ onCheckedChange = {
+ takeoverWhenMediaStart.value = it
+ sharedPreferences.edit { putBoolean("takeover_when_media_start", it)}
+ },
+ independent = false
+ )
+ }
+
+ Text(
+ text = stringResource(R.string.advanced_options),
+ style = TextStyle(
+ fontSize = 14.sp,
+ fontWeight = FontWeight.Bold,
+ color = textColor.copy(alpha = 0.6f),
+ fontFamily = FontFamily(Font(R.font.sf_pro))
+ ),
+ modifier = Modifier.padding(16.dp, bottom = 2.dp, top = 24.dp)
+ )
+
+ Spacer(modifier = Modifier.height(2.dp))
+
+ Column(
+ modifier = Modifier
+ .fillMaxWidth()
+ .background(
+ backgroundColor,
+ RoundedCornerShape(28.dp)
+ )
+ .padding(horizontal = 16.dp, vertical = 4.dp)
+ ) {
Row(
modifier = Modifier
.fillMaxWidth()
- .padding(bottom = 8.dp),
- horizontalArrangement = Arrangement.SpaceBetween
- ) {
- Text(
- text = "10%",
- style = TextStyle(
- fontSize = 14.sp,
- fontWeight = FontWeight.Light,
- color = textColor.copy(alpha = 0.7f)
+ .clickable (
+ onClick = { showIrkDialog.value = true },
+ indication = null,
+ interactionSource = remember { MutableInteractionSource() }
),
- modifier = Modifier.padding(start = 4.dp)
- )
- Text(
- text = "85%",
- style = TextStyle(
- fontSize = 14.sp,
- fontWeight = FontWeight.Light,
- color = textColor.copy(alpha = 0.7f)
- ),
- modifier = Modifier.padding(end = 4.dp)
- )
- }
- }
-
- Text(
- text = stringResource(R.string.quick_settings_tile).uppercase(),
- style = TextStyle(
- fontSize = 14.sp,
- fontWeight = FontWeight.Light,
- color = textColor.copy(alpha = 0.6f),
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- modifier = Modifier.padding(8.dp, bottom = 2.dp, top = 24.dp)
- )
-
- Spacer(modifier = Modifier.height(2.dp))
-
- Column(
- modifier = Modifier
- .fillMaxWidth()
- .background(
- backgroundColor,
- RoundedCornerShape(14.dp)
- )
- .padding(horizontal = 16.dp, vertical = 4.dp)
- ) {
- fun updateQsClickBehavior(enabled: Boolean) {
- openDialogForControlling = enabled
- sharedPreferences.edit { putString("qs_click_behavior", if (enabled) "dialog" else "cycle")}
- }
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- updateQsClickBehavior(!openDialogForControlling)
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.open_dialog_for_controlling),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.open_dialog_for_controlling_description),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = openDialogForControlling,
- onCheckedChange = {
- updateQsClickBehavior(it)
- }
- )
- }
- }
-
- Text(
- text = stringResource(R.string.ear_detection).uppercase(),
- style = TextStyle(
- fontSize = 14.sp,
- fontWeight = FontWeight.Light,
- color = textColor.copy(alpha = 0.6f),
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- modifier = Modifier.padding(8.dp, bottom = 2.dp, top = 24.dp)
- )
-
- Spacer(modifier = Modifier.height(2.dp))
-
- Column(
- modifier = Modifier
- .fillMaxWidth()
- .background(
- backgroundColor,
- RoundedCornerShape(14.dp)
- )
- .padding(horizontal = 16.dp, vertical = 4.dp)
- ) {
- fun updateDisconnectWhenNotWearing(enabled: Boolean) {
- disconnectWhenNotWearing = enabled
- sharedPreferences.edit { putBoolean("disconnect_when_not_wearing", enabled)}
- }
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- updateDisconnectWhenNotWearing(!disconnectWhenNotWearing)
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.disconnect_when_not_wearing),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.disconnect_when_not_wearing_description),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = disconnectWhenNotWearing,
- onCheckedChange = {
- updateDisconnectWhenNotWearing(it)
- }
- )
- }
- }
-
- Text(
- text = stringResource(R.string.takeover_header).uppercase(),
- style = TextStyle(
- fontSize = 14.sp,
- fontWeight = FontWeight.Light,
- color = textColor.copy(alpha = 0.6f),
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- modifier = Modifier.padding(8.dp, bottom = 2.dp, top = 24.dp)
- )
-
- Spacer(modifier = Modifier.height(2.dp))
-
- Column(
- modifier = Modifier
- .fillMaxWidth()
- .background(
- backgroundColor,
- RoundedCornerShape(14.dp)
- )
- .padding(horizontal = 16.dp, vertical = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.takeover_airpods_state),
- fontSize = 16.sp,
- fontWeight = FontWeight.Medium,
- color = textColor,
- modifier = Modifier.padding(top = 12.dp, bottom = 4.dp)
- )
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- takeoverWhenDisconnected = !takeoverWhenDisconnected
- sharedPreferences.edit { putBoolean("takeover_when_disconnected", takeoverWhenDisconnected)}
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.takeover_disconnected),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.takeover_disconnected_desc),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = takeoverWhenDisconnected,
- onCheckedChange = {
- takeoverWhenDisconnected = it
- sharedPreferences.edit { putBoolean("takeover_when_disconnected", it)}
- }
- )
- }
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- takeoverWhenIdle = !takeoverWhenIdle
- sharedPreferences.edit { putBoolean("takeover_when_idle", takeoverWhenIdle)}
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.takeover_idle),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.takeover_idle_desc),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = takeoverWhenIdle,
- onCheckedChange = {
- takeoverWhenIdle = it
- sharedPreferences.edit { putBoolean("takeover_when_idle", it)}
- }
- )
- }
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- takeoverWhenMusic = !takeoverWhenMusic
- sharedPreferences.edit { putBoolean("takeover_when_music", takeoverWhenMusic)}
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.takeover_music),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.takeover_music_desc),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = takeoverWhenMusic,
- onCheckedChange = {
- takeoverWhenMusic = it
- sharedPreferences.edit { putBoolean("takeover_when_music", it)}
- }
- )
- }
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- takeoverWhenCall = !takeoverWhenCall
- sharedPreferences.edit { putBoolean("takeover_when_call", takeoverWhenCall)}
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.takeover_call),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.takeover_call_desc),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = takeoverWhenCall,
- onCheckedChange = {
- takeoverWhenCall = it
- sharedPreferences.edit { putBoolean("takeover_when_call", it)}
- }
- )
- }
-
- Spacer(modifier = Modifier.height(12.dp))
-
- Text(
- text = stringResource(R.string.takeover_phone_state),
- fontSize = 16.sp,
- fontWeight = FontWeight.Medium,
- color = textColor,
- modifier = Modifier.padding(top = 8.dp, bottom = 4.dp)
- )
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- takeoverWhenRingingCall = !takeoverWhenRingingCall
- sharedPreferences.edit { putBoolean("takeover_when_ringing_call", takeoverWhenRingingCall)}
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.takeover_ringing_call),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.takeover_ringing_call_desc),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = takeoverWhenRingingCall,
- onCheckedChange = {
- takeoverWhenRingingCall = it
- sharedPreferences.edit { putBoolean("takeover_when_ringing_call", it)}
- }
- )
- }
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- takeoverWhenMediaStart = !takeoverWhenMediaStart
- sharedPreferences.edit { putBoolean("takeover_when_media_start", takeoverWhenMediaStart)}
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.takeover_media_start),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.takeover_media_start_desc),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = takeoverWhenMediaStart,
- onCheckedChange = {
- takeoverWhenMediaStart = it
- sharedPreferences.edit { putBoolean("takeover_when_media_start", it)}
- }
- )
- }
- }
-
- Text(
- text = stringResource(R.string.advanced_options).uppercase(),
- style = TextStyle(
- fontSize = 14.sp,
- fontWeight = FontWeight.Light,
- color = textColor.copy(alpha = 0.6f),
- fontFamily = FontFamily(Font(R.font.sf_pro))
- ),
- modifier = Modifier.padding(8.dp, bottom = 2.dp, top = 24.dp)
- )
-
- Spacer(modifier = Modifier.height(2.dp))
-
- Column(
- modifier = Modifier
- .fillMaxWidth()
- .background(
- backgroundColor,
- RoundedCornerShape(14.dp)
- )
- .padding(horizontal = 16.dp, vertical = 4.dp)
- ) {
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable {
- showIrkDialog = true
- },
verticalAlignment = Alignment.CenterVertically
) {
Column(
@@ -1026,12 +524,19 @@ fun AppSettingsScreen(navController: NavController) {
}
}
+ HorizontalDivider(
+ thickness = 1.dp,
+ color = Color(0x40888888),
+ )
+
Row(
modifier = Modifier
.fillMaxWidth()
- .clickable {
- showEncKeyDialog = true
- },
+ .clickable (
+ onClick = { showEncKeyDialog.value = true },
+ indication = null,
+ interactionSource = remember { MutableInteractionSource() }
+ ),
verticalAlignment = Alignment.CenterVertically
) {
Column(
@@ -1054,177 +559,71 @@ fun AppSettingsScreen(navController: NavController) {
)
}
}
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- useAlternateHeadTrackingPackets = !useAlternateHeadTrackingPackets
- sharedPreferences.edit {
- putBoolean(
- "use_alternate_head_tracking_packets",
- useAlternateHeadTrackingPackets)}
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.use_alternate_head_tracking_packets),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.use_alternate_head_tracking_packets_description),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
-
- StyledSwitch(
- checked = useAlternateHeadTrackingPackets,
- onCheckedChange = {
- useAlternateHeadTrackingPackets = it
- sharedPreferences.edit { putBoolean("use_alternate_head_tracking_packets", it)}
- }
- )
- }
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable {
- navController.navigate("troubleshooting")
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.troubleshooting),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.troubleshooting_description),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- }
- }
-
- LaunchedEffect(Unit) {
- actAsAppleDevice = RadareOffsetFinder.isSdpOffsetAvailable()
- }
- val restartBluetoothText = stringResource(R.string.found_offset_restart_bluetooth)
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable(
- enabled = !isProcessingSdp,
- indication = null,
- interactionSource = remember { MutableInteractionSource() }
- ) {
- if (!isProcessingSdp) {
- val newValue = !actAsAppleDevice
- actAsAppleDevice = newValue
- isProcessingSdp = true
- coroutineScope.launch {
- if (newValue) {
- val radareOffsetFinder = RadareOffsetFinder(context)
- val success = radareOffsetFinder.findSdpOffset()
- if (success) {
- Toast.makeText(context, restartBluetoothText, Toast.LENGTH_LONG).show()
- }
- } else {
- RadareOffsetFinder.clearSdpOffset()
- }
- isProcessingSdp = false
- }
- }
- },
- verticalAlignment = Alignment.CenterVertically
- ) {
- Column(
- modifier = Modifier
- .weight(1f)
- .padding(vertical = 8.dp)
- .padding(end = 4.dp)
- ) {
- Text(
- text = stringResource(R.string.act_as_an_apple_device),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.height(4.dp))
- Text(
- text = stringResource(R.string.act_as_an_apple_device_description),
- fontSize = 14.sp,
- color = textColor.copy(0.6f),
- lineHeight = 16.sp,
- )
- if (actAsAppleDevice) {
- Spacer(modifier = Modifier.height(8.dp))
- Text(
- text = stringResource(R.string.act_as_an_apple_device_warning),
- fontSize = 12.sp,
- color = MaterialTheme.colorScheme.error,
- lineHeight = 14.sp,
- )
- }
- }
- StyledSwitch(
- checked = actAsAppleDevice,
- onCheckedChange = {
- if (!isProcessingSdp) {
- actAsAppleDevice = it
- isProcessingSdp = true
- coroutineScope.launch {
- if (it) {
- val radareOffsetFinder = RadareOffsetFinder(context)
- val success = radareOffsetFinder.findSdpOffset()
- if (success) {
- Toast.makeText(context, restartBluetoothText, Toast.LENGTH_LONG).show()
- }
- } else {
- RadareOffsetFinder.clearSdpOffset()
- }
- isProcessingSdp = false
- }
- }
- },
- enabled = !isProcessingSdp
- )
- }
}
Spacer(modifier = Modifier.height(16.dp))
+ StyledToggle(
+ label = stringResource(R.string.use_alternate_head_tracking_packets),
+ description = stringResource(R.string.use_alternate_head_tracking_packets_description),
+ checkedState = useAlternateHeadTrackingPackets,
+ onCheckedChange = {
+ useAlternateHeadTrackingPackets.value = it
+ sharedPreferences.edit { putBoolean("use_alternate_head_tracking_packets", it)}
+ },
+ independent = true
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+
+ NavigationButton(
+ to = "troubleshooting",
+ name = stringResource(R.string.troubleshooting),
+ navController = navController,
+ independent = true,
+ description = stringResource(R.string.troubleshooting_description)
+ )
+
+ LaunchedEffect(Unit) {
+ actAsAppleDevice.value = RadareOffsetFinder.isSdpOffsetAvailable()
+ }
+ val restartBluetoothText = stringResource(R.string.found_offset_restart_bluetooth)
+
+ StyledToggle(
+ label = stringResource(R.string.act_as_an_apple_device),
+ description = stringResource(R.string.act_as_an_apple_device_description),
+ checkedState = actAsAppleDevice,
+ onCheckedChange = {
+ actAsAppleDevice.value = it
+ isProcessingSdp.value = true
+ coroutineScope.launch {
+ if (it) {
+ val radareOffsetFinder = RadareOffsetFinder(context)
+ val success = radareOffsetFinder.findSdpOffset()
+ if (success) {
+ Toast.makeText(context, restartBluetoothText, Toast.LENGTH_LONG).show()
+ }
+ } else {
+ RadareOffsetFinder.clearSdpOffset()
+ }
+ isProcessingSdp.value = false
+ }
+ },
+ independent = true,
+ enabled = !isProcessingSdp.value
+ )
+
+ Spacer(modifier = Modifier.height(16.dp))
+
Button(
- onClick = { showResetDialog = true },
+ onClick = { showResetDialog.value = true },
modifier = Modifier
.fillMaxWidth()
.height(50.dp),
colors = ButtonDefaults.buttonColors(
containerColor = MaterialTheme.colorScheme.errorContainer
),
- shape = RoundedCornerShape(14.dp)
+ shape = RoundedCornerShape(28.dp)
) {
Row(
verticalAlignment = Alignment.CenterVertically,
@@ -1251,9 +650,9 @@ fun AppSettingsScreen(navController: NavController) {
Spacer(modifier = Modifier.height(32.dp))
- if (showResetDialog) {
+ if (showResetDialog.value) {
AlertDialog(
- onDismissRequest = { showResetDialog = false },
+ onDismissRequest = { showResetDialog.value = false },
title = {
Text(
"Reset Hook Offset",
@@ -1289,7 +688,7 @@ fun AppSettingsScreen(navController: NavController) {
Toast.LENGTH_SHORT
).show()
}
- showResetDialog = false
+ showResetDialog.value = false
},
colors = ButtonDefaults.textButtonColors(
contentColor = MaterialTheme.colorScheme.error
@@ -1304,7 +703,7 @@ fun AppSettingsScreen(navController: NavController) {
},
dismissButton = {
TextButton(
- onClick = { showResetDialog = false }
+ onClick = { showResetDialog.value = false }
) {
Text(
"Cancel",
@@ -1316,9 +715,9 @@ fun AppSettingsScreen(navController: NavController) {
)
}
- if (showIrkDialog) {
+ if (showIrkDialog.value) {
AlertDialog(
- onDismissRequest = { showIrkDialog = false },
+ onDismissRequest = { showIrkDialog.value = false },
title = {
Text(
stringResource(R.string.set_identity_resolving_key),
@@ -1335,13 +734,13 @@ fun AppSettingsScreen(navController: NavController) {
)
OutlinedTextField(
- value = irkValue,
+ value = irkValue.value,
onValueChange = {
- irkValue = it.lowercase().filter { char -> char.isDigit() || char in 'a'..'f' }
- irkError = null
+ irkValue.value = it.lowercase().filter { char -> char.isDigit() || char in 'a'..'f' }
+ irkError.value = null
},
modifier = Modifier.fillMaxWidth(),
- isError = irkError != null,
+ isError = irkError.value != null,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Ascii,
capitalization = KeyboardCapitalization.None
@@ -1351,7 +750,7 @@ fun AppSettingsScreen(navController: NavController) {
unfocusedBorderColor = if (isDarkTheme) Color.Gray else Color.LightGray
),
supportingText = {
- if (irkError != null) {
+ if (irkError.value != null) {
Text(stringResource(R.string.must_be_32_hex_chars), color = MaterialTheme.colorScheme.error)
}
},
@@ -1364,15 +763,15 @@ fun AppSettingsScreen(navController: NavController) {
val errorText = stringResource(R.string.error_converting_hex)
TextButton(
onClick = {
- if (!validateHexInput(irkValue)) {
- irkError = "Must be exactly 32 hex characters"
+ if (!validateHexInput(irkValue.value)) {
+ irkError.value = "Must be exactly 32 hex characters"
return@TextButton
}
try {
val hexBytes = ByteArray(16)
for (i in 0 until 16) {
- val hexByte = irkValue.substring(i * 2, i * 2 + 2)
+ val hexByte = irkValue.value.substring(i * 2, i * 2 + 2)
hexBytes[i] = hexByte.toInt(16).toByte()
}
@@ -1380,9 +779,9 @@ fun AppSettingsScreen(navController: NavController) {
sharedPreferences.edit { putString(AACPManager.Companion.ProximityKeyType.IRK.name, base64Value)}
Toast.makeText(context, successText, Toast.LENGTH_SHORT).show()
- showIrkDialog = false
+ showIrkDialog.value = false
} catch (e: Exception) {
- irkError = errorText + " " + (e.message ?: "Unknown error")
+ irkError.value = errorText + " " + (e.message ?: "Unknown error")
}
}
) {
@@ -1395,7 +794,7 @@ fun AppSettingsScreen(navController: NavController) {
},
dismissButton = {
TextButton(
- onClick = { showIrkDialog = false }
+ onClick = { showIrkDialog.value = false }
) {
Text(
"Cancel",
@@ -1407,9 +806,9 @@ fun AppSettingsScreen(navController: NavController) {
)
}
- if (showEncKeyDialog) {
+ if (showEncKeyDialog.value) {
AlertDialog(
- onDismissRequest = { showEncKeyDialog = false },
+ onDismissRequest = { showEncKeyDialog.value = false },
title = {
Text(
stringResource(R.string.set_encryption_key),
@@ -1426,13 +825,13 @@ fun AppSettingsScreen(navController: NavController) {
)
OutlinedTextField(
- value = encKeyValue,
+ value = encKeyValue.value,
onValueChange = {
- encKeyValue = it.lowercase().filter { char -> char.isDigit() || char in 'a'..'f' }
- encKeyError = null
+ encKeyValue.value = it.lowercase().filter { char -> char.isDigit() || char in 'a'..'f' }
+ encKeyError.value = null
},
modifier = Modifier.fillMaxWidth(),
- isError = encKeyError != null,
+ isError = encKeyError.value != null,
keyboardOptions = KeyboardOptions(
keyboardType = KeyboardType.Ascii,
capitalization = KeyboardCapitalization.None
@@ -1442,7 +841,7 @@ fun AppSettingsScreen(navController: NavController) {
unfocusedBorderColor = if (isDarkTheme) Color.Gray else Color.LightGray
),
supportingText = {
- if (encKeyError != null) {
+ if (encKeyError.value != null) {
Text(stringResource(R.string.must_be_32_hex_chars), color = MaterialTheme.colorScheme.error)
}
},
@@ -1455,15 +854,15 @@ fun AppSettingsScreen(navController: NavController) {
val errorText = stringResource(R.string.error_converting_hex)
TextButton(
onClick = {
- if (!validateHexInput(encKeyValue)) {
- encKeyError = "Must be exactly 32 hex characters"
+ if (!validateHexInput(encKeyValue.value)) {
+ encKeyError.value = "Must be exactly 32 hex characters"
return@TextButton
}
try {
val hexBytes = ByteArray(16)
for (i in 0 until 16) {
- val hexByte = encKeyValue.substring(i * 2, i * 2 + 2)
+ val hexByte = encKeyValue.value.substring(i * 2, i * 2 + 2)
hexBytes[i] = hexByte.toInt(16).toByte()
}
@@ -1471,9 +870,9 @@ fun AppSettingsScreen(navController: NavController) {
sharedPreferences.edit { putString(AACPManager.Companion.ProximityKeyType.ENC_KEY.name, base64Value)}
Toast.makeText(context, successText, Toast.LENGTH_SHORT).show()
- showEncKeyDialog = false
+ showEncKeyDialog.value = false
} catch (e: Exception) {
- encKeyError = errorText + " " + (e.message ?: "Unknown error")
+ encKeyError.value = errorText + " " + (e.message ?: "Unknown error")
}
}
) {
@@ -1486,7 +885,7 @@ fun AppSettingsScreen(navController: NavController) {
},
dismissButton = {
TextButton(
- onClick = { showEncKeyDialog = false }
+ onClick = { showEncKeyDialog.value = false }
) {
Text(
"Cancel",
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/DebugScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/DebugScreen.kt
index f9dbdab..fc3bf05 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/DebugScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/DebugScreen.kt
@@ -40,14 +40,11 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding
-import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState
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.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.Send
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
@@ -78,6 +75,8 @@ import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
+import com.kyant.backdrop.backdrops.layerBackdrop
+import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.delay
@@ -325,14 +324,15 @@ fun DebugScreen(navController: NavController) {
}
val isDarkTheme = isSystemInDarkTheme()
-
+ val backdrop = rememberLayerBackdrop()
StyledScaffold(
title = "Debug",
navigationButton = {
StyledIconButton(
onClick = { navController.popBackStack() },
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
},
actionButtons = listOf(
@@ -344,6 +344,7 @@ fun DebugScreen(navController: NavController) {
},
icon = "",
darkMode = isDarkTheme,
+ backdrop = backdrop
)
}
),
@@ -353,6 +354,7 @@ fun DebugScreen(navController: NavController) {
.fillMaxSize()
.hazeSource(hazeState)
.navigationBarsPadding()
+ .layerBackdrop(backdrop)
.padding(horizontal = 16.dp)
) {
Spacer(modifier = Modifier.height(spacerHeight))
@@ -391,11 +393,13 @@ fun DebugScreen(navController: NavController) {
)
) {
Row(verticalAlignment = Alignment.CenterVertically) {
- Icon(
- imageVector = if (isSent) Icons.AutoMirrored.Filled.KeyboardArrowLeft else Icons.AutoMirrored.Filled.KeyboardArrowRight,
- contentDescription = null,
- tint = if (isSent) Color.Green else Color.Red,
- modifier = Modifier.size(24.dp)
+ Text(
+ text = if (isSent) "" else "",
+ style = TextStyle(
+ fontSize = 16.sp,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ color = if (isSent) Color(0xFF4CD964) else Color(0xFFFF3B30)
+ ),
)
Spacer(modifier = Modifier.width(4.dp))
Column {
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/HeadTrackingScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/HeadTrackingScreen.kt
index ad71bb4..a42241a 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/HeadTrackingScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/HeadTrackingScreen.kt
@@ -42,10 +42,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
-import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
-import androidx.compose.material3.Button
-import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
@@ -87,12 +84,15 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
+import com.kyant.backdrop.backdrops.layerBackdrop
+import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch
import me.kavishdevar.librepods.R
+import me.kavishdevar.librepods.composables.StyledButton
import me.kavishdevar.librepods.composables.StyledIconButton
import me.kavishdevar.librepods.composables.StyledScaffold
import me.kavishdevar.librepods.composables.StyledToggle
@@ -116,18 +116,19 @@ fun HeadTrackingScreen(navController: NavController) {
}
}
val isDarkTheme = isSystemInDarkTheme()
- val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
+ if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
val textColor = if (isDarkTheme) Color.White else Color.Black
val scrollState = rememberScrollState()
-
+ val backdrop = rememberLayerBackdrop()
StyledScaffold (
title = stringResource(R.string.head_tracking),
navigationButton = {
StyledIconButton(
onClick = { navController.popBackStack() },
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
},
actionButtons = listOf(
@@ -144,72 +145,95 @@ fun HeadTrackingScreen(navController: NavController) {
}
},
icon = if (isActive) "" else "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
}
),
) { spacerHeight, hazeState ->
- Column (
+ val backdrop = rememberLayerBackdrop()
+ val sharedPreferences = LocalContext.current.getSharedPreferences("settings", Context.MODE_PRIVATE)
+
+ var gestureText by remember { mutableStateOf("") }
+ val coroutineScope = rememberCoroutineScope()
+
+ var lastClickTime by remember { mutableLongStateOf(0L) }
+ var shouldExplode by remember { mutableStateOf(false) }
+ Column(
modifier = Modifier
- .fillMaxSize()
- .padding(top = 8.dp)
- .padding(horizontal = 16.dp)
- .verticalScroll(scrollState)
- .hazeSource(state = hazeState)
+ .layerBackdrop(backdrop)
+ .fillMaxWidth(),
+ horizontalAlignment = Alignment.CenterHorizontally
) {
- Spacer(modifier = Modifier.height(spacerHeight))
- val sharedPreferences =
- LocalContext.current.getSharedPreferences("settings", Context.MODE_PRIVATE)
+ Column (
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(top = 8.dp)
+ .padding(horizontal = 16.dp)
+ .verticalScroll(scrollState)
+ .hazeSource(state = hazeState)
+ .layerBackdrop(
+ backdrop = backdrop
+ )
+ ) {
+ Spacer(modifier = Modifier.height(spacerHeight))
+ StyledToggle(
+ label = "Head Gestures",
+ sharedPreferences = sharedPreferences,
+ sharedPreferenceKey = "head_gestures",
+ )
- var gestureText by remember { mutableStateOf("") }
- val coroutineScope = rememberCoroutineScope()
+ Spacer(modifier = Modifier.height(2.dp))
+ Text(
+ stringResource(R.string.head_gestures_details),
+ style = TextStyle(
+ fontSize = 14.sp,
+ fontWeight = FontWeight.Normal,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ color = textColor.copy(0.6f)
+ ),
+ modifier = Modifier.padding(start = 4.dp)
+ )
- StyledToggle(
- label = "Head Gestures",
- sharedPreferences = sharedPreferences,
- sharedPreferenceKey = "head_gestures",
- )
-
- Spacer(modifier = Modifier.height(2.dp))
- Text(
- stringResource(R.string.head_gestures_details),
- style = TextStyle(
- fontSize = 14.sp,
- fontWeight = FontWeight.Normal,
- fontFamily = FontFamily(Font(R.font.sf_pro)),
- color = textColor.copy(0.6f)
- ),
- modifier = Modifier.padding(start = 4.dp)
- )
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ "Head Orientation",
+ style = TextStyle(
+ fontSize = 18.sp,
+ fontWeight = FontWeight.Medium,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ color = textColor
+ ),
+ modifier = Modifier.padding(start = 4.dp, bottom = 8.dp, top = 8.dp)
+ )
+ HeadVisualization()
- Spacer(modifier = Modifier.height(16.dp))
- Text(
- "Head Orientation",
- style = TextStyle(
- fontSize = 18.sp,
- fontWeight = FontWeight.Medium,
- fontFamily = FontFamily(Font(R.font.sf_pro)),
- color = textColor
- ),
- modifier = Modifier.padding(start = 4.dp, bottom = 8.dp, top = 8.dp)
- )
- HeadVisualization()
+ Spacer(modifier = Modifier.height(16.dp))
+ Text(
+ "Velocity",
+ style = TextStyle(
+ fontSize = 18.sp,
+ fontWeight = FontWeight.Medium,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ color = textColor
+ ),
+ modifier = Modifier.padding(start = 4.dp, bottom = 8.dp, top = 8.dp)
+ )
+ AccelerationPlot()
- Spacer(modifier = Modifier.height(16.dp))
- Text(
- "Velocity",
- style = TextStyle(
- fontSize = 18.sp,
- fontWeight = FontWeight.Medium,
- fontFamily = FontFamily(Font(R.font.sf_pro)),
- color = textColor
- ),
- modifier = Modifier.padding(start = 4.dp, bottom = 8.dp, top = 8.dp)
- )
- AccelerationPlot()
+ Spacer(modifier = Modifier.height(16.dp))
- Spacer(modifier = Modifier.height(16.dp))
- Button (
+ LaunchedEffect(gestureText) {
+ if (gestureText.isNotEmpty()) {
+ lastClickTime = System.currentTimeMillis()
+ delay(3000)
+ if (System.currentTimeMillis() - lastClickTime >= 3000) {
+ shouldExplode = true
+ }
+ }
+ }
+ }
+ StyledButton(
onClick = {
gestureText = "Shake your head or nod!"
coroutineScope.launch {
@@ -217,13 +241,9 @@ fun HeadTrackingScreen(navController: NavController) {
gestureText = if (accepted) "\"Yes\" gesture detected." else "\"No\" gesture detected."
}
},
- modifier = Modifier
- .fillMaxWidth()
- .height(55.dp),
- colors = ButtonDefaults.buttonColors(
- containerColor = backgroundColor
- ),
- shape = RoundedCornerShape(8.dp)
+ backdrop = backdrop,
+ modifier = Modifier.fillMaxWidth(0.75f),
+ maxScale = 0.05f
) {
Text(
"Test Head Gestures",
@@ -235,19 +255,6 @@ fun HeadTrackingScreen(navController: NavController) {
),
)
}
- var lastClickTime by remember { mutableLongStateOf(0L) }
- var shouldExplode by remember { mutableStateOf(false) }
-
- LaunchedEffect(gestureText) {
- if (gestureText.isNotEmpty()) {
- lastClickTime = System.currentTimeMillis()
- delay(3000)
- if (System.currentTimeMillis() - lastClickTime >= 3000) {
- shouldExplode = true
- }
- }
- }
-
Box(
contentAlignment = Alignment.Center,
modifier = Modifier.padding(top = 12.dp, bottom = 24.dp)
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidAdjustmentsScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidAdjustmentsScreen.kt
index 6c642a5..1a48a12 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidAdjustmentsScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidAdjustmentsScreen.kt
@@ -41,6 +41,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.navigation.NavController
+import com.kyant.backdrop.backdrops.layerBackdrop
+import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.HazeState
import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
@@ -77,14 +79,15 @@ fun HearingAidAdjustmentsScreen(@Suppress("unused") navController: NavController
val attManager = ServiceManager.getService()?.attManager ?: throw IllegalStateException("ATTManager not available")
val aacpManager = remember { ServiceManager.getService()?.aacpManager }
-
+ val backdrop = rememberLayerBackdrop()
StyledScaffold(
title = stringResource(R.string.adjustments),
navigationButton = {
StyledIconButton(
onClick = { navController.popBackStack() },
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
}
) { spacerHeight ->
@@ -92,6 +95,7 @@ fun HearingAidAdjustmentsScreen(@Suppress("unused") navController: NavController
modifier = Modifier
.hazeSource(hazeState)
.fillMaxSize()
+ .layerBackdrop(backdrop)
.verticalScroll(verticalScrollState)
.padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp)
@@ -282,7 +286,7 @@ fun HearingAidAdjustmentsScreen(@Suppress("unused") navController: NavController
}
StyledSlider(
- label = stringResource(R.string.amplification).uppercase(),
+ label = stringResource(R.string.amplification),
valueRange = -1f..1f,
mutableFloatState = amplificationSliderValue,
onValueChange = {
@@ -301,20 +305,20 @@ fun HearingAidAdjustmentsScreen(@Suppress("unused") navController: NavController
)
StyledSlider(
- label = stringResource(R.string.balance).uppercase(),
+ label = stringResource(R.string.balance),
valueRange = -1f..1f,
mutableFloatState = balanceSliderValue,
onValueChange = {
balanceSliderValue.floatValue = it
},
- snapPoints = listOf(0f),
+ snapPoints = listOf(-1f, 0f, 1f),
startLabel = stringResource(R.string.left),
endLabel = stringResource(R.string.right),
independent = true,
)
StyledSlider(
- label = stringResource(R.string.tone).uppercase(),
+ label = stringResource(R.string.tone),
valueRange = -1f..1f,
mutableFloatState = toneSliderValue,
onValueChange = {
@@ -326,7 +330,7 @@ fun HearingAidAdjustmentsScreen(@Suppress("unused") navController: NavController
)
StyledSlider(
- label = stringResource(R.string.ambient_noise_reduction).uppercase(),
+ label = stringResource(R.string.ambient_noise_reduction),
valueRange = 0f..1f,
mutableFloatState = ambientNoiseReductionSliderValue,
onValueChange = {
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidScreen.kt
index 106ea48..28e4c98 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidScreen.kt
@@ -20,15 +20,10 @@ package me.kavishdevar.librepods.screens
import android.annotation.SuppressLint
import android.util.Log
-import androidx.compose.animation.animateColorAsState
-import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
-import androidx.compose.foundation.clickable
-import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -37,25 +32,18 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
-import androidx.compose.material3.Icon
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
-import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
-import androidx.compose.runtime.setValue
-import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
-import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
@@ -74,9 +62,9 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import me.kavishdevar.librepods.R
import me.kavishdevar.librepods.composables.ConfirmationDialog
+import me.kavishdevar.librepods.composables.NavigationButton
import me.kavishdevar.librepods.composables.StyledIconButton
import me.kavishdevar.librepods.composables.StyledScaffold
-import me.kavishdevar.librepods.composables.StyledSwitch
import me.kavishdevar.librepods.composables.StyledToggle
import me.kavishdevar.librepods.services.ServiceManager
import me.kavishdevar.librepods.utils.AACPManager
@@ -117,7 +105,8 @@ fun HearingAidScreen(navController: NavController) {
StyledIconButton(
onClick = { navController.popBackStack() },
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
},
actionButtons = emptyList(),
@@ -129,7 +118,7 @@ fun HearingAidScreen(navController: NavController) {
.hazeSource(hazeState)
.fillMaxSize()
.verticalScroll(verticalScrollState)
- .padding(16.dp),
+ .padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp)
) {
Spacer(modifier = Modifier.height(spacerHeight))
@@ -175,22 +164,22 @@ fun HearingAidScreen(navController: NavController) {
}
fun onAdjustPhoneChange(value: Boolean) {
- adjustPhoneEnabled.value = value
+ // TODO
}
fun onAdjustMediaChange(value: Boolean) {
- adjustMediaEnabled.value = value
+ // TODO
}
Text(
- text = stringResource(R.string.hearing_aid).uppercase(),
+ text = stringResource(R.string.hearing_aid),
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
- modifier = Modifier.padding(8.dp, bottom = 2.dp)
+ modifier = Modifier.padding(16.dp, bottom = 2.dp)
)
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
@@ -198,9 +187,9 @@ fun HearingAidScreen(navController: NavController) {
Column(
modifier = Modifier
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp))
+ .background(backgroundColor, RoundedCornerShape(28.dp))
.clip(
- RoundedCornerShape(14.dp)
+ RoundedCornerShape(28.dp)
)
) {
StyledToggle(
@@ -209,31 +198,17 @@ fun HearingAidScreen(navController: NavController) {
independent = false
)
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888),
modifier = Modifier
- .padding(start = 12.dp, end = 0.dp)
+ .padding(horizontal = 12.dp)
+ )
+ NavigationButton(
+ to = "hearing_aid_adjustments",
+ name = stringResource(R.string.adjustments),
+ navController,
+ independent = false
)
-
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .clickable { navController.navigate("hearing_aid_adjustments") }
- .padding(12.dp),
- verticalAlignment = Alignment.CenterVertically
- ) {
- Text(
- text = stringResource(R.string.adjustments),
- fontSize = 16.sp,
- color = textColor
- )
- Spacer(modifier = Modifier.weight(1f))
- Icon(
- imageVector = Icons.AutoMirrored.Filled.KeyboardArrowRight,
- contentDescription = null,
- tint = textColor
- )
- }
}
Text(
text = stringResource(R.string.hearing_aid_description),
@@ -243,12 +218,12 @@ fun HearingAidScreen(navController: NavController) {
color = (if (isSystemInDarkTheme()) Color.White else Color.Black).copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
- modifier = Modifier.padding(horizontal = 8.dp)
+ modifier = Modifier.padding(horizontal = 16.dp)
)
Spacer(modifier = Modifier.height(16.dp))
-
+
StyledToggle(
- title = stringResource(R.string.media_assist).uppercase(),
+ title = stringResource(R.string.media_assist),
label = stringResource(R.string.media_assist),
checkedState = mediaAssistEnabled,
independent = true,
@@ -260,99 +235,27 @@ fun HearingAidScreen(navController: NavController) {
Column (
modifier = Modifier
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp))
+ .background(backgroundColor, RoundedCornerShape(28.dp))
) {
- val isDarkThemeLocal = isSystemInDarkTheme()
- var backgroundColorAdjustMedia by remember { mutableStateOf(if (isDarkThemeLocal) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
- val animatedBackgroundColorAdjustMedia by animateColorAsState(targetValue = backgroundColorAdjustMedia, animationSpec = tween(durationMillis = 500))
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .padding(12.dp)
- .pointerInput(Unit) {
- detectTapGestures(
- onPress = {
- backgroundColorAdjustMedia = if (isDarkThemeLocal) Color(0x40888888) else Color(0x40D9D9D9)
- tryAwaitRelease()
- backgroundColorAdjustMedia = if (isDarkThemeLocal) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
- },
- onTap = {
- onAdjustMediaChange(!adjustMediaEnabled.value)
- }
- )
- }
- .background(
- animatedBackgroundColorAdjustMedia,
- RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp)
- ),
- verticalAlignment = Alignment.CenterVertically
- ) {
- Text(
- text = stringResource(R.string.adjust_media),
- modifier = Modifier.weight(1f),
- style = TextStyle(
- fontSize = 16.sp,
- fontFamily = FontFamily(Font(R.font.sf_pro)),
- fontWeight = FontWeight.Normal,
- color = textColor
- )
- )
- StyledSwitch(
- checked = adjustMediaEnabled.value,
- onCheckedChange = {
- onAdjustMediaChange(it)
- },
- )
- }
-
+ StyledToggle(
+ label = stringResource(R.string.adjust_media),
+ checkedState = adjustMediaEnabled,
+ onCheckedChange = { onAdjustMediaChange(it) },
+ independent = false
+ )
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888),
modifier = Modifier
- .padding(start = 12.dp, end = 0.dp)
+ .padding(horizontal = 12.dp)
)
- var backgroundColorAdjustPhone by remember { mutableStateOf(if (isDarkThemeLocal) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
- val animatedBackgroundColorAdjustPhone by animateColorAsState(targetValue = backgroundColorAdjustPhone, animationSpec = tween(durationMillis = 500))
- Row(
- modifier = Modifier
- .fillMaxWidth()
- .padding(12.dp)
- .pointerInput(Unit) {
- detectTapGestures(
- onPress = {
- backgroundColorAdjustPhone = if (isDarkThemeLocal) Color(0x40888888) else Color(0x40D9D9D9)
- tryAwaitRelease()
- backgroundColorAdjustPhone = if (isDarkThemeLocal) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
- },
- onTap = {
- onAdjustPhoneChange(!adjustPhoneEnabled.value)
- }
- )
- }
- .background(
- animatedBackgroundColorAdjustPhone,
- RoundedCornerShape(bottomStart = 14.dp, bottomEnd = 14.dp)
- ),
- verticalAlignment = Alignment.CenterVertically
- ) {
- Text(
- text = stringResource(R.string.adjust_calls),
- modifier = Modifier.weight(1f),
- style = TextStyle(
- fontSize = 16.sp,
- fontFamily = FontFamily(Font(R.font.sf_pro)),
- fontWeight = FontWeight.Normal,
- color = textColor
- )
- )
- StyledSwitch(
- checked = adjustPhoneEnabled.value,
- onCheckedChange = {
- onAdjustPhoneChange(it)
- },
- )
- }
+ StyledToggle(
+ label = stringResource(R.string.adjust_calls),
+ checkedState = adjustPhoneEnabled,
+ onCheckedChange = { onAdjustPhoneChange(it) },
+ independent = false
+ )
}
}
}
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/Onboarding.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/Onboarding.kt
index e6420bb..7e886ba 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/Onboarding.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/Onboarding.kt
@@ -73,6 +73,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.edit
import androidx.navigation.NavController
+import com.kyant.backdrop.backdrops.layerBackdrop
+import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@@ -151,6 +153,7 @@ fun Onboarding(navController: NavController, activityContext: Context) {
isComplete = true
}
}
+ val backdrop = rememberLayerBackdrop()
StyledScaffold(
title = "Setting Up",
actionButtons = listOf(
@@ -160,7 +163,8 @@ fun Onboarding(navController: NavController, activityContext: Context) {
showSkipDialog = true
},
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
}
)
@@ -168,6 +172,7 @@ fun Onboarding(navController: NavController, activityContext: Context) {
Column(
modifier = Modifier
.fillMaxSize()
+ .layerBackdrop(backdrop)
.padding(horizontal = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp)
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/PressAndHoldSettingsScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/PressAndHoldSettingsScreen.kt
index 032cbc4..d461322 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/PressAndHoldSettingsScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/PressAndHoldSettingsScreen.kt
@@ -23,6 +23,7 @@ package me.kavishdevar.librepods.screens
import android.content.Context
import android.util.Log
import androidx.compose.animation.animateColorAsState
+import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
@@ -37,8 +38,6 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape
-import androidx.compose.material3.Checkbox
-import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
@@ -50,11 +49,11 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
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.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
+import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
@@ -63,6 +62,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.edit
import androidx.navigation.NavController
+import com.kyant.backdrop.backdrops.layerBackdrop
+import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import me.kavishdevar.librepods.R
import me.kavishdevar.librepods.composables.StyledIconButton
@@ -76,20 +77,20 @@ import kotlin.io.encoding.ExperimentalEncodingApi
@Composable
fun RightDivider() {
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888),
modifier = Modifier
- .padding(start = 72.dp)
+ .padding(start = 72.dp, end = 20.dp)
)
}
@Composable
fun RightDividerNoIcon() {
HorizontalDivider(
- thickness = 1.5.dp,
+ thickness = 1.dp,
color = Color(0x40888888),
modifier = Modifier
- .padding(start = 20.dp)
+ .padding(start = 20.dp, end = 20.dp)
)
}
@@ -117,19 +118,22 @@ fun LongPress(navController: NavController, name: String) {
val longPressActionPref = sharedPreferences.getString(prefKey, StemAction.CYCLE_NOISE_CONTROL_MODES.name)
Log.d("PressAndHoldSettingsScreen", "Long press action preference ($prefKey): $longPressActionPref")
var longPressAction by remember { mutableStateOf(StemAction.valueOf(longPressActionPref ?: StemAction.CYCLE_NOISE_CONTROL_MODES.name)) }
+ val backdrop = rememberLayerBackdrop()
StyledScaffold(
title = name,
navigationButton = {
StyledIconButton(
onClick = { navController.popBackStack() },
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
}
) { spacerHeight ->
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
Column (
modifier = Modifier
+ .layerBackdrop(backdrop)
.fillMaxSize()
.padding(top = 8.dp)
.padding(horizontal = 16.dp)
@@ -138,11 +142,11 @@ fun LongPress(navController: NavController, name: String) {
Column(
modifier = Modifier
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp)),
+ .background(backgroundColor, RoundedCornerShape(28.dp)),
horizontalAlignment = Alignment.CenterHorizontally
) {
LongPressActionElement(
- name = "Noise Control",
+ name = stringResource(R.string.noise_control),
selected = longPressAction == StemAction.CYCLE_NOISE_CONTROL_MODES,
onClick = {
longPressAction = StemAction.CYCLE_NOISE_CONTROL_MODES
@@ -153,7 +157,7 @@ fun LongPress(navController: NavController, name: String) {
)
RightDividerNoIcon()
LongPressActionElement(
- name = "Digital Assistant",
+ name = stringResource(R.string.digital_assistant),
selected = longPressAction == StemAction.DIGITAL_ASSISTANT,
onClick = {
longPressAction = StemAction.DIGITAL_ASSISTANT
@@ -165,23 +169,25 @@ fun LongPress(navController: NavController, name: String) {
}
if (longPressAction == StemAction.CYCLE_NOISE_CONTROL_MODES) {
+ Spacer(modifier = Modifier.height(32.dp))
Text(
- text = "NOISE CONTROL",
+ text = stringResource(R.string.noise_control),
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f),
),
fontFamily = FontFamily(Font(R.font.sf_pro)),
modifier = Modifier
- .padding(top = 32.dp, bottom = 4.dp)
- .padding(horizontal = 8.dp)
+ .padding(horizontal = 18.dp)
)
+ Spacer(modifier = Modifier.height(8.dp))
+
Column(
modifier = Modifier
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp)),
+ .background(backgroundColor, RoundedCornerShape(28.dp)),
horizontalAlignment = Alignment.CenterHorizontally
) {
val offListeningModeValue = ServiceManager.getService()!!.aacpManager.controlCommandStatusList.find {
@@ -189,28 +195,28 @@ fun LongPress(navController: NavController, name: String) {
}?.value?.takeIf { it.isNotEmpty() }?.get(0)
val offListeningMode = offListeningModeValue == 1.toByte()
ListeningModeElement(
- name = "Off",
+ name = stringResource(R.string.off),
enabled = offListeningMode,
resourceId = R.drawable.noise_cancellation,
isFirst = true)
if (offListeningMode) RightDivider()
ListeningModeElement(
- name = "Transparency",
+ name = stringResource(R.string.transparency),
resourceId = R.drawable.transparency,
isFirst = !offListeningMode)
RightDivider()
ListeningModeElement(
- name = "Adaptive",
+ name = stringResource(R.string.adaptive),
resourceId = R.drawable.adaptive)
RightDivider()
ListeningModeElement(
- name = "Noise Cancellation",
+ name = stringResource(R.string.noise_cancellation),
resourceId = R.drawable.noise_cancellation,
isLast = true)
}
- Spacer(modifier = Modifier.height(4.dp))
+ Spacer(modifier = Modifier.height(8.dp))
Text(
- text = "Press and hold the stem to cycle between the selected noise control modes.",
+ text = stringResource(R.string.press_and_hold_noise_control_description),
style = TextStyle(
fontSize = 12.sp,
fontWeight = FontWeight.Light,
@@ -218,7 +224,7 @@ fun LongPress(navController: NavController, name: String) {
fontFamily = FontFamily(Font(R.font.sf_pro))
),
modifier = Modifier
- .padding(horizontal = 8.dp)
+ .padding(horizontal = 18.dp)
)
}
}
@@ -329,8 +335,8 @@ fun ListeningModeElement(name: String, enabled: Boolean = true, resourceId: Int,
}
val shape = when {
- isFirst -> RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp)
- isLast -> RoundedCornerShape(bottomStart = 14.dp, bottomEnd = 14.dp)
+ isFirst -> RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp)
+ isLast -> RoundedCornerShape(bottomStart = 28.dp, bottomEnd = 28.dp)
else -> RoundedCornerShape(0.dp)
}
var backgroundColor by remember { mutableStateOf(if (darkMode) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
@@ -352,7 +358,7 @@ fun ListeningModeElement(name: String, enabled: Boolean = true, resourceId: Int,
},
)
}
- .padding(horizontal = 16.dp, vertical = 0.dp),
+ .padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
@@ -384,24 +390,19 @@ fun ListeningModeElement(name: String, enabled: Boolean = true, resourceId: Int,
fontFamily = FontFamily(Font(R.font.sf_pro)),
)
}
- Checkbox(
- checked = checked.value,
- onCheckedChange = { valueChanged() },
- colors = CheckboxDefaults.colors().copy(
- checkedCheckmarkColor = Color(0xFF007AFF),
- uncheckedCheckmarkColor = Color.Transparent,
- checkedBoxColor = Color.Transparent,
- uncheckedBoxColor = Color.Transparent,
- checkedBorderColor = Color.Transparent,
- uncheckedBorderColor = Color.Transparent,
- disabledBorderColor = Color.Transparent,
- disabledCheckedBoxColor = Color.Transparent,
- disabledUncheckedBoxColor = Color.Transparent,
- disabledUncheckedBorderColor = Color.Transparent
+
+ val floatAnimateState by animateFloatAsState(
+ targetValue = if (checked.value) 1f else 0f,
+ animationSpec = tween(durationMillis = 300)
+ )
+ Text(
+ text = "",
+ style = TextStyle(
+ fontSize = 20.sp,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ color = Color(0xFF007AFF).copy(alpha = floatAnimateState),
),
- modifier = Modifier
- .height(24.dp)
- .scale(1.5f),
+ modifier = Modifier.padding(end = 4.dp)
)
}
}
@@ -417,15 +418,15 @@ fun LongPressActionElement(
) {
val darkMode = isSystemInDarkTheme()
val shape = when {
- isFirst -> RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp)
- isLast -> RoundedCornerShape(bottomStart = 14.dp, bottomEnd = 14.dp)
+ isFirst -> RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp)
+ isLast -> RoundedCornerShape(bottomStart = 28.dp, bottomEnd = 28.dp)
else -> RoundedCornerShape(0.dp)
}
var backgroundColor by remember { mutableStateOf(if (darkMode) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
val animatedBackgroundColor by animateColorAsState(targetValue = backgroundColor, animationSpec = tween(durationMillis = 500))
Row(
modifier = Modifier
- .height(48.dp)
+ .height(55.dp)
.background(animatedBackgroundColor, shape)
.pointerInput(Unit) {
detectTapGestures(
@@ -437,7 +438,7 @@ fun LongPressActionElement(
}
)
}
- .padding(horizontal = 16.dp, vertical = 0.dp),
+ .padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
@@ -449,24 +450,18 @@ fun LongPressActionElement(
.weight(1f)
.padding(start = 4.dp)
)
- Checkbox(
- checked = selected,
- onCheckedChange = { onClick() },
- colors = CheckboxDefaults.colors().copy(
- checkedCheckmarkColor = Color(0xFF007AFF),
- uncheckedCheckmarkColor = Color.Transparent,
- checkedBoxColor = Color.Transparent,
- uncheckedBoxColor = Color.Transparent,
- checkedBorderColor = Color.Transparent,
- uncheckedBorderColor = Color.Transparent,
- disabledBorderColor = Color.Transparent,
- disabledCheckedBoxColor = Color.Transparent,
- disabledUncheckedBoxColor = Color.Transparent,
- disabledUncheckedBorderColor = Color.Transparent
+ val floatAnimateState by animateFloatAsState(
+ targetValue = if (selected) 1f else 0f,
+ animationSpec = tween(durationMillis = 300)
+ )
+ Text(
+ text = "",
+ style = TextStyle(
+ fontSize = 20.sp,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ color = Color(0xFF007AFF).copy(alpha = floatAnimateState)
),
- modifier = Modifier
- .height(24.dp)
- .scale(1.5f),
+ modifier = Modifier.padding(end = 4.dp)
)
}
}
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/RenameScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/RenameScreen.kt
index 9dd1f95..11f5eba 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/RenameScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/RenameScreen.kt
@@ -32,11 +32,9 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField
-import androidx.compose.material.icons.Icons
-import androidx.compose.material.icons.filled.Clear
import androidx.compose.material3.ExperimentalMaterial3Api
-import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
+import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf
@@ -52,12 +50,16 @@ import androidx.compose.ui.platform.LocalSoftwareKeyboardController
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextRange
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.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.edit
import androidx.navigation.NavController
+import com.kyant.backdrop.backdrops.layerBackdrop
+import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import me.kavishdevar.librepods.R
import me.kavishdevar.librepods.composables.StyledIconButton
@@ -81,19 +83,23 @@ fun RenameScreen(navController: NavController) {
name.value = name.value.copy(selection = TextRange(name.value.text.length))
}
+ val backdrop = rememberLayerBackdrop()
+
StyledScaffold(
title = stringResource(R.string.name),
navigationButton = {
StyledIconButton(
onClick = { navController.popBackStack() },
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
},
) { spacerHeight ->
Column(
modifier = Modifier
.fillMaxSize()
+ .layerBackdrop(backdrop)
.padding(horizontal = 16.dp)
) {
Spacer(modifier = Modifier.height(spacerHeight))
@@ -105,10 +111,10 @@ fun RenameScreen(navController: NavController) {
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier
.fillMaxWidth()
- .height(55.dp)
+ .height(58.dp)
.background(
backgroundColor,
- RoundedCornerShape(14.dp)
+ RoundedCornerShape(28.dp)
)
.padding(horizontal = 16.dp, vertical = 8.dp)
) {
@@ -120,8 +126,9 @@ fun RenameScreen(navController: NavController) {
ServiceManager.getService()?.setName(it.text)
},
textStyle = TextStyle(
- color = textColor,
fontSize = 16.sp,
+ color = textColor,
+ fontFamily = FontFamily(Font(R.font.sf_pro))
),
singleLine = true,
cursorBrush = SolidColor(cursorColor),
@@ -138,14 +145,15 @@ fun RenameScreen(navController: NavController) {
IconButton(
onClick = {
name.value = TextFieldValue("")
- sharedPreferences.edit { putString("name", "") }
- ServiceManager.getService()?.setName("")
}
) {
- Icon(
- Icons.Default.Clear,
- contentDescription = "Clear",
- tint = if (isDarkTheme) Color.White else Color.Black
+ Text(
+ text = "",
+ style = TextStyle(
+ fontSize = 16.sp,
+ fontFamily = FontFamily(Font(R.font.sf_pro)),
+ color = if (isDarkTheme) Color.White.copy(alpha = 0.6f) else Color.Black.copy(alpha = 0.6f)
+ ),
)
}
}
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/TransparencySettingsScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/TransparencySettingsScreen.kt
index a0a8855..ebee5a5 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/TransparencySettingsScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/TransparencySettingsScreen.kt
@@ -59,6 +59,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController
+import com.kyant.backdrop.backdrops.layerBackdrop
+import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.delay
@@ -95,19 +97,23 @@ fun TransparencySettingsScreen(navController: NavController) {
val activeTrackColor = if (isDarkTheme) Color(0xFF007AFF) else Color(0xFF3C6DF5)
val thumbColor = if (isDarkTheme) Color(0xFFFFFFFF) else Color(0xFFFFFFFF)
+ val backdrop = rememberLayerBackdrop()
+
StyledScaffold(
title = stringResource(R.string.customize_transparency_mode),
navigationButton = {
StyledIconButton(
onClick = { navController.popBackStack() },
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
}
){ spacerHeight, hazeState ->
Column(
modifier = Modifier
.hazeSource(hazeState)
+ .layerBackdrop(backdrop)
.fillMaxSize()
.verticalScroll(verticalScrollState)
.padding(horizontal = 16.dp),
@@ -154,19 +160,15 @@ fun TransparencySettingsScreen(navController: NavController) {
object : (ByteArray) -> Unit {
override fun invoke(value: ByteArray) {
val parsed = parseTransparencySettingsResponse(value)
- if (parsed != null) {
- enabled.value = parsed.enabled
- amplificationSliderValue.floatValue = parsed.netAmplification
- balanceSliderValue.floatValue = parsed.balance
- toneSliderValue.floatValue = parsed.leftTone
- ambientNoiseReductionSliderValue.floatValue =
- parsed.leftAmbientNoiseReduction
- conversationBoostEnabled.value = parsed.leftConversationBoost
- eq.value = parsed.leftEQ.copyOf()
- Log.d(TAG, "Updated transparency settings from notification")
- } else {
- Log.w(TAG, "Failed to parse transparency settings from notification")
- }
+ enabled.value = parsed.enabled
+ amplificationSliderValue.floatValue = parsed.netAmplification
+ balanceSliderValue.floatValue = parsed.balance
+ toneSliderValue.floatValue = parsed.leftTone
+ ambientNoiseReductionSliderValue.floatValue =
+ parsed.leftAmbientNoiseReduction
+ conversationBoostEnabled.value = parsed.leftConversationBoost
+ eq.value = parsed.leftEQ.copyOf()
+ Log.d(TAG, "Updated transparency settings from notification")
}
}
}
@@ -251,12 +253,7 @@ fun TransparencySettingsScreen(navController: NavController) {
try {
val data = attManager.read(ATTHandles.TRANSPARENCY)
parsedSettings = parseTransparencySettingsResponse(data = data)
- if (parsedSettings != null) {
- Log.d(TAG, "Parsed settings on attempt $attempt")
- break
- } else {
- Log.d(TAG, "Parsing returned null on attempt $attempt")
- }
+ Log.d(TAG, "Parsed settings on attempt $attempt")
} catch (e: Exception) {
Log.w(TAG, "Read attempt $attempt failed: ${e.message}")
}
@@ -297,7 +294,7 @@ fun TransparencySettingsScreen(navController: NavController) {
)
Spacer(modifier = Modifier.height(4.dp))
StyledSlider(
- label = stringResource(R.string.amplification).uppercase(),
+ label = stringResource(R.string.amplification),
valueRange = -1f..1f,
mutableFloatState = amplificationSliderValue,
onValueChange = {
@@ -309,20 +306,20 @@ fun TransparencySettingsScreen(navController: NavController) {
)
StyledSlider(
- label = stringResource(R.string.balance).uppercase(),
+ label = stringResource(R.string.balance),
valueRange = -1f..1f,
mutableFloatState = balanceSliderValue,
onValueChange = {
balanceSliderValue.floatValue = it
},
- snapPoints = listOf(0f),
+ snapPoints = listOf(-1f, 0f, 1f),
startLabel = stringResource(R.string.left),
endLabel = stringResource(R.string.right),
independent = true,
)
StyledSlider(
- label = stringResource(R.string.tone).uppercase(),
+ label = stringResource(R.string.tone),
valueRange = -1f..1f,
mutableFloatState = toneSliderValue,
onValueChange = {
@@ -334,7 +331,7 @@ fun TransparencySettingsScreen(navController: NavController) {
)
StyledSlider(
- label = stringResource(R.string.ambient_noise_reduction).uppercase(),
+ label = stringResource(R.string.ambient_noise_reduction),
valueRange = 0f..1f,
mutableFloatState = ambientNoiseReductionSliderValue,
onValueChange = {
@@ -356,20 +353,20 @@ fun TransparencySettingsScreen(navController: NavController) {
// Only show transparency mode EQ section if SDP offset is available
if (isSdpOffsetAvailable.value) {
Text(
- text = stringResource(R.string.equalizer).uppercase(),
+ text = stringResource(R.string.equalizer),
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
- modifier = Modifier.padding(8.dp, bottom = 2.dp)
+ modifier = Modifier.padding(16.dp, bottom = 4.dp)
)
Column(
modifier = Modifier
.fillMaxWidth()
- .background(backgroundColor, RoundedCornerShape(14.dp))
+ .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceBetween
diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/TroubleshootingScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/TroubleshootingScreen.kt
index 1124ad5..467367b 100644
--- a/android/app/src/main/java/me/kavishdevar/librepods/screens/TroubleshootingScreen.kt
+++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/TroubleshootingScreen.kt
@@ -85,6 +85,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.core.content.FileProvider
import androidx.navigation.NavController
+import com.kyant.backdrop.backdrops.layerBackdrop
+import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.Dispatchers
@@ -208,6 +210,8 @@ fun TroubleshootingScreen(navController: NavController) {
showBottomSheet = true
}
+ val backdrop = rememberLayerBackdrop()
+
Box(
modifier = Modifier.fillMaxSize()
) {
@@ -217,28 +221,30 @@ fun TroubleshootingScreen(navController: NavController) {
StyledIconButton(
onClick = { navController.popBackStack() },
icon = "",
- darkMode = isDarkTheme
+ darkMode = isDarkTheme,
+ backdrop = backdrop
)
}
){ spacerHeight, hazeState ->
Column(
modifier = Modifier
.fillMaxSize()
- .verticalScroll(scrollState)
+ .layerBackdrop(backdrop)
.hazeSource(state = hazeState)
+ .verticalScroll(scrollState)
.padding(horizontal = 16.dp)
) {
Spacer(modifier = Modifier.height(spacerHeight))
Text(
- text = stringResource(R.string.saved_logs).uppercase(),
+ text = stringResource(R.string.saved_logs),
style = TextStyle(
fontSize = 14.sp,
- fontWeight = FontWeight.Light,
+ fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
- modifier = Modifier.padding(8.dp, bottom = 2.dp, top = 8.dp)
+ modifier = Modifier.padding(16.dp, bottom = 4.dp, top = 8.dp)
)
Spacer(modifier = Modifier.height(2.dp))
@@ -249,7 +255,7 @@ fun TroubleshootingScreen(navController: NavController) {
.fillMaxWidth()
.background(
backgroundColor,
- RoundedCornerShape(14.dp)
+ RoundedCornerShape(28.dp)
)
.padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally
@@ -266,7 +272,7 @@ fun TroubleshootingScreen(navController: NavController) {
.fillMaxWidth()
.background(
backgroundColor,
- RoundedCornerShape(14.dp)
+ RoundedCornerShape(28.dp)
)
.padding(horizontal = 16.dp, vertical = 8.dp)
) {
@@ -372,14 +378,14 @@ fun TroubleshootingScreen(navController: NavController) {
Spacer(modifier = Modifier.height(16.dp))
Text(
- text = "TROUBLESHOOTING STEPS".uppercase(),
+ text = "TROUBLESHOOTING STEPS",
style = TextStyle(
fontSize = 14.sp,
fontWeight = FontWeight.Light,
color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
- modifier = Modifier.padding(8.dp, bottom = 2.dp, top = 8.dp)
+ modifier = Modifier.padding(16.dp, bottom = 2.dp, top = 8.dp)
)
Spacer(modifier = Modifier.height(2.dp))
@@ -389,7 +395,7 @@ fun TroubleshootingScreen(navController: NavController) {
.fillMaxWidth()
.background(
backgroundColor,
- RoundedCornerShape(14.dp)
+ RoundedCornerShape(28.dp)
)
.padding(16.dp)
) {
diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml
index 2c49987..31a83be 100644
--- a/android/app/src/main/res/values/strings.xml
+++ b/android/app/src/main/res/values/strings.xml
@@ -15,12 +15,13 @@
Case
Test
Name
- Noise Control
+ Listening Mode
Off
Transparency
Adaptive
Noise Cancellation
Press and Hold AirPods
+ Press and hold the stem to cycle between the selected listening modes.
Head Gestures
Left
Right
@@ -110,7 +111,7 @@
Press Speed
Adjust the speed required to press two or three times on your AirPods.
Press and Hold Duration
- Adjust the duration required to press and hold on your AirPods
+ Adjust the duration required to press and hold on your AirPods.
Volume Swipe Speed
To prevent unintended volume adjustments, select preferred wait time between swipes.
Equalizer
@@ -133,7 +134,7 @@
Ambient Noise Reduction
Conversation Boost
Conversation Boost focuses your AirPods Pro on the person talking in front of you, making it easier to hear in a face-to-face conversation.
- AirPods can use the results of a hearing test to make adjustments that improve the clarity of voices and sounds around you. \n\n Hearing Aid is only intended for people with perceived mild to moderate hearing loss.
+ AirPods can use the results of a hearing test to make adjustments that improve the clarity of voices and sounds around you.\n\nHearing Aid is only intended for people with perceived mild to moderate hearing loss.
Media Assist
AirPods Pro can use the results of a hearing test to make adjustments that improve the clarity of music, video, and calls.
Adjust Music and Video
@@ -174,4 +175,5 @@
Must be exactly 32 hex characters
Error converting hex:
Found offset please restart the Bluetooth process
+ Digital Assistant