android: liquidglass, maybe?

the switch and icon button took quite a while. i forgot the order of modifiers matters!
This commit is contained in:
Kavish Devar
2025-09-28 12:27:05 +05:30
parent 8dc7a97c43
commit 08738a1293
33 changed files with 1245 additions and 1992 deletions

Binary file not shown.

View File

@@ -51,22 +51,22 @@ fun AudioSettings(navController: NavController) {
val textColor = if (isDarkTheme) Color.White else Color.Black val textColor = if (isDarkTheme) Color.White else Color.Black
Text( Text(
text = stringResource(R.string.audio).uppercase(), text = stringResource(R.string.audio),
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f) 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) val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
Column( Column(
modifier = Modifier modifier = Modifier
.clip(RoundedCornerShape(14.dp)) .clip(RoundedCornerShape(28.dp))
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(top = 2.dp) .padding(top = 2.dp)
) { ) {
@@ -76,11 +76,12 @@ fun AudioSettings(navController: NavController) {
controlCommandIdentifier = AACPManager.Companion.ControlCommandIdentifiers.ADAPTIVE_VOLUME_CONFIG, controlCommandIdentifier = AACPManager.Companion.ControlCommandIdentifiers.ADAPTIVE_VOLUME_CONFIG,
independent = false independent = false
) )
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888), color = Color(0x40888888),
modifier = Modifier modifier = Modifier
.padding(start = 12.dp, end = 0.dp) .padding(horizontal= 12.dp)
) )
StyledToggle( StyledToggle(
@@ -90,10 +91,10 @@ fun AudioSettings(navController: NavController) {
independent = false independent = false
) )
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888), color = Color(0x40888888),
modifier = Modifier modifier = Modifier
.padding(start = 12.dp, end = 0.dp) .padding(horizontal= 12.dp)
) )
StyledToggle( StyledToggle(
@@ -103,10 +104,10 @@ fun AudioSettings(navController: NavController) {
independent = false independent = false
) )
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888), color = Color(0x40888888),
modifier = Modifier modifier = Modifier
.padding(start = 12.dp, end = 0.dp) .padding(horizontal= 12.dp)
) )
NavigationButton( NavigationButton(

View File

@@ -27,7 +27,9 @@ import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.height
import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -71,7 +73,6 @@ fun BatteryIndicator(
Column( Column(
modifier = Modifier modifier = Modifier
.padding(12.dp)
.background(backgroundColor), // just for haze to work .background(backgroundColor), // just for haze to work
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
@@ -85,7 +86,7 @@ fun BatteryIndicator(
color = batteryFillColor, color = batteryFillColor,
gapSize = 0.dp, gapSize = 0.dp,
strokeCap = StrokeCap.Round, strokeCap = StrokeCap.Round,
strokeWidth = 2.dp, strokeWidth = 4.dp,
trackColor = if (isDarkTheme) Color(0xFF0E0E0F) else Color(0xFFE3E3E8) trackColor = if (isDarkTheme) Color(0xFF0E0E0F) else Color(0xFFE3E3E8)
) )
@@ -101,6 +102,8 @@ fun BatteryIndicator(
) )
} }
Spacer(modifier = Modifier.height(4.dp))
Text( Text(
text = "$prefix $batteryPercentage%", text = "$prefix $batteryPercentage%",
color = batteryTextColor, color = batteryTextColor,

View File

@@ -146,7 +146,7 @@ fun BatteryView(service: AirPodsService, preview: Boolean = false) {
contentDescription = stringResource(R.string.buds), contentDescription = stringResource(R.string.buds),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(12.dp) .padding(8.dp)
) )
if ( if (
leftCharging == rightCharging && leftCharging == rightCharging &&
@@ -202,7 +202,7 @@ fun BatteryView(service: AirPodsService, preview: Boolean = false) {
contentDescription = stringResource(R.string.case_alt), contentDescription = stringResource(R.string.case_alt),
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(12.dp) .padding(8.dp)
) )
if (caseLevel > 0 || case?.status != BatteryStatus.DISCONNECTED) { if (caseLevel > 0 || case?.status != BatteryStatus.DISCONNECTED) {
BatteryIndicator( BatteryIndicator(

View File

@@ -32,12 +32,8 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape 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.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect 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.platform.LocalDensity
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@@ -76,19 +74,19 @@ fun CallControlSettings(hazeState: HazeState) {
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF) val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
Text( Text(
text = stringResource(R.string.call_controls).uppercase(), text = stringResource(R.string.call_controls),
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f) color = textColor.copy(alpha = 0.6f)
), ),
modifier = Modifier.padding(8.dp, bottom = 2.dp) modifier = Modifier.padding(16.dp, bottom = 4.dp)
) )
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(top = 2.dp) .padding(top = 2.dp)
) { ) {
val service = ServiceManager.getService()!! val service = ServiceManager.getService()!!
@@ -169,8 +167,8 @@ fun CallControlSettings(hazeState: HazeState) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(start = 12.dp, end = 12.dp) .padding(horizontal = 16.dp)
.height(50.dp), .height(58.dp),
horizontalArrangement = Arrangement.SpaceBetween, horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -187,17 +185,17 @@ fun CallControlSettings(hazeState: HazeState) {
) )
} }
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888), color = Color(0x40888888),
modifier = Modifier modifier = Modifier
.padding(start = 12.dp, end = 0.dp) .padding(horizontal = 12.dp)
) )
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(start = 12.dp, end = 12.dp) .padding(horizontal = 16.dp)
.height(50.dp) .height(58.dp)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures { offset -> detectTapGestures { offset ->
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
@@ -276,14 +274,21 @@ fun CallControlSettings(hazeState: HazeState) {
) { ) {
Text( Text(
text = singlePressAction, text = singlePressAction,
fontSize = 16.sp, style = TextStyle(
color = textColor.copy(alpha = 0.8f) fontSize = 16.sp,
color = textColor.copy(alpha = 0.8f),
fontFamily = FontFamily(Font(R.font.sf_pro))
)
) )
Icon( Text(
Icons.Default.KeyboardArrowDown, text = "􀆏",
contentDescription = null, style = TextStyle(
modifier = Modifier.size(18.dp), fontSize = 16.sp,
tint = textColor.copy(alpha = 0.6f) 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( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888), color = Color(0x40888888),
modifier = Modifier modifier = Modifier
.padding(start = 12.dp, end = 0.dp) .padding(horizontal = 12.dp)
) )
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(start = 12.dp, end = 12.dp) .padding(horizontal = 16.dp)
.height(50.dp) .height(58.dp)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures { offset -> detectTapGestures { offset ->
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
@@ -404,14 +409,21 @@ fun CallControlSettings(hazeState: HazeState) {
) { ) {
Text( Text(
text = doublePressAction, text = doublePressAction,
fontSize = 16.sp, style = TextStyle(
color = textColor.copy(alpha = 0.8f) fontSize = 16.sp,
color = textColor.copy(alpha = 0.8f),
fontFamily = FontFamily(Font(R.font.sf_pro))
)
) )
Icon( Text(
Icons.Default.KeyboardArrowDown, text = "􀆏",
contentDescription = null, style = TextStyle(
modifier = Modifier.size(18.dp), fontSize = 16.sp,
tint = textColor.copy(alpha = 0.6f) color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
modifier = Modifier
.padding(start = 6.dp)
) )
} }

View File

@@ -74,7 +74,6 @@ import com.kyant.backdrop.effects.blur
import com.kyant.backdrop.effects.colorControls import com.kyant.backdrop.effects.colorControls
import com.kyant.backdrop.effects.refraction import com.kyant.backdrop.effects.refraction
import com.kyant.backdrop.highlight.Highlight import com.kyant.backdrop.highlight.Highlight
import com.kyant.backdrop.highlight.HighlightStyle
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.kavishdevar.librepods.R import me.kavishdevar.librepods.R
import me.kavishdevar.librepods.utils.inspectDragGestures import me.kavishdevar.librepods.utils.inspectDragGestures
@@ -143,7 +142,9 @@ half4 main(float2 coord) {
.drawBackdrop( .drawBackdrop(
backdrop, backdrop,
{ RoundedCornerShape(48f.dp) }, { RoundedCornerShape(48f.dp) },
highlight = { Highlight { HighlightStyle.Solid } }, highlight = {
Highlight.SolidDefault
},
onDrawSurface = { drawRect(containerColor) }, onDrawSurface = { drawRect(containerColor) },
effects = { effects = {
colorControls( colorControls(
@@ -153,7 +154,7 @@ half4 main(float2 coord) {
blur(if (isLightTheme) 16f.dp.toPx() else 8f.dp.toPx()) blur(if (isLightTheme) 16f.dp.toPx() else 8f.dp.toPx())
refraction(24f.dp.toPx(), 48f.dp.toPx(), true) refraction(24f.dp.toPx(), 48f.dp.toPx(), true)
}, },
layer = { layerBlock = {
val width = size.width val width = size.width
val height = size.height val height = size.height
@@ -273,16 +274,6 @@ half4 main(float2 coord) {
horizontalArrangement = Arrangement.spacedBy(12.dp), horizontalArrangement = Arrangement.spacedBy(12.dp),
verticalAlignment = Alignment.CenterVertically 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( StyledButton(
onClick = onDismiss, onClick = onDismiss,
backdrop = backdrop, backdrop = backdrop,
@@ -295,16 +286,6 @@ half4 main(float2 coord) {
style = TextStyle(contentColor, 16.sp) 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( StyledButton(
onClick = onConfirm, onClick = onConfirm,
backdrop = backdrop, backdrop = backdrop,

View File

@@ -20,6 +20,7 @@
package me.kavishdevar.librepods.composables package me.kavishdevar.librepods.composables
import android.content.Context.MODE_PRIVATE
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Column 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.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import 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.R
import me.kavishdevar.librepods.utils.AACPManager
import kotlin.io.encoding.ExperimentalEncodingApi
@Composable @Composable
fun ConnectionSettings() { fun ConnectionSettings() {
@@ -48,7 +47,7 @@ fun ConnectionSettings() {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(top = 2.dp) .padding(top = 2.dp)
) { ) {
StyledToggle( StyledToggle(
@@ -59,10 +58,10 @@ fun ConnectionSettings() {
independent = false independent = false
) )
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888), color = Color(0x40888888),
modifier = Modifier modifier = Modifier
.padding(start = 12.dp, end = 0.dp) .padding(horizontal= 12.dp)
) )
StyledToggle( StyledToggle(

View File

@@ -32,11 +32,7 @@ import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape 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.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect 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.layout.positionInParent
import androidx.compose.ui.platform.LocalDensity import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.res.stringResource 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.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
@@ -75,7 +74,7 @@ fun MicrophoneSettings(hazeState: HazeState) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(top = 2.dp) .padding(top = 2.dp)
) { ) {
val service = ServiceManager.getService()!! val service = ServiceManager.getService()!!
@@ -141,8 +140,8 @@ fun MicrophoneSettings(hazeState: HazeState) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(start = 12.dp, end = 12.dp) .padding(horizontal = 16.dp)
.height(55.dp) .height(58.dp)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures { offset -> detectTapGestures { offset ->
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
@@ -214,8 +213,11 @@ fun MicrophoneSettings(hazeState: HazeState) {
) { ) {
Text( Text(
text = stringResource(R.string.microphone_mode), text = stringResource(R.string.microphone_mode),
fontSize = 16.sp, style = TextStyle(
color = textColor, fontSize = 16.sp,
color = textColor,
fontFamily = FontFamily(Font(R.font.sf_pro))
),
modifier = Modifier.padding(bottom = 4.dp) modifier = Modifier.padding(bottom = 4.dp)
) )
Box( Box(
@@ -228,14 +230,21 @@ fun MicrophoneSettings(hazeState: HazeState) {
) { ) {
Text( Text(
text = selectedMode, text = selectedMode,
fontSize = 16.sp, style = TextStyle(
color = textColor.copy(alpha = 0.8f) fontSize = 16.sp,
color = textColor.copy(alpha = 0.8f),
fontFamily = FontFamily(Font(R.font.sf_pro))
)
) )
Icon( Text(
Icons.Default.KeyboardArrowDown, text = "􀆏",
contentDescription = null, style = TextStyle(
modifier = Modifier.size(16.dp), fontSize = 16.sp,
tint = textColor.copy(alpha = 0.6f) color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro))
),
modifier = Modifier
.padding(start = 6.dp)
) )
} }

View File

@@ -1,154 +0,0 @@
/*
* LibrePods - AirPods liberated from Apples 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 <https://www.gnu.org/licenses/>.
*/
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())
}

View File

@@ -1,17 +1,17 @@
/* /*
* LibrePods - AirPods liberated from Apples ecosystem * LibrePods - AirPods liberated from Apples ecosystem
* *
* Copyright (C) 2025 LibrePods contributors * Copyright (C) 2025 LibrePods contributors
* *
* This program is free software: you can redistribute it and/or modify * 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 * it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License. * by the Free Software Foundation, either version 3 of the License.
* *
* This program is distributed in the hope that it will be useful, * This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of * but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details. * GNU Affero General Public License for more details.
* *
* You should have received a copy of the GNU Affero General Public License * You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>. * along with this program. If not, see <https://www.gnu.org/licenses/>.
*/ */
@@ -23,75 +23,105 @@ import androidx.compose.animation.core.tween
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape 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.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext 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.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import androidx.navigation.NavController
import me.kavishdevar.librepods.R
@Composable @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() val isDarkTheme = isSystemInDarkTheme()
var backgroundColor by remember { mutableStateOf(if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) } var backgroundColor by remember { mutableStateOf(if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
val animatedBackgroundColor by animateColorAsState(targetValue = backgroundColor, animationSpec = tween(durationMillis = 500)) val animatedBackgroundColor by animateColorAsState(targetValue = backgroundColor, animationSpec = tween(durationMillis = 500))
Column {
Row( Row(
modifier = Modifier modifier = Modifier
.background(animatedBackgroundColor, RoundedCornerShape(if (independent) 14.dp else 0.dp)) .background(animatedBackgroundColor, RoundedCornerShape(if (independent) 28.dp else 0.dp))
.height(55.dp) .height(58.dp)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures( detectTapGestures(
onPress = { onPress = {
backgroundColor = if (isDarkTheme) Color(0x40888888) else Color(0x40D9D9D9) backgroundColor = if (isDarkTheme) Color(0x40888888) else Color(0x40D9D9D9)
tryAwaitRelease() tryAwaitRelease()
backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF) backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
}, },
onTap = { onTap = {
if (onClick != null) onClick() else navController.navigate(to) 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( text = "􀯻",
text = name, style = TextStyle(
modifier = Modifier.padding(16.dp), fontSize = 16.sp,
color = if (isDarkTheme) Color.White else Color.Black fontFamily = FontFamily(Font(R.font.sf_pro)),
) color = if (isDarkTheme) Color.White.copy(alpha = 0.6f) else Color.Black.copy(alpha = 0.6f)
Spacer(modifier = Modifier.weight(1f)) ),
IconButton( modifier = Modifier
onClick = { if (onClick != null) onClick() else navController.navigate(to) }, .padding(start = if (currentState != null) 6.dp else 0.dp)
colors = IconButtonDefaults.iconButtonColors( )
containerColor = Color.Transparent, }
contentColor = if (isDarkTheme) Color.White else Color.Black if (description != null) {
), Text(
modifier = Modifier text = description,
.padding(start = 16.dp) style = TextStyle(
.fillMaxHeight() fontSize = 12.sp,
) { fontWeight = FontWeight.Light,
@Suppress("DEPRECATION") color = if (isDarkTheme) Color.White.copy(alpha = 0.6f) else Color.Black.copy(alpha = 0.6f),
Icon( fontFamily = FontFamily(Font(R.font.sf_pro))
imageVector = Icons.Default.KeyboardArrowRight, ),
contentDescription = name modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp)
) )
} }
} }
@@ -101,4 +131,4 @@ fun NavigationButton(to: String, name: String, navController: NavController, onC
@Composable @Composable
fun NavigationButtonPreview() { fun NavigationButtonPreview() {
NavigationButton("to", "Name", NavController(LocalContext.current)) NavigationButton("to", "Name", NavController(LocalContext.current))
} }

View File

@@ -181,10 +181,10 @@ fun NoiseControlSettings(
} }
Text( Text(
text = stringResource(R.string.noise_control).uppercase(), text = stringResource(R.string.noise_control),
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f), color = textColor.copy(alpha = 0.6f),
), ),
modifier = Modifier.padding(8.dp, bottom = 2.dp) modifier = Modifier.padding(8.dp, bottom = 2.dp)
@@ -241,7 +241,7 @@ fun NoiseControlSettings(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(60.dp) .height(60.dp)
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(28.dp))
) { ) {
Row( Row(
modifier = Modifier.fillMaxWidth() modifier = Modifier.fillMaxWidth()
@@ -334,7 +334,7 @@ fun NoiseControlSettings(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.padding(3.dp) .padding(3.dp)
.background(selectedBackground, RoundedCornerShape(12.dp)) .background(selectedBackground, RoundedCornerShape(26.dp))
) )
} }
@@ -400,7 +400,6 @@ fun NoiseControlSettings(
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 4.dp)
.padding(top = 4.dp) .padding(top = 4.dp)
) { ) {
if (offListeningMode.value) { if (offListeningMode.value) {
@@ -408,7 +407,6 @@ fun NoiseControlSettings(
text = stringResource(R.string.off), text = stringResource(R.string.off),
style = TextStyle(fontSize = 12.sp, color = textColor), style = TextStyle(fontSize = 12.sp, color = textColor),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
} }
@@ -416,21 +414,18 @@ fun NoiseControlSettings(
text = stringResource(R.string.transparency), text = stringResource(R.string.transparency),
style = TextStyle(fontSize = 12.sp, color = textColor), style = TextStyle(fontSize = 12.sp, color = textColor),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
Text( Text(
text = stringResource(R.string.adaptive), text = stringResource(R.string.adaptive),
style = TextStyle(fontSize = 12.sp, color = textColor), style = TextStyle(fontSize = 12.sp, color = textColor),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
Text( Text(
text = stringResource(R.string.noise_cancellation), text = stringResource(R.string.noise_cancellation),
style = TextStyle(fontSize = 12.sp, color = textColor), style = TextStyle(fontSize = 12.sp, color = textColor),
textAlign = TextAlign.Center, textAlign = TextAlign.Center,
fontWeight = FontWeight.Bold,
modifier = Modifier.weight(1f) modifier = Modifier.weight(1f)
) )
} }

View File

@@ -19,34 +19,21 @@
package me.kavishdevar.librepods.composables package me.kavishdevar.librepods.composables
import android.content.Context import android.content.Context
import androidx.compose.animation.animateColorAsState import android.content.res.Configuration
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures
import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape 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.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.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.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
@@ -65,12 +52,6 @@ fun PressAndHoldSettings(navController: NavController) {
val isDarkTheme = isSystemInDarkTheme() val isDarkTheme = isSystemInDarkTheme()
val textColor = if (isDarkTheme) Color.White else Color.Black val textColor = if (isDarkTheme) Color.White else Color.Black
val dividerColor = Color(0x40888888) 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<Color>(durationMillis = 500)
val animatedLeftBackgroundColor by animateColorAsState(targetValue = leftBackgroundColor, animationSpec = animationSpec)
val animatedRightBackgroundColor by animateColorAsState(targetValue = rightBackgroundColor, animationSpec = animationSpec)
val context = LocalContext.current val context = LocalContext.current
val sharedPreferences = context.getSharedPreferences("settings", Context.MODE_PRIVATE) val sharedPreferences = context.getSharedPreferences("settings", Context.MODE_PRIVATE)
@@ -91,14 +72,14 @@ fun PressAndHoldSettings(navController: NavController) {
} }
Text( Text(
text = stringResource(R.string.press_and_hold_airpods).uppercase(), text = stringResource(R.string.press_and_hold_airpods),
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f), color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro)) 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)) Spacer(modifier = Modifier.height(1.dp))
@@ -106,126 +87,33 @@ fun PressAndHoldSettings(navController: NavController) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .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( NavigationButton(
modifier = Modifier to = "long_press/Left",
.fillMaxWidth() name = stringResource(R.string.left),
.height(50.dp) navController = navController,
.background(animatedLeftBackgroundColor, RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp)) independent = false,
.pointerInput(Unit) { currentState = leftActionText,
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
)
}
}
}
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = dividerColor, color = dividerColor,
modifier = Modifier 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 @Composable
fun PressAndHoldSettingsPreview() { fun PressAndHoldSettingsPreview() {
PressAndHoldSettings(navController = NavController(LocalContext.current)) PressAndHoldSettings(navController = NavController(LocalContext.current))

View File

@@ -74,7 +74,8 @@ fun StyledButton(
isInteractive: Boolean = true, isInteractive: Boolean = true,
tint: Color = Color.Unspecified, tint: Color = Color.Unspecified,
surfaceColor: Color = Color.Unspecified, surfaceColor: Color = Color.Unspecified,
content: @Composable RowScope.() -> Unit maxScale: Float = 0.1f,
content: @Composable RowScope.() -> Unit,
) { ) {
val animationScope = rememberCoroutineScope() val animationScope = rememberCoroutineScope()
val progressAnimation = remember { Animatable(0f) } val progressAnimation = remember { Animatable(0f) }
@@ -113,7 +114,7 @@ half4 main(float2 coord) {
effects = { effects = {
blur(16f.dp.toPx()) blur(16f.dp.toPx())
}, },
layer = null, layerBlock = null,
onDrawSurface = { onDrawSurface = {
if (tint.isSpecified) { if (tint.isSpecified) {
drawRect(tint, blendMode = BlendMode.Hue) drawRect(tint, blendMode = BlendMode.Hue)
@@ -147,12 +148,11 @@ half4 main(float2 coord) {
blur(2f.dp.toPx()) blur(2f.dp.toPx())
refraction(12f.dp.toPx(), 24f.dp.toPx()) refraction(12f.dp.toPx(), 24f.dp.toPx())
}, },
layer = { layerBlock = {
val width = size.width val width = size.width
val height = size.height val height = size.height
val progress = progressAnimation.value val progress = progressAnimation.value
val maxScale = 0.1f
val scale = lerp(1f, 1f + maxScale, progress) val scale = lerp(1f, 1f + maxScale, progress)
val maxOffset = size.minDimension val maxOffset = size.minDimension

View File

@@ -230,7 +230,7 @@ fun StyledDropdown(
if (index != options.lastIndex) { if (index != options.lastIndex) {
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888), color = Color(0x40888888),
modifier = Modifier.padding(start = 12.dp, end = 0.dp) modifier = Modifier.padding(start = 12.dp, end = 0.dp)
) )

View File

@@ -24,6 +24,7 @@ import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.VectorConverter import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.VisibilityThreshold import androidx.compose.animation.core.VisibilityThreshold
import androidx.compose.animation.core.spring import androidx.compose.animation.core.spring
import androidx.compose.foundation.isSystemInDarkTheme
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape 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.fastCoerceAtMost
import androidx.compose.ui.util.fastCoerceIn import androidx.compose.ui.util.fastCoerceIn
import androidx.compose.ui.util.lerp import androidx.compose.ui.util.lerp
import com.kyant.backdrop.backdrops.LayerBackdrop
import com.kyant.backdrop.backdrops.rememberLayerBackdrop import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import com.kyant.backdrop.drawBackdrop import com.kyant.backdrop.drawBackdrop
import com.kyant.backdrop.effects.blur
import com.kyant.backdrop.effects.refractionWithDispersion import com.kyant.backdrop.effects.refractionWithDispersion
import com.kyant.backdrop.highlight.Highlight import com.kyant.backdrop.highlight.Highlight
import com.kyant.backdrop.shadow.Shadow import com.kyant.backdrop.shadow.Shadow
@@ -79,6 +82,8 @@ fun StyledIconButton(
icon: String, icon: String,
darkMode: Boolean, darkMode: Boolean,
tint: Color = Color.Unspecified, tint: Color = Color.Unspecified,
backdrop: LayerBackdrop = rememberLayerBackdrop(),
modifier: Modifier = Modifier,
) { ) {
val animationScope = rememberCoroutineScope() val animationScope = rememberCoroutineScope()
val progressAnimationSpec = spring(0.5f, 300f, 0.001f) val progressAnimationSpec = spring(0.5f, 300f, 0.001f)
@@ -110,26 +115,23 @@ half4 main(float2 coord) {
null null
} }
} }
val isDarkTheme = isSystemInDarkTheme()
TextButton( TextButton(
onClick = onClick, onClick = onClick,
shape = RoundedCornerShape(56.dp), shape = RoundedCornerShape(56.dp),
modifier = Modifier modifier = modifier
.padding(horizontal = 12.dp) .padding(horizontal = 12.dp)
.drawBackdrop( .drawBackdrop(
backdrop = rememberLayerBackdrop(), backdrop = backdrop,
shape = { RoundedCornerShape(56.dp) }, shape = { RoundedCornerShape(56.dp) },
highlight = { highlight = { Highlight.AmbientDefault.copy(alpha = if (isDarkTheme) 1f else 0f) },
val progress = progressAnimation.value
Highlight.AmbientDefault.copy(alpha = progress.coerceIn(0.45f, 1f))
},
shadow = { shadow = {
Shadow( Shadow(
radius = 4f.dp, radius = 48f.dp,
color = Color.Black.copy(0.08f) color = Color.Black.copy(if (isDarkTheme) 0.08f else 0.4f)
) )
}, },
layer = { layerBlock = {
val width = size.width val width = size.width
val height = size.height val height = size.height
@@ -182,7 +184,7 @@ half4 main(float2 coord) {
drawLayer(innerShadowLayer) drawLayer(innerShadowLayer)
drawRect( 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 = { onDrawFront = {
@@ -218,6 +220,7 @@ half4 main(float2 coord) {
}, },
effects = { effects = {
refractionWithDispersion(6f.dp.toPx(), size.height / 2f) refractionWithDispersion(6f.dp.toPx(), size.height / 2f)
blur(24f, TileMode.Decal)
}, },
) )
.pointerInput(animationScope) { .pointerInput(animationScope) {

View File

@@ -31,12 +31,14 @@ import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@@ -84,6 +86,7 @@ import com.kyant.backdrop.highlight.Highlight
import com.kyant.backdrop.shadow.Shadow import com.kyant.backdrop.shadow.Shadow
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.kavishdevar.librepods.R import me.kavishdevar.librepods.R
import kotlin.math.abs
import kotlin.math.roundToInt import kotlin.math.roundToInt
@Composable @Composable
@@ -136,23 +139,26 @@ fun StyledSlider(
val content = @Composable { val content = @Composable {
Box( Box(
Modifier.fillMaxWidth(if (startIcon == null && endIcon == null) 0.95f else 1f) Modifier
) { .fillMaxWidth(if (startIcon == null && endIcon == null) 0.95f else 1f)
) {
Box( Box(
Modifier Modifier
.padding(vertical = 4.dp)
.layerBackdrop(sliderBackdrop) .layerBackdrop(sliderBackdrop)
.fillMaxWidth()) { .fillMaxWidth()
) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth(1f) .fillMaxWidth(1f)
.padding(vertical = 12.dp), .padding(vertical = 12.dp),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(12.dp)
) { ) {
if (startLabel != null || endLabel != null) { if (startLabel != null || endLabel != null) {
Row( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth(), .fillMaxWidth()
.padding(horizontal = 8.dp),
horizontalArrangement = Arrangement.SpaceBetween horizontalArrangement = Arrangement.SpaceBetween
) { ) {
Text( Text(
@@ -174,80 +180,119 @@ fun StyledSlider(
) )
) )
} }
Spacer(modifier = Modifier.height(12.dp))
} }
Column(
Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(vertical = 4.dp) .padding(vertical = 4.dp)
.then(if (startIcon == null && endIcon == null) Modifier.padding(horizontal = 12.dp) else Modifier), .then(if (startIcon == null && endIcon == null) Modifier.padding(horizontal = 8.dp) else Modifier),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(0.dp)
) { ) {
if (startIcon != null) { Row(
Text( verticalAlignment = Alignment.CenterVertically,
text = startIcon, horizontalArrangement = Arrangement.spacedBy(0.dp)
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
}
) { ) {
Box( if (startIcon != null) {
Modifier Text(
.clip(RoundedCornerShape(28.dp)) text = startIcon,
.background(trackColor) style = TextStyle(
.height(6f.dp) fontSize = 18.sp,
.fillMaxWidth() fontWeight = FontWeight.Normal,
) color = accentColor,
fontFamily = FontFamily(Font(R.font.sf_pro))
Box( ),
Modifier modifier = Modifier
.clip(RoundedCornerShape(28.dp)) .padding(horizontal = 12.dp)
.background(accentColor) .onGloballyPositioned {
.height(6f.dp) startIconWidthState.floatValue = it.size.width.toFloat()
.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)
} }
} )
) }
} Box(
if (endIcon != null) { Modifier
Text( .weight(1f)
text = endIcon, .onSizeChanged { trackWidthState.floatValue = it.width.toFloat() }
style = TextStyle(
fontSize = 18.sp,
fontWeight = FontWeight.Normal,
color = accentColor,
fontFamily = FontFamily(Font(R.font.sf_pro))
),
modifier = Modifier
.padding(horizontal = 12.dp)
.onGloballyPositioned { .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 Modifier
.graphicsLayer { .graphicsLayer {
val startOffset = 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 = translationX =
startOffset + fraction * trackWidthState.floatValue - size.width / 2f 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( .draggable(
rememberDraggableState { delta -> rememberDraggableState { delta ->
@@ -305,7 +350,7 @@ fun StyledSlider(
color = Color.Black.copy(0.05f) color = Color.Black.copy(0.05f)
) )
}, },
layer = { layerBlock = {
val progress = progressAnimation.value val progress = progressAnimation.value
val scale = lerp(1f, 1.5f, progress) val scale = lerp(1f, 1.5f, progress)
scaleX = scale scaleX = scale
@@ -361,20 +406,20 @@ fun StyledSlider(
text = label, text = label,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = labelTextColor.copy(alpha = 0.6f), color = labelTextColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro)) fontFamily = FontFamily(Font(R.font.sf_pro))
), ),
modifier = Modifier.padding(8.dp) modifier = Modifier.padding(horizontal = 18.dp, vertical = 4.dp)
) )
} }
Box( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(horizontal = 8.dp, vertical = 0.dp) .padding(horizontal = 8.dp, vertical = 0.dp)
.heightIn(min = 55.dp), .heightIn(min = 58.dp),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
content() content()
@@ -390,7 +435,7 @@ fun StyledSlider(
fontFamily = FontFamily(Font(R.font.sf_pro)) fontFamily = FontFamily(Font(R.font.sf_pro))
), ),
modifier = Modifier 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<Float>, threshold: Float = 0.05f): Float { private fun snapIfClose(value: Float, points: List<Float>, threshold: Float = 0.05f): Float {
val nearest = points.minByOrNull { kotlin.math.abs(it - value) } ?: value val nearest = points.minByOrNull { abs(it - value) } ?: value
return if (kotlin.math.abs(nearest - value) <= threshold) nearest else value return if (abs(nearest - value) <= threshold) nearest else value
} }
@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Preview(uiMode = Configuration.UI_MODE_NIGHT_YES)
@@ -426,9 +471,11 @@ fun StyledSliderPreview() {
a.floatValue = it a.floatValue = it
}, },
valueRange = 0f..2f, valueRange = 0f..2f,
snapPoints = listOf(0f, 0.5f, 1f, 1.5f, 2f),
snapThreshold = 0.1f,
independent = true, independent = true,
startLabel = "A", startLabel = "A",
endLabel = "B" endLabel = "B",
) )
} }
} }

View File

@@ -48,8 +48,11 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.BlendMode import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.BlurEffect import androidx.compose.ui.graphics.BlurEffect
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Paint
import androidx.compose.ui.graphics.TileMode import androidx.compose.ui.graphics.TileMode
import androidx.compose.ui.graphics.drawOutline 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.drawscope.translate
import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.graphics.layer.CompositingStrategy 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.effects.refractionWithDispersion
import com.kyant.backdrop.highlight.Highlight import com.kyant.backdrop.highlight.Highlight
import com.kyant.backdrop.shadow.Shadow import com.kyant.backdrop.shadow.Shadow
import kotlinx.coroutines.delay import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@Composable @Composable
@@ -76,16 +79,17 @@ fun StyledSwitch(
checked: Boolean, checked: Boolean,
onCheckedChange: (Boolean) -> Unit, onCheckedChange: (Boolean) -> Unit,
enabled: Boolean = true, enabled: Boolean = true,
indpendent: Boolean = true,
) { ) {
val isDarkTheme = isSystemInDarkTheme() val isDarkTheme = isSystemInDarkTheme()
val onColor = if (enabled) Color(0xFF34C759) else if (isDarkTheme) Color(0xFF5B5B5E) else Color(0xFFD1D1D6) 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 offColor = if (enabled) if (isDarkTheme) Color(0xFF5B5B5E) else Color(0xFFD1D1D6) else if (isDarkTheme) Color(0xFF5B5B5E) else Color(0xFFD1D1D6)
val trackWidth = 70.dp val trackWidth = 64.dp
val trackHeight = 31.dp val trackHeight = 28.dp
val thumbHeight = 27.dp val thumbHeight = 24.dp
val thumbWidth = 36.dp val thumbWidth = 39.dp
val backdrop = rememberLayerBackdrop() val backdrop = rememberLayerBackdrop()
val switchBackdrop = rememberLayerBackdrop() val switchBackdrop = rememberLayerBackdrop()
@@ -97,18 +101,23 @@ fun StyledSwitch(
val density = LocalDensity.current val density = LocalDensity.current
val animationScope = rememberCoroutineScope() val animationScope = rememberCoroutineScope()
val progressAnimationSpec = spring(0.5f, 300f, 0.001f) val progressAnimationSpec = spring(0.5f, 300f, 0.001f)
val colorAnimationSpec = tween<Color>(300, easing = FastOutSlowInEasing) val colorAnimationSpec = tween<Color>(200, easing = FastOutSlowInEasing)
val progressAnimation = remember { Animatable(0f) } val progressAnimation = remember { Animatable(0f) }
val innerShadowLayer = rememberGraphicsLayer().apply { val innerShadowLayer = rememberGraphicsLayer().apply {
compositingStrategy = CompositingStrategy.Offscreen compositingStrategy = CompositingStrategy.Offscreen
} }
val animatedTrackColor = remember { Animatable(if (checked) onColor else offColor) } val animatedTrackColor = remember { Animatable(if (checked) onColor else offColor) }
LaunchedEffect(checked) { LaunchedEffect(checked) {
val targetColor = if (checked) onColor else offColor coroutineScope {
animatedTrackColor.animateTo(targetColor, colorAnimationSpec) launch {
val targetFrac = if (checked) 1f else 0f val targetColor = if (checked) onColor else offColor
animatedFraction.animateTo(targetFrac, progressAnimationSpec) animatedTrackColor.animateTo(targetColor, colorAnimationSpec)
}
launch {
val targetFrac = if (checked) 1f else 0f
animatedFraction.animateTo(targetFrac, progressAnimationSpec)
}
}
} }
Box( Box(
@@ -136,7 +145,7 @@ fun StyledSwitch(
.then(if (enabled) Modifier.draggable( .then(if (enabled) Modifier.draggable(
rememberDraggableState { delta -> rememberDraggableState { delta ->
if (trackWidthPx.floatValue > 0f) { 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 { animationScope.launch {
animatedFraction.snapTo(newFraction) animatedFraction.snapTo(newFraction)
} }
@@ -155,10 +164,12 @@ fun StyledSwitch(
}, },
onDragStopped = { onDragStopped = {
animationScope.launch { animationScope.launch {
progressAnimation.animateTo(0f, progressAnimationSpec)
val snappedFraction = if (animatedFraction.value >= 0.5f) 1f else 0f val snappedFraction = if (animatedFraction.value >= 0.5f) 1f else 0f
animatedFraction.animateTo(snappedFraction, progressAnimationSpec)
onCheckedChange(snappedFraction >= 0.5f) onCheckedChange(snappedFraction >= 0.5f)
coroutineScope {
launch { progressAnimation.animateTo(0f, progressAnimationSpec) }
launch { animatedFraction.animateTo(snappedFraction, progressAnimationSpec) }
}
} }
} }
) else Modifier) ) else Modifier)
@@ -175,12 +186,27 @@ fun StyledSwitch(
color = Color.Black.copy(0.05f) color = Color.Black.copy(0.05f)
) )
}, },
layer = { layerBlock = {
val progress = progressAnimation.value val progress = progressAnimation.value
val scale = lerp(1f, 2f, progress) val scale = lerp(1f, 1.6f, progress)
scaleX = scale scaleX = scale
scaleY = 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 = { onDrawSurface = {
val progress = progressAnimation.value.fastCoerceIn(0f, 1f) val progress = progressAnimation.value.fastCoerceIn(0f, 1f)
@@ -224,12 +250,12 @@ fun StyledSwitch(
@Composable @Composable
fun StyledSwitchPreview() { fun StyledSwitchPreview() {
val isDarkTheme = isSystemInDarkTheme() val isDarkTheme = isSystemInDarkTheme()
val backgroundColor = if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7) val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFF2F2F7)
Box( Box(
modifier = Modifier modifier = Modifier
.background(backgroundColor) .background(backgroundColor)
.width(100.dp) .width(100.dp)
.height(100.dp), .height(400.dp),
contentAlignment = Alignment.Center contentAlignment = Alignment.Center
) { ) {
val checked = remember { mutableStateOf(true) } val checked = remember { mutableStateOf(true) }
@@ -238,13 +264,14 @@ fun StyledSwitchPreview() {
onCheckedChange = { onCheckedChange = {
checked.value = it checked.value = it
}, },
enabled = true enabled = true,
indpendent = false
) )
LaunchedEffect(Unit) { // LaunchedEffect(Unit) {
delay(1000) // delay(1000)
checked.value = false // checked.value = false
delay(1000) // delay(1000)
checked.value = true // checked.value = true
} // }
} }
} }

View File

@@ -75,6 +75,7 @@ fun StyledToggle(
sharedPreferenceKey: String? = null, sharedPreferenceKey: String? = null,
sharedPreferences: SharedPreferences? = null, sharedPreferences: SharedPreferences? = null,
independent: Boolean = true, independent: Boolean = true,
enabled: Boolean = true,
onCheckedChange: ((Boolean) -> Unit)? = null, onCheckedChange: ((Boolean) -> Unit)? = null,
) { ) {
val isDarkTheme = isSystemInDarkTheme() val isDarkTheme = isSystemInDarkTheme()
@@ -82,7 +83,9 @@ fun StyledToggle(
var checked by checkedState var checked by checkedState
var backgroundColor by remember { mutableStateOf(if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) } var backgroundColor by remember { mutableStateOf(if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
val animatedBackgroundColor by animateColorAsState(targetValue = backgroundColor, animationSpec = tween(durationMillis = 500)) val animatedBackgroundColor by animateColorAsState(targetValue = backgroundColor, animationSpec = tween(durationMillis = 500))
if (sharedPreferenceKey != null && sharedPreferences != null) {
checked = sharedPreferences.getBoolean(sharedPreferenceKey, checked)
}
fun cb() { fun cb() {
if (sharedPreferences != null) { if (sharedPreferences != null) {
if (sharedPreferenceKey == null) { if (sharedPreferenceKey == null) {
@@ -101,15 +104,16 @@ fun StyledToggle(
text = title, text = title,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f) 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( Box(
modifier = Modifier modifier = Modifier
.background(animatedBackgroundColor, RoundedCornerShape(14.dp)) .background(animatedBackgroundColor, RoundedCornerShape(28.dp))
.padding(4.dp)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures( detectTapGestures(
onPress = { onPress = {
@@ -120,8 +124,10 @@ fun StyledToggle(
if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF) if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
}, },
onTap = { onTap = {
checked = !checked if (enabled) {
cb() checked = !checked
cb()
}
} }
) )
} }
@@ -145,10 +151,14 @@ fun StyledToggle(
) )
StyledSwitch( StyledSwitch(
checked = checked, checked = checked,
enabled = enabled,
onCheckedChange = { onCheckedChange = {
checked = it if (enabled) {
cb() checked = it
} cb()
}
},
indpendent = true
) )
} }
} }
@@ -156,7 +166,7 @@ fun StyledToggle(
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Box( Box(
modifier = Modifier modifier = Modifier
.padding(horizontal = 8.dp) .padding(horizontal = 16.dp)
.background(if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7)) .background(if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7))
) { ) {
Text( Text(
@@ -177,10 +187,10 @@ fun StyledToggle(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background( .background(
shape = RoundedCornerShape(14.dp), shape = RoundedCornerShape(28.dp),
color = if (isPressed.value) Color(0xFFE0E0E0) else Color.Transparent color = if (isPressed.value) Color(0xFFE0E0E0) else Color.Transparent
) )
.padding(horizontal = 12.dp, vertical = 12.dp) .padding(16.dp)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures( detectTapGestures(
onPress = { onPress = {
@@ -194,8 +204,10 @@ fun StyledToggle(
indication = null, indication = null,
interactionSource = remember { MutableInteractionSource() } interactionSource = remember { MutableInteractionSource() }
) { ) {
checked = !checked if (enabled) {
cb() checked = !checked
cb()
}
}, },
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -206,25 +218,35 @@ fun StyledToggle(
) { ) {
Text( Text(
text = label, text = label,
fontSize = 16.sp, style = TextStyle(
color = textColor fontSize = 16.sp,
fontFamily = FontFamily(Font(R.font.sf_pro)),
fontWeight = FontWeight.Normal,
color = textColor
)
) )
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
if (description != null) { if (description != null) {
Text( Text(
text = description, text = description,
fontSize = 12.sp, style = TextStyle(
color = textColor.copy(0.6f), fontSize = 12.sp,
lineHeight = 14.sp, color = textColor.copy(0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro)),
)
) )
} }
} }
StyledSwitch( StyledSwitch(
checked = checked, checked = checked,
enabled = enabled,
onCheckedChange = { onCheckedChange = {
checked = it if (enabled) {
cb() checked = it
} cb()
}
},
indpendent = false
) )
} }
} }
@@ -237,6 +259,7 @@ fun StyledToggle(
description: String? = null, description: String? = null,
controlCommandIdentifier: AACPManager.Companion.ControlCommandIdentifiers, controlCommandIdentifier: AACPManager.Companion.ControlCommandIdentifiers,
independent: Boolean = true, independent: Boolean = true,
enabled: Boolean = true,
sharedPreferenceKey: String? = null, sharedPreferenceKey: String? = null,
sharedPreferences: SharedPreferences? = null, sharedPreferences: SharedPreferences? = null,
onCheckedChange: ((Boolean) -> Unit)? = null, onCheckedChange: ((Boolean) -> Unit)? = null,
@@ -291,15 +314,16 @@ fun StyledToggle(
text = title, text = title,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f) 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( Box(
modifier = Modifier modifier = Modifier
.background(animatedBackgroundColor, RoundedCornerShape(14.dp)) .background(animatedBackgroundColor, RoundedCornerShape(28.dp))
.padding(4.dp)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures( detectTapGestures(
onPress = { onPress = {
@@ -310,8 +334,10 @@ fun StyledToggle(
if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF) if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
}, },
onTap = { onTap = {
checked = !checked if (enabled) {
cb() checked = !checked
cb()
}
} }
) )
} }
@@ -335,10 +361,14 @@ fun StyledToggle(
) )
StyledSwitch( StyledSwitch(
checked = checked, checked = checked,
enabled = enabled,
onCheckedChange = { onCheckedChange = {
checked = it if (enabled) {
cb() checked = it
} cb()
}
},
indpendent = true
) )
} }
} }
@@ -346,7 +376,7 @@ fun StyledToggle(
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Box( Box(
modifier = Modifier modifier = Modifier
.padding(horizontal = 8.dp) .padding(horizontal = 16.dp)
.background(if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7)) .background(if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7))
) { ) {
Text( Text(
@@ -367,10 +397,10 @@ fun StyledToggle(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background( .background(
shape = RoundedCornerShape(14.dp), shape = RoundedCornerShape(28.dp),
color = if (isPressed.value) Color(0xFFE0E0E0) else Color.Transparent color = if (isPressed.value) Color(0xFFE0E0E0) else Color.Transparent
) )
.padding(horizontal = 12.dp, vertical = 12.dp) .padding(16.dp)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures( detectTapGestures(
onPress = { onPress = {
@@ -384,8 +414,10 @@ fun StyledToggle(
indication = null, indication = null,
interactionSource = remember { MutableInteractionSource() } interactionSource = remember { MutableInteractionSource() }
) { ) {
checked = !checked if (enabled) {
cb() checked = !checked
cb()
}
}, },
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -396,25 +428,35 @@ fun StyledToggle(
) { ) {
Text( Text(
text = label, text = label,
fontSize = 16.sp, style = TextStyle(
color = textColor fontSize = 16.sp,
fontFamily = FontFamily(Font(R.font.sf_pro)),
fontWeight = FontWeight.Normal,
color = textColor
)
) )
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
if (description != null) { if (description != null) {
Text( Text(
text = description, text = description,
fontSize = 12.sp, style = TextStyle(
color = textColor.copy(0.6f), fontSize = 12.sp,
lineHeight = 14.sp, color = textColor.copy(0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro)),
)
) )
} }
} }
StyledSwitch( StyledSwitch(
checked = checked, checked = checked,
enabled = enabled,
onCheckedChange = { onCheckedChange = {
checked = it if (enabled) {
cb() checked = it
} cb()
}
},
indpendent = false
) )
} }
} }
@@ -427,6 +469,7 @@ fun StyledToggle(
description: String? = null, description: String? = null,
attHandle: ATTHandles, attHandle: ATTHandles,
independent: Boolean = true, independent: Boolean = true,
enabled: Boolean = true,
sharedPreferenceKey: String? = null, sharedPreferenceKey: String? = null,
sharedPreferences: SharedPreferences? = null, sharedPreferences: SharedPreferences? = null,
onCheckedChange: ((Boolean) -> Unit)? = null, onCheckedChange: ((Boolean) -> Unit)? = null,
@@ -509,15 +552,16 @@ fun StyledToggle(
text = title, text = title,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f) 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( Box(
modifier = Modifier modifier = Modifier
.background(animatedBackgroundColor, RoundedCornerShape(14.dp)) .background(animatedBackgroundColor, RoundedCornerShape(28.dp))
.padding(4.dp)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures( detectTapGestures(
onPress = { onPress = {
@@ -528,8 +572,10 @@ fun StyledToggle(
if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF) if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
}, },
onTap = { onTap = {
checked = !checked if (enabled) {
cb() checked = !checked
cb()
}
} }
) )
} }
@@ -553,10 +599,14 @@ fun StyledToggle(
) )
StyledSwitch( StyledSwitch(
checked = checked, checked = checked,
enabled = enabled,
onCheckedChange = { onCheckedChange = {
checked = it if (enabled) {
cb() checked = it
} cb()
}
},
indpendent = true
) )
} }
} }
@@ -564,7 +614,7 @@ fun StyledToggle(
Spacer(modifier = Modifier.height(8.dp)) Spacer(modifier = Modifier.height(8.dp))
Box( Box(
modifier = Modifier modifier = Modifier
.padding(horizontal = 8.dp) .padding(horizontal = 16.dp)
.background(if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7)) .background(if (isDarkTheme) Color(0xFF000000) else Color(0xFFF2F2F7))
) { ) {
Text( Text(
@@ -585,10 +635,10 @@ fun StyledToggle(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background( .background(
shape = RoundedCornerShape(14.dp), shape = RoundedCornerShape(28.dp),
color = if (isPressed.value) Color(0xFFE0E0E0) else Color.Transparent color = if (isPressed.value) Color(0xFFE0E0E0) else Color.Transparent
) )
.padding(horizontal = 12.dp, vertical = 12.dp) .padding(16.dp)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures( detectTapGestures(
onPress = { onPress = {
@@ -602,8 +652,10 @@ fun StyledToggle(
indication = null, indication = null,
interactionSource = remember { MutableInteractionSource() } interactionSource = remember { MutableInteractionSource() }
) { ) {
checked = !checked if (enabled) {
cb() checked = !checked
cb()
}
}, },
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
@@ -629,10 +681,14 @@ fun StyledToggle(
} }
StyledSwitch( StyledSwitch(
checked = checked, checked = checked,
enabled = enabled,
onCheckedChange = { onCheckedChange = {
checked = it if (enabled) {
cb() checked = it
} cb()
}
},
indpendent = false
) )
} }
} }

View File

@@ -40,20 +40,16 @@ import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll 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.Checkbox
import androidx.compose.material3.CheckboxDefaults import androidx.compose.material3.CheckboxDefaults
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.Slider import androidx.compose.material3.Slider
import androidx.compose.material3.SliderDefaults import androidx.compose.material3.SliderDefaults
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableLongStateOf 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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavController 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.HazeState
import dev.chrisbanes.haze.hazeSource import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
@@ -149,13 +147,16 @@ fun AccessibilitySettingsScreen(navController: NavController) {
} }
} }
val backdrop = rememberLayerBackdrop()
StyledScaffold( StyledScaffold(
title = stringResource(R.string.accessibility), title = stringResource(R.string.accessibility),
navigationButton = { navigationButton = {
StyledIconButton( StyledIconButton(
onClick = { navController.popBackStack() }, onClick = { navController.popBackStack() },
icon = "􀯶", icon = "􀯶",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
}, },
) { spacerHeight, hazeState -> ) { spacerHeight, hazeState ->
@@ -163,6 +164,7 @@ fun AccessibilitySettingsScreen(navController: NavController) {
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.hazeSource(hazeState) .hazeSource(hazeState)
.layerBackdrop(backdrop)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(16.dp)
@@ -370,7 +372,7 @@ fun AccessibilitySettingsScreen(navController: NavController) {
) )
StyledToggle( StyledToggle(
title = stringResource(R.string.noise_control).uppercase(), title = stringResource(R.string.noise_control),
label = stringResource(R.string.noise_cancellation_single_airpod), label = stringResource(R.string.noise_cancellation_single_airpod),
description = stringResource(R.string.noise_cancellation_single_airpod_description), description = stringResource(R.string.noise_cancellation_single_airpod_description),
controlCommandIdentifier = AACPManager.Companion.ControlCommandIdentifiers.ONE_BUD_ANC_MODE, controlCommandIdentifier = AACPManager.Companion.ControlCommandIdentifiers.ONE_BUD_ANC_MODE,
@@ -392,7 +394,7 @@ fun AccessibilitySettingsScreen(navController: NavController) {
} }
StyledSlider( StyledSlider(
label = stringResource(R.string.tone_volume).uppercase(), label = stringResource(R.string.tone_volume),
description = stringResource(R.string.tone_volume_description), description = stringResource(R.string.tone_volume_description),
mutableFloatState = toneVolumeValue, mutableFloatState = toneVolumeValue,
onValueChange = { onValueChange = {
@@ -405,6 +407,12 @@ fun AccessibilitySettingsScreen(navController: NavController) {
independent = true independent = true
) )
StyledToggle(
label = stringResource(R.string.volume_control),
description = stringResource(R.string.volume_control_description),
controlCommandIdentifier = AACPManager.Companion.ControlCommandIdentifiers.VOLUME_SWIPE_MODE,
)
DropdownMenuComponent( DropdownMenuComponent(
label = stringResource(R.string.volume_swipe_speed), label = stringResource(R.string.volume_swipe_speed),
description = stringResource(R.string.volume_swipe_speed_description), description = stringResource(R.string.volume_swipe_speed_description),
@@ -425,10 +433,10 @@ fun AccessibilitySettingsScreen(navController: NavController) {
if (!hearingAidEnabled.value&& isSdpOffsetAvailable.value) { if (!hearingAidEnabled.value&& isSdpOffsetAvailable.value) {
Text( Text(
text = stringResource(R.string.apply_eq_to).uppercase(), text = stringResource(R.string.apply_eq_to),
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f), color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro)) fontFamily = FontFamily(Font(R.font.sf_pro))
), ),
@@ -437,12 +445,12 @@ fun AccessibilitySettingsScreen(navController: NavController) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(vertical = 0.dp) .padding(vertical = 0.dp)
) { ) {
val darkModeLocal = isSystemInDarkTheme() 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 { var phoneBackgroundColor by remember {
mutableStateOf( mutableStateOf(
if (darkModeLocal) Color( if (darkModeLocal) Color(
@@ -500,11 +508,11 @@ fun AccessibilitySettingsScreen(navController: NavController) {
} }
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888) 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 { var mediaBackgroundColor by remember {
mutableStateOf( mutableStateOf(
if (darkModeLocal) Color( if (darkModeLocal) Color(
@@ -565,7 +573,7 @@ fun AccessibilitySettingsScreen(navController: NavController) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(12.dp), .padding(12.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
@@ -686,15 +694,18 @@ private fun DropdownMenuComponent(
) )
.background( .background(
if (independent) (if (isSystemInDarkTheme()) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) else Color.Transparent, 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( Row(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(start = 12.dp, end = 12.dp) .padding(start = 12.dp, end = 12.dp)
.height(55.dp) .height(58.dp)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures { offset -> detectTapGestures { offset ->
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
@@ -766,7 +777,7 @@ private fun DropdownMenuComponent(
color = textColor.copy(alpha = 0.6f), color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro)) 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(
text = selectedOption, text = selectedOption,
fontSize = 16.sp, style = TextStyle(
color = textColor.copy(alpha = 0.8f) fontSize = 16.sp,
color = textColor.copy(alpha = 0.8f),
fontFamily = FontFamily(Font(R.font.sf_pro))
)
) )
Icon( Text(
Icons.Default.KeyboardArrowDown, text = "􀆏",
contentDescription = null, style = TextStyle(
modifier = Modifier.size(18.dp), fontSize = 16.sp,
tint = textColor.copy(alpha = 0.6f) 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( Box(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.padding(horizontal = 8.dp) .padding(horizontal = 16.dp)
.background(if (isSystemInDarkTheme()) Color(0xFF000000) else Color(0xFFF2F2F7)) .background(if (isSystemInDarkTheme()) Color(0xFF000000) else Color(0xFFF2F2F7))
){ ){
Text( Text(

View File

@@ -36,6 +36,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavController import androidx.navigation.NavController
import com.kyant.backdrop.backdrops.layerBackdrop
import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -94,6 +96,7 @@ fun AdaptiveStrengthScreen(navController: NavController) {
} }
} }
val backdrop = rememberLayerBackdrop()
StyledScaffold( StyledScaffold(
title = stringResource(R.string.customize_adaptive_audio), title = stringResource(R.string.customize_adaptive_audio),
@@ -101,19 +104,21 @@ fun AdaptiveStrengthScreen(navController: NavController) {
StyledIconButton( StyledIconButton(
onClick = { navController.popBackStack() }, onClick = { navController.popBackStack() },
icon = "􀯶", icon = "􀯶",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
} }
) { spacerHeight -> ) { spacerHeight ->
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.layerBackdrop(backdrop)
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(16.dp)
) { ) {
Spacer(modifier = Modifier.height(spacerHeight)) Spacer(modifier = Modifier.height(spacerHeight))
StyledSlider( StyledSlider(
label = stringResource(R.string.customize_adaptive_audio).uppercase(), label = stringResource(R.string.customize_adaptive_audio),
mutableFloatState = sliderValue, mutableFloatState = sliderValue,
onValueChange = { onValueChange = {
sliderValue.floatValue = it sliderValue.floatValue = it

View File

@@ -68,6 +68,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavController import androidx.navigation.NavController
import androidx.navigation.compose.rememberNavController import androidx.navigation.compose.rememberNavController
import com.kyant.backdrop.backdrops.layerBackdrop
import com.kyant.backdrop.backdrops.rememberLayerBackdrop import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import com.kyant.backdrop.drawBackdrop import com.kyant.backdrop.drawBackdrop
import com.kyant.backdrop.highlight.Highlight 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.CallControlSettings
import me.kavishdevar.librepods.composables.ConnectionSettings import me.kavishdevar.librepods.composables.ConnectionSettings
import me.kavishdevar.librepods.composables.MicrophoneSettings import me.kavishdevar.librepods.composables.MicrophoneSettings
import me.kavishdevar.librepods.composables.NameField
import me.kavishdevar.librepods.composables.NavigationButton import me.kavishdevar.librepods.composables.NavigationButton
import me.kavishdevar.librepods.composables.NoiseControlSettings import me.kavishdevar.librepods.composables.NoiseControlSettings
import me.kavishdevar.librepods.composables.PressAndHoldSettings import me.kavishdevar.librepods.composables.PressAndHoldSettings
@@ -199,13 +199,15 @@ fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
} }
} }
val darkMode = isSystemInDarkTheme() val darkMode = isSystemInDarkTheme()
val backdrop = rememberLayerBackdrop()
StyledScaffold( StyledScaffold(
title = deviceName.text, title = deviceName.text,
actionButtons = listOf { actionButtons = listOf {
StyledIconButton( StyledIconButton(
onClick = { navController.navigate("app_settings") }, onClick = { navController.navigate("app_settings") },
icon = "􀍟", icon = "􀍟",
darkMode = darkMode darkMode = darkMode,
backdrop = backdrop
) )
}, },
snackbarHostState = snackbarHostState snackbarHostState = snackbarHostState
@@ -216,6 +218,7 @@ fun AirPodsSettingsScreen(dev: BluetoothDevice?, service: AirPodsService,
.fillMaxSize() .fillMaxSize()
.hazeSource(hazeState) .hazeSource(hazeState)
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
.layerBackdrop(backdrop)
.verticalScroll(rememberScrollState()) .verticalScroll(rememberScrollState())
) { ) {
Spacer(modifier = Modifier.height(spacerHeight)) 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 // Only show name field when not in BLE-only mode
if (!bleOnlyMode) { if (!bleOnlyMode) {
NameField( NavigationButton(
to = "rename",
name = stringResource(R.string.name), name = stringResource(R.string.name),
value = deviceName.text, currentState = deviceName.text,
navController = navController navController = navController,
independent = true
) )
}
if (!bleOnlyMode) {
Spacer(modifier = Modifier.height(32.dp)) Spacer(modifier = Modifier.height(32.dp))
NavigationButton(to = "hearing_aid", stringResource(R.string.hearing_aid), navController) NavigationButton(to = "hearing_aid", stringResource(R.string.hearing_aid), navController)
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
NoiseControlSettings(service = service) NoiseControlSettings(service = service)
Spacer(modifier = Modifier.height(16.dp))
PressAndHoldSettings(navController = navController)
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
CallControlSettings(hazeState = hazeState) 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 // 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)) Spacer(modifier = Modifier.height(16.dp))
AudioSettings(navController = navController) AudioSettings(navController = navController)

View File

@@ -40,14 +40,11 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.navigationBarsPadding
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.rememberLazyListState import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowLeft
import androidx.compose.material.icons.automirrored.filled.KeyboardArrowRight
import androidx.compose.material.icons.filled.Send import androidx.compose.material.icons.filled.Send
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults 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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavController 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.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@@ -325,14 +324,15 @@ fun DebugScreen(navController: NavController) {
} }
val isDarkTheme = isSystemInDarkTheme() val isDarkTheme = isSystemInDarkTheme()
val backdrop = rememberLayerBackdrop()
StyledScaffold( StyledScaffold(
title = "Debug", title = "Debug",
navigationButton = { navigationButton = {
StyledIconButton( StyledIconButton(
onClick = { navController.popBackStack() }, onClick = { navController.popBackStack() },
icon = "􀯶", icon = "􀯶",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
}, },
actionButtons = listOf( actionButtons = listOf(
@@ -344,6 +344,7 @@ fun DebugScreen(navController: NavController) {
}, },
icon = "􀈑", icon = "􀈑",
darkMode = isDarkTheme, darkMode = isDarkTheme,
backdrop = backdrop
) )
} }
), ),
@@ -353,6 +354,7 @@ fun DebugScreen(navController: NavController) {
.fillMaxSize() .fillMaxSize()
.hazeSource(hazeState) .hazeSource(hazeState)
.navigationBarsPadding() .navigationBarsPadding()
.layerBackdrop(backdrop)
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
) { ) {
Spacer(modifier = Modifier.height(spacerHeight)) Spacer(modifier = Modifier.height(spacerHeight))
@@ -391,11 +393,13 @@ fun DebugScreen(navController: NavController) {
) )
) { ) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Icon( Text(
imageVector = if (isSent) Icons.AutoMirrored.Filled.KeyboardArrowLeft else Icons.AutoMirrored.Filled.KeyboardArrowRight, text = if (isSent) "􀆉" else "􀆊",
contentDescription = null, style = TextStyle(
tint = if (isSent) Color.Green else Color.Red, fontSize = 16.sp,
modifier = Modifier.size(24.dp) fontFamily = FontFamily(Font(R.font.sf_pro)),
color = if (isSent) Color(0xFF4CD964) else Color(0xFFFF3B30)
),
) )
Spacer(modifier = Modifier.width(4.dp)) Spacer(modifier = Modifier.width(4.dp))
Column { Column {

View File

@@ -42,10 +42,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Card import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api 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.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavController 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.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.kavishdevar.librepods.R import me.kavishdevar.librepods.R
import me.kavishdevar.librepods.composables.StyledButton
import me.kavishdevar.librepods.composables.StyledIconButton import me.kavishdevar.librepods.composables.StyledIconButton
import me.kavishdevar.librepods.composables.StyledScaffold import me.kavishdevar.librepods.composables.StyledScaffold
import me.kavishdevar.librepods.composables.StyledToggle import me.kavishdevar.librepods.composables.StyledToggle
@@ -116,18 +116,19 @@ fun HeadTrackingScreen(navController: NavController) {
} }
} }
val isDarkTheme = isSystemInDarkTheme() 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 textColor = if (isDarkTheme) Color.White else Color.Black
val scrollState = rememberScrollState() val scrollState = rememberScrollState()
val backdrop = rememberLayerBackdrop()
StyledScaffold ( StyledScaffold (
title = stringResource(R.string.head_tracking), title = stringResource(R.string.head_tracking),
navigationButton = { navigationButton = {
StyledIconButton( StyledIconButton(
onClick = { navController.popBackStack() }, onClick = { navController.popBackStack() },
icon = "􀯶", icon = "􀯶",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
}, },
actionButtons = listOf( actionButtons = listOf(
@@ -144,72 +145,95 @@ fun HeadTrackingScreen(navController: NavController) {
} }
}, },
icon = if (isActive) "􀊅" else "􀊃", icon = if (isActive) "􀊅" else "􀊃",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
} }
), ),
) { spacerHeight, hazeState -> ) { 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 modifier = Modifier
.fillMaxSize() .layerBackdrop(backdrop)
.padding(top = 8.dp) .fillMaxWidth(),
.padding(horizontal = 16.dp) horizontalAlignment = Alignment.CenterHorizontally
.verticalScroll(scrollState)
.hazeSource(state = hazeState)
) { ) {
Spacer(modifier = Modifier.height(spacerHeight)) Column (
val sharedPreferences = modifier = Modifier
LocalContext.current.getSharedPreferences("settings", Context.MODE_PRIVATE) .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("") } Spacer(modifier = Modifier.height(2.dp))
val coroutineScope = rememberCoroutineScope() 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( Spacer(modifier = Modifier.height(16.dp))
label = "Head Gestures", Text(
sharedPreferences = sharedPreferences, "Head Orientation",
sharedPreferenceKey = "head_gestures", style = TextStyle(
) fontSize = 18.sp,
fontWeight = FontWeight.Medium,
Spacer(modifier = Modifier.height(2.dp)) fontFamily = FontFamily(Font(R.font.sf_pro)),
Text( color = textColor
stringResource(R.string.head_gestures_details), ),
style = TextStyle( modifier = Modifier.padding(start = 4.dp, bottom = 8.dp, top = 8.dp)
fontSize = 14.sp, )
fontWeight = FontWeight.Normal, HeadVisualization()
fontFamily = FontFamily(Font(R.font.sf_pro)),
color = textColor.copy(0.6f)
),
modifier = Modifier.padding(start = 4.dp)
)
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Text( Text(
"Head Orientation", "Velocity",
style = TextStyle( style = TextStyle(
fontSize = 18.sp, fontSize = 18.sp,
fontWeight = FontWeight.Medium, fontWeight = FontWeight.Medium,
fontFamily = FontFamily(Font(R.font.sf_pro)), fontFamily = FontFamily(Font(R.font.sf_pro)),
color = textColor color = textColor
), ),
modifier = Modifier.padding(start = 4.dp, bottom = 8.dp, top = 8.dp) modifier = Modifier.padding(start = 4.dp, bottom = 8.dp, top = 8.dp)
) )
HeadVisualization() AccelerationPlot()
Spacer(modifier = Modifier.height(16.dp)) 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)) LaunchedEffect(gestureText) {
Button ( if (gestureText.isNotEmpty()) {
lastClickTime = System.currentTimeMillis()
delay(3000)
if (System.currentTimeMillis() - lastClickTime >= 3000) {
shouldExplode = true
}
}
}
}
StyledButton(
onClick = { onClick = {
gestureText = "Shake your head or nod!" gestureText = "Shake your head or nod!"
coroutineScope.launch { coroutineScope.launch {
@@ -217,13 +241,9 @@ fun HeadTrackingScreen(navController: NavController) {
gestureText = if (accepted) "\"Yes\" gesture detected." else "\"No\" gesture detected." gestureText = if (accepted) "\"Yes\" gesture detected." else "\"No\" gesture detected."
} }
}, },
modifier = Modifier backdrop = backdrop,
.fillMaxWidth() modifier = Modifier.fillMaxWidth(0.75f),
.height(55.dp), maxScale = 0.05f
colors = ButtonDefaults.buttonColors(
containerColor = backgroundColor
),
shape = RoundedCornerShape(8.dp)
) { ) {
Text( Text(
"Test Head Gestures", "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( Box(
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
modifier = Modifier.padding(top = 12.dp, bottom = 24.dp) modifier = Modifier.padding(top = 12.dp, bottom = 24.dp)

View File

@@ -41,6 +41,8 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.navigation.NavController 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.HazeState
import dev.chrisbanes.haze.hazeSource import dev.chrisbanes.haze.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi 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 attManager = ServiceManager.getService()?.attManager ?: throw IllegalStateException("ATTManager not available")
val aacpManager = remember { ServiceManager.getService()?.aacpManager } val aacpManager = remember { ServiceManager.getService()?.aacpManager }
val backdrop = rememberLayerBackdrop()
StyledScaffold( StyledScaffold(
title = stringResource(R.string.adjustments), title = stringResource(R.string.adjustments),
navigationButton = { navigationButton = {
StyledIconButton( StyledIconButton(
onClick = { navController.popBackStack() }, onClick = { navController.popBackStack() },
icon = "􀯶", icon = "􀯶",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
} }
) { spacerHeight -> ) { spacerHeight ->
@@ -92,6 +95,7 @@ fun HearingAidAdjustmentsScreen(@Suppress("unused") navController: NavController
modifier = Modifier modifier = Modifier
.hazeSource(hazeState) .hazeSource(hazeState)
.fillMaxSize() .fillMaxSize()
.layerBackdrop(backdrop)
.verticalScroll(verticalScrollState) .verticalScroll(verticalScrollState)
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(16.dp)
@@ -282,7 +286,7 @@ fun HearingAidAdjustmentsScreen(@Suppress("unused") navController: NavController
} }
StyledSlider( StyledSlider(
label = stringResource(R.string.amplification).uppercase(), label = stringResource(R.string.amplification),
valueRange = -1f..1f, valueRange = -1f..1f,
mutableFloatState = amplificationSliderValue, mutableFloatState = amplificationSliderValue,
onValueChange = { onValueChange = {
@@ -301,20 +305,20 @@ fun HearingAidAdjustmentsScreen(@Suppress("unused") navController: NavController
) )
StyledSlider( StyledSlider(
label = stringResource(R.string.balance).uppercase(), label = stringResource(R.string.balance),
valueRange = -1f..1f, valueRange = -1f..1f,
mutableFloatState = balanceSliderValue, mutableFloatState = balanceSliderValue,
onValueChange = { onValueChange = {
balanceSliderValue.floatValue = it balanceSliderValue.floatValue = it
}, },
snapPoints = listOf(0f), snapPoints = listOf(-1f, 0f, 1f),
startLabel = stringResource(R.string.left), startLabel = stringResource(R.string.left),
endLabel = stringResource(R.string.right), endLabel = stringResource(R.string.right),
independent = true, independent = true,
) )
StyledSlider( StyledSlider(
label = stringResource(R.string.tone).uppercase(), label = stringResource(R.string.tone),
valueRange = -1f..1f, valueRange = -1f..1f,
mutableFloatState = toneSliderValue, mutableFloatState = toneSliderValue,
onValueChange = { onValueChange = {
@@ -326,7 +330,7 @@ fun HearingAidAdjustmentsScreen(@Suppress("unused") navController: NavController
) )
StyledSlider( StyledSlider(
label = stringResource(R.string.ambient_noise_reduction).uppercase(), label = stringResource(R.string.ambient_noise_reduction),
valueRange = 0f..1f, valueRange = 0f..1f,
mutableFloatState = ambientNoiseReductionSliderValue, mutableFloatState = ambientNoiseReductionSliderValue,
onValueChange = { onValueChange = {

View File

@@ -20,15 +20,10 @@ package me.kavishdevar.librepods.screens
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.util.Log import android.util.Log
import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background 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.isSystemInDarkTheme
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth 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.rememberScrollState
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.verticalScroll 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.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon
import androidx.compose.material3.SnackbarHostState import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.Font
@@ -74,9 +62,9 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import me.kavishdevar.librepods.R import me.kavishdevar.librepods.R
import me.kavishdevar.librepods.composables.ConfirmationDialog import me.kavishdevar.librepods.composables.ConfirmationDialog
import me.kavishdevar.librepods.composables.NavigationButton
import me.kavishdevar.librepods.composables.StyledIconButton import me.kavishdevar.librepods.composables.StyledIconButton
import me.kavishdevar.librepods.composables.StyledScaffold import me.kavishdevar.librepods.composables.StyledScaffold
import me.kavishdevar.librepods.composables.StyledSwitch
import me.kavishdevar.librepods.composables.StyledToggle import me.kavishdevar.librepods.composables.StyledToggle
import me.kavishdevar.librepods.services.ServiceManager import me.kavishdevar.librepods.services.ServiceManager
import me.kavishdevar.librepods.utils.AACPManager import me.kavishdevar.librepods.utils.AACPManager
@@ -117,7 +105,8 @@ fun HearingAidScreen(navController: NavController) {
StyledIconButton( StyledIconButton(
onClick = { navController.popBackStack() }, onClick = { navController.popBackStack() },
icon = "􀯶", icon = "􀯶",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
}, },
actionButtons = emptyList(), actionButtons = emptyList(),
@@ -129,7 +118,7 @@ fun HearingAidScreen(navController: NavController) {
.hazeSource(hazeState) .hazeSource(hazeState)
.fillMaxSize() .fillMaxSize()
.verticalScroll(verticalScrollState) .verticalScroll(verticalScrollState)
.padding(16.dp), .padding(horizontal = 16.dp),
verticalArrangement = Arrangement.spacedBy(8.dp) verticalArrangement = Arrangement.spacedBy(8.dp)
) { ) {
Spacer(modifier = Modifier.height(spacerHeight)) Spacer(modifier = Modifier.height(spacerHeight))
@@ -175,22 +164,22 @@ fun HearingAidScreen(navController: NavController) {
} }
fun onAdjustPhoneChange(value: Boolean) { fun onAdjustPhoneChange(value: Boolean) {
adjustPhoneEnabled.value = value // TODO
} }
fun onAdjustMediaChange(value: Boolean) { fun onAdjustMediaChange(value: Boolean) {
adjustMediaEnabled.value = value // TODO
} }
Text( Text(
text = stringResource(R.string.hearing_aid).uppercase(), text = stringResource(R.string.hearing_aid),
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f), color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro)) 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) val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
@@ -198,9 +187,9 @@ fun HearingAidScreen(navController: NavController) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(28.dp))
.clip( .clip(
RoundedCornerShape(14.dp) RoundedCornerShape(28.dp)
) )
) { ) {
StyledToggle( StyledToggle(
@@ -209,31 +198,17 @@ fun HearingAidScreen(navController: NavController) {
independent = false independent = false
) )
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888), color = Color(0x40888888),
modifier = Modifier 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(
text = stringResource(R.string.hearing_aid_description), 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), color = (if (isSystemInDarkTheme()) Color.White else Color.Black).copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro)) 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)) Spacer(modifier = Modifier.height(16.dp))
StyledToggle( StyledToggle(
title = stringResource(R.string.media_assist).uppercase(), title = stringResource(R.string.media_assist),
label = stringResource(R.string.media_assist), label = stringResource(R.string.media_assist),
checkedState = mediaAssistEnabled, checkedState = mediaAssistEnabled,
independent = true, independent = true,
@@ -260,99 +235,27 @@ fun HearingAidScreen(navController: NavController) {
Column ( Column (
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(28.dp))
) { ) {
val isDarkThemeLocal = isSystemInDarkTheme() StyledToggle(
var backgroundColorAdjustMedia by remember { mutableStateOf(if (isDarkThemeLocal) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) } label = stringResource(R.string.adjust_media),
val animatedBackgroundColorAdjustMedia by animateColorAsState(targetValue = backgroundColorAdjustMedia, animationSpec = tween(durationMillis = 500)) checkedState = adjustMediaEnabled,
Row( onCheckedChange = { onAdjustMediaChange(it) },
modifier = Modifier independent = false
.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)
},
)
}
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888), color = Color(0x40888888),
modifier = Modifier 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)) } StyledToggle(
val animatedBackgroundColorAdjustPhone by animateColorAsState(targetValue = backgroundColorAdjustPhone, animationSpec = tween(durationMillis = 500)) label = stringResource(R.string.adjust_calls),
Row( checkedState = adjustPhoneEnabled,
modifier = Modifier onCheckedChange = { onAdjustPhoneChange(it) },
.fillMaxWidth() independent = false
.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)
},
)
}
} }
} }
} }

View File

@@ -73,6 +73,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.content.edit import androidx.core.content.edit
import androidx.navigation.NavController import androidx.navigation.NavController
import com.kyant.backdrop.backdrops.layerBackdrop
import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@@ -151,6 +153,7 @@ fun Onboarding(navController: NavController, activityContext: Context) {
isComplete = true isComplete = true
} }
} }
val backdrop = rememberLayerBackdrop()
StyledScaffold( StyledScaffold(
title = "Setting Up", title = "Setting Up",
actionButtons = listOf( actionButtons = listOf(
@@ -160,7 +163,8 @@ fun Onboarding(navController: NavController, activityContext: Context) {
showSkipDialog = true showSkipDialog = true
}, },
icon = "􀊋", icon = "􀊋",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
} }
) )
@@ -168,6 +172,7 @@ fun Onboarding(navController: NavController, activityContext: Context) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.layerBackdrop(backdrop)
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.spacedBy(16.dp) verticalArrangement = Arrangement.spacedBy(16.dp)

View File

@@ -23,6 +23,7 @@ package me.kavishdevar.librepods.screens
import android.content.Context import android.content.Context
import android.util.Log import android.util.Log
import androidx.compose.animation.animateColorAsState import androidx.compose.animation.animateColorAsState
import androidx.compose.animation.core.animateFloatAsState
import androidx.compose.animation.core.tween import androidx.compose.animation.core.tween
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures 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.padding
import androidx.compose.foundation.layout.wrapContentWidth import androidx.compose.foundation.layout.wrapContentWidth
import androidx.compose.foundation.shape.RoundedCornerShape 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.ExperimentalMaterial3Api
import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Icon import androidx.compose.material3.Icon
@@ -50,11 +49,11 @@ import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.scale
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
@@ -63,6 +62,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.content.edit import androidx.core.content.edit
import androidx.navigation.NavController import androidx.navigation.NavController
import com.kyant.backdrop.backdrops.layerBackdrop
import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import me.kavishdevar.librepods.R import me.kavishdevar.librepods.R
import me.kavishdevar.librepods.composables.StyledIconButton import me.kavishdevar.librepods.composables.StyledIconButton
@@ -76,20 +77,20 @@ import kotlin.io.encoding.ExperimentalEncodingApi
@Composable @Composable
fun RightDivider() { fun RightDivider() {
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888), color = Color(0x40888888),
modifier = Modifier modifier = Modifier
.padding(start = 72.dp) .padding(start = 72.dp, end = 20.dp)
) )
} }
@Composable @Composable
fun RightDividerNoIcon() { fun RightDividerNoIcon() {
HorizontalDivider( HorizontalDivider(
thickness = 1.5.dp, thickness = 1.dp,
color = Color(0x40888888), color = Color(0x40888888),
modifier = Modifier 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) val longPressActionPref = sharedPreferences.getString(prefKey, StemAction.CYCLE_NOISE_CONTROL_MODES.name)
Log.d("PressAndHoldSettingsScreen", "Long press action preference ($prefKey): $longPressActionPref") Log.d("PressAndHoldSettingsScreen", "Long press action preference ($prefKey): $longPressActionPref")
var longPressAction by remember { mutableStateOf(StemAction.valueOf(longPressActionPref ?: StemAction.CYCLE_NOISE_CONTROL_MODES.name)) } var longPressAction by remember { mutableStateOf(StemAction.valueOf(longPressActionPref ?: StemAction.CYCLE_NOISE_CONTROL_MODES.name)) }
val backdrop = rememberLayerBackdrop()
StyledScaffold( StyledScaffold(
title = name, title = name,
navigationButton = { navigationButton = {
StyledIconButton( StyledIconButton(
onClick = { navController.popBackStack() }, onClick = { navController.popBackStack() },
icon = "􀯶", icon = "􀯶",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
} }
) { spacerHeight -> ) { spacerHeight ->
val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF) val backgroundColor = if (isDarkTheme) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)
Column ( Column (
modifier = Modifier modifier = Modifier
.layerBackdrop(backdrop)
.fillMaxSize() .fillMaxSize()
.padding(top = 8.dp) .padding(top = 8.dp)
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
@@ -138,11 +142,11 @@ fun LongPress(navController: NavController, name: String) {
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)), .background(backgroundColor, RoundedCornerShape(28.dp)),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
LongPressActionElement( LongPressActionElement(
name = "Noise Control", name = stringResource(R.string.noise_control),
selected = longPressAction == StemAction.CYCLE_NOISE_CONTROL_MODES, selected = longPressAction == StemAction.CYCLE_NOISE_CONTROL_MODES,
onClick = { onClick = {
longPressAction = StemAction.CYCLE_NOISE_CONTROL_MODES longPressAction = StemAction.CYCLE_NOISE_CONTROL_MODES
@@ -153,7 +157,7 @@ fun LongPress(navController: NavController, name: String) {
) )
RightDividerNoIcon() RightDividerNoIcon()
LongPressActionElement( LongPressActionElement(
name = "Digital Assistant", name = stringResource(R.string.digital_assistant),
selected = longPressAction == StemAction.DIGITAL_ASSISTANT, selected = longPressAction == StemAction.DIGITAL_ASSISTANT,
onClick = { onClick = {
longPressAction = StemAction.DIGITAL_ASSISTANT longPressAction = StemAction.DIGITAL_ASSISTANT
@@ -165,23 +169,25 @@ fun LongPress(navController: NavController, name: String) {
} }
if (longPressAction == StemAction.CYCLE_NOISE_CONTROL_MODES) { if (longPressAction == StemAction.CYCLE_NOISE_CONTROL_MODES) {
Spacer(modifier = Modifier.height(32.dp))
Text( Text(
text = "NOISE CONTROL", text = stringResource(R.string.noise_control),
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f), color = textColor.copy(alpha = 0.6f),
), ),
fontFamily = FontFamily(Font(R.font.sf_pro)), fontFamily = FontFamily(Font(R.font.sf_pro)),
modifier = Modifier modifier = Modifier
.padding(top = 32.dp, bottom = 4.dp) .padding(horizontal = 18.dp)
.padding(horizontal = 8.dp)
) )
Spacer(modifier = Modifier.height(8.dp))
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)), .background(backgroundColor, RoundedCornerShape(28.dp)),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
) { ) {
val offListeningModeValue = ServiceManager.getService()!!.aacpManager.controlCommandStatusList.find { val offListeningModeValue = ServiceManager.getService()!!.aacpManager.controlCommandStatusList.find {
@@ -189,28 +195,28 @@ fun LongPress(navController: NavController, name: String) {
}?.value?.takeIf { it.isNotEmpty() }?.get(0) }?.value?.takeIf { it.isNotEmpty() }?.get(0)
val offListeningMode = offListeningModeValue == 1.toByte() val offListeningMode = offListeningModeValue == 1.toByte()
ListeningModeElement( ListeningModeElement(
name = "Off", name = stringResource(R.string.off),
enabled = offListeningMode, enabled = offListeningMode,
resourceId = R.drawable.noise_cancellation, resourceId = R.drawable.noise_cancellation,
isFirst = true) isFirst = true)
if (offListeningMode) RightDivider() if (offListeningMode) RightDivider()
ListeningModeElement( ListeningModeElement(
name = "Transparency", name = stringResource(R.string.transparency),
resourceId = R.drawable.transparency, resourceId = R.drawable.transparency,
isFirst = !offListeningMode) isFirst = !offListeningMode)
RightDivider() RightDivider()
ListeningModeElement( ListeningModeElement(
name = "Adaptive", name = stringResource(R.string.adaptive),
resourceId = R.drawable.adaptive) resourceId = R.drawable.adaptive)
RightDivider() RightDivider()
ListeningModeElement( ListeningModeElement(
name = "Noise Cancellation", name = stringResource(R.string.noise_cancellation),
resourceId = R.drawable.noise_cancellation, resourceId = R.drawable.noise_cancellation,
isLast = true) isLast = true)
} }
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(8.dp))
Text( 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( style = TextStyle(
fontSize = 12.sp, fontSize = 12.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Light,
@@ -218,7 +224,7 @@ fun LongPress(navController: NavController, name: String) {
fontFamily = FontFamily(Font(R.font.sf_pro)) fontFamily = FontFamily(Font(R.font.sf_pro))
), ),
modifier = Modifier 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 { val shape = when {
isFirst -> RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp) isFirst -> RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp)
isLast -> RoundedCornerShape(bottomStart = 14.dp, bottomEnd = 14.dp) isLast -> RoundedCornerShape(bottomStart = 28.dp, bottomEnd = 28.dp)
else -> RoundedCornerShape(0.dp) else -> RoundedCornerShape(0.dp)
} }
var backgroundColor by remember { mutableStateOf(if (darkMode) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) } 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, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween horizontalArrangement = Arrangement.SpaceBetween
) { ) {
@@ -384,24 +390,19 @@ fun ListeningModeElement(name: String, enabled: Boolean = true, resourceId: Int,
fontFamily = FontFamily(Font(R.font.sf_pro)), fontFamily = FontFamily(Font(R.font.sf_pro)),
) )
} }
Checkbox(
checked = checked.value, val floatAnimateState by animateFloatAsState(
onCheckedChange = { valueChanged() }, targetValue = if (checked.value) 1f else 0f,
colors = CheckboxDefaults.colors().copy( animationSpec = tween(durationMillis = 300)
checkedCheckmarkColor = Color(0xFF007AFF), )
uncheckedCheckmarkColor = Color.Transparent, Text(
checkedBoxColor = Color.Transparent, text = "􀆅",
uncheckedBoxColor = Color.Transparent, style = TextStyle(
checkedBorderColor = Color.Transparent, fontSize = 20.sp,
uncheckedBorderColor = Color.Transparent, fontFamily = FontFamily(Font(R.font.sf_pro)),
disabledBorderColor = Color.Transparent, color = Color(0xFF007AFF).copy(alpha = floatAnimateState),
disabledCheckedBoxColor = Color.Transparent,
disabledUncheckedBoxColor = Color.Transparent,
disabledUncheckedBorderColor = Color.Transparent
), ),
modifier = Modifier modifier = Modifier.padding(end = 4.dp)
.height(24.dp)
.scale(1.5f),
) )
} }
} }
@@ -417,15 +418,15 @@ fun LongPressActionElement(
) { ) {
val darkMode = isSystemInDarkTheme() val darkMode = isSystemInDarkTheme()
val shape = when { val shape = when {
isFirst -> RoundedCornerShape(topStart = 14.dp, topEnd = 14.dp) isFirst -> RoundedCornerShape(topStart = 28.dp, topEnd = 28.dp)
isLast -> RoundedCornerShape(bottomStart = 14.dp, bottomEnd = 14.dp) isLast -> RoundedCornerShape(bottomStart = 28.dp, bottomEnd = 28.dp)
else -> RoundedCornerShape(0.dp) else -> RoundedCornerShape(0.dp)
} }
var backgroundColor by remember { mutableStateOf(if (darkMode) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) } var backgroundColor by remember { mutableStateOf(if (darkMode) Color(0xFF1C1C1E) else Color(0xFFFFFFFF)) }
val animatedBackgroundColor by animateColorAsState(targetValue = backgroundColor, animationSpec = tween(durationMillis = 500)) val animatedBackgroundColor by animateColorAsState(targetValue = backgroundColor, animationSpec = tween(durationMillis = 500))
Row( Row(
modifier = Modifier modifier = Modifier
.height(48.dp) .height(55.dp)
.background(animatedBackgroundColor, shape) .background(animatedBackgroundColor, shape)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures( detectTapGestures(
@@ -437,7 +438,7 @@ fun LongPressActionElement(
} }
) )
} }
.padding(horizontal = 16.dp, vertical = 0.dp), .padding(horizontal = 16.dp),
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween horizontalArrangement = Arrangement.SpaceBetween
) { ) {
@@ -449,24 +450,18 @@ fun LongPressActionElement(
.weight(1f) .weight(1f)
.padding(start = 4.dp) .padding(start = 4.dp)
) )
Checkbox( val floatAnimateState by animateFloatAsState(
checked = selected, targetValue = if (selected) 1f else 0f,
onCheckedChange = { onClick() }, animationSpec = tween(durationMillis = 300)
colors = CheckboxDefaults.colors().copy( )
checkedCheckmarkColor = Color(0xFF007AFF), Text(
uncheckedCheckmarkColor = Color.Transparent, text = "􀆅",
checkedBoxColor = Color.Transparent, style = TextStyle(
uncheckedBoxColor = Color.Transparent, fontSize = 20.sp,
checkedBorderColor = Color.Transparent, fontFamily = FontFamily(Font(R.font.sf_pro)),
uncheckedBorderColor = Color.Transparent, color = Color(0xFF007AFF).copy(alpha = floatAnimateState)
disabledBorderColor = Color.Transparent,
disabledCheckedBoxColor = Color.Transparent,
disabledUncheckedBoxColor = Color.Transparent,
disabledUncheckedBorderColor = Color.Transparent
), ),
modifier = Modifier modifier = Modifier.padding(end = 4.dp)
.height(24.dp)
.scale(1.5f),
) )
} }
} }

View File

@@ -32,11 +32,9 @@ import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.foundation.text.BasicTextField 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.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.IconButton import androidx.compose.material3.IconButton
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.mutableStateOf 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.res.stringResource
import androidx.compose.ui.text.TextRange import androidx.compose.ui.text.TextRange
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.input.TextFieldValue import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.content.edit import androidx.core.content.edit
import androidx.navigation.NavController import androidx.navigation.NavController
import com.kyant.backdrop.backdrops.layerBackdrop
import com.kyant.backdrop.backdrops.rememberLayerBackdrop
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import me.kavishdevar.librepods.R import me.kavishdevar.librepods.R
import me.kavishdevar.librepods.composables.StyledIconButton 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)) name.value = name.value.copy(selection = TextRange(name.value.text.length))
} }
val backdrop = rememberLayerBackdrop()
StyledScaffold( StyledScaffold(
title = stringResource(R.string.name), title = stringResource(R.string.name),
navigationButton = { navigationButton = {
StyledIconButton( StyledIconButton(
onClick = { navController.popBackStack() }, onClick = { navController.popBackStack() },
icon = "􀯶", icon = "􀯶",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
}, },
) { spacerHeight -> ) { spacerHeight ->
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.layerBackdrop(backdrop)
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
) { ) {
Spacer(modifier = Modifier.height(spacerHeight)) Spacer(modifier = Modifier.height(spacerHeight))
@@ -105,10 +111,10 @@ fun RenameScreen(navController: NavController) {
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.height(55.dp) .height(58.dp)
.background( .background(
backgroundColor, backgroundColor,
RoundedCornerShape(14.dp) RoundedCornerShape(28.dp)
) )
.padding(horizontal = 16.dp, vertical = 8.dp) .padding(horizontal = 16.dp, vertical = 8.dp)
) { ) {
@@ -120,8 +126,9 @@ fun RenameScreen(navController: NavController) {
ServiceManager.getService()?.setName(it.text) ServiceManager.getService()?.setName(it.text)
}, },
textStyle = TextStyle( textStyle = TextStyle(
color = textColor,
fontSize = 16.sp, fontSize = 16.sp,
color = textColor,
fontFamily = FontFamily(Font(R.font.sf_pro))
), ),
singleLine = true, singleLine = true,
cursorBrush = SolidColor(cursorColor), cursorBrush = SolidColor(cursorColor),
@@ -138,14 +145,15 @@ fun RenameScreen(navController: NavController) {
IconButton( IconButton(
onClick = { onClick = {
name.value = TextFieldValue("") name.value = TextFieldValue("")
sharedPreferences.edit { putString("name", "") }
ServiceManager.getService()?.setName("")
} }
) { ) {
Icon( Text(
Icons.Default.Clear, text = "􀁡",
contentDescription = "Clear", style = TextStyle(
tint = if (isDarkTheme) Color.White else Color.Black 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)
),
) )
} }
} }

View File

@@ -59,6 +59,8 @@ import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.navigation.NavController 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.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
@@ -95,19 +97,23 @@ fun TransparencySettingsScreen(navController: NavController) {
val activeTrackColor = if (isDarkTheme) Color(0xFF007AFF) else Color(0xFF3C6DF5) val activeTrackColor = if (isDarkTheme) Color(0xFF007AFF) else Color(0xFF3C6DF5)
val thumbColor = if (isDarkTheme) Color(0xFFFFFFFF) else Color(0xFFFFFFFF) val thumbColor = if (isDarkTheme) Color(0xFFFFFFFF) else Color(0xFFFFFFFF)
val backdrop = rememberLayerBackdrop()
StyledScaffold( StyledScaffold(
title = stringResource(R.string.customize_transparency_mode), title = stringResource(R.string.customize_transparency_mode),
navigationButton = { navigationButton = {
StyledIconButton( StyledIconButton(
onClick = { navController.popBackStack() }, onClick = { navController.popBackStack() },
icon = "􀯶", icon = "􀯶",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
} }
){ spacerHeight, hazeState -> ){ spacerHeight, hazeState ->
Column( Column(
modifier = Modifier modifier = Modifier
.hazeSource(hazeState) .hazeSource(hazeState)
.layerBackdrop(backdrop)
.fillMaxSize() .fillMaxSize()
.verticalScroll(verticalScrollState) .verticalScroll(verticalScrollState)
.padding(horizontal = 16.dp), .padding(horizontal = 16.dp),
@@ -154,19 +160,15 @@ fun TransparencySettingsScreen(navController: NavController) {
object : (ByteArray) -> Unit { object : (ByteArray) -> Unit {
override fun invoke(value: ByteArray) { override fun invoke(value: ByteArray) {
val parsed = parseTransparencySettingsResponse(value) val parsed = parseTransparencySettingsResponse(value)
if (parsed != null) { enabled.value = parsed.enabled
enabled.value = parsed.enabled amplificationSliderValue.floatValue = parsed.netAmplification
amplificationSliderValue.floatValue = parsed.netAmplification balanceSliderValue.floatValue = parsed.balance
balanceSliderValue.floatValue = parsed.balance toneSliderValue.floatValue = parsed.leftTone
toneSliderValue.floatValue = parsed.leftTone ambientNoiseReductionSliderValue.floatValue =
ambientNoiseReductionSliderValue.floatValue = parsed.leftAmbientNoiseReduction
parsed.leftAmbientNoiseReduction conversationBoostEnabled.value = parsed.leftConversationBoost
conversationBoostEnabled.value = parsed.leftConversationBoost eq.value = parsed.leftEQ.copyOf()
eq.value = parsed.leftEQ.copyOf() Log.d(TAG, "Updated transparency settings from notification")
Log.d(TAG, "Updated transparency settings from notification")
} else {
Log.w(TAG, "Failed to parse transparency settings from notification")
}
} }
} }
} }
@@ -251,12 +253,7 @@ fun TransparencySettingsScreen(navController: NavController) {
try { try {
val data = attManager.read(ATTHandles.TRANSPARENCY) val data = attManager.read(ATTHandles.TRANSPARENCY)
parsedSettings = parseTransparencySettingsResponse(data = data) parsedSettings = parseTransparencySettingsResponse(data = data)
if (parsedSettings != null) { Log.d(TAG, "Parsed settings on attempt $attempt")
Log.d(TAG, "Parsed settings on attempt $attempt")
break
} else {
Log.d(TAG, "Parsing returned null on attempt $attempt")
}
} catch (e: Exception) { } catch (e: Exception) {
Log.w(TAG, "Read attempt $attempt failed: ${e.message}") Log.w(TAG, "Read attempt $attempt failed: ${e.message}")
} }
@@ -297,7 +294,7 @@ fun TransparencySettingsScreen(navController: NavController) {
) )
Spacer(modifier = Modifier.height(4.dp)) Spacer(modifier = Modifier.height(4.dp))
StyledSlider( StyledSlider(
label = stringResource(R.string.amplification).uppercase(), label = stringResource(R.string.amplification),
valueRange = -1f..1f, valueRange = -1f..1f,
mutableFloatState = amplificationSliderValue, mutableFloatState = amplificationSliderValue,
onValueChange = { onValueChange = {
@@ -309,20 +306,20 @@ fun TransparencySettingsScreen(navController: NavController) {
) )
StyledSlider( StyledSlider(
label = stringResource(R.string.balance).uppercase(), label = stringResource(R.string.balance),
valueRange = -1f..1f, valueRange = -1f..1f,
mutableFloatState = balanceSliderValue, mutableFloatState = balanceSliderValue,
onValueChange = { onValueChange = {
balanceSliderValue.floatValue = it balanceSliderValue.floatValue = it
}, },
snapPoints = listOf(0f), snapPoints = listOf(-1f, 0f, 1f),
startLabel = stringResource(R.string.left), startLabel = stringResource(R.string.left),
endLabel = stringResource(R.string.right), endLabel = stringResource(R.string.right),
independent = true, independent = true,
) )
StyledSlider( StyledSlider(
label = stringResource(R.string.tone).uppercase(), label = stringResource(R.string.tone),
valueRange = -1f..1f, valueRange = -1f..1f,
mutableFloatState = toneSliderValue, mutableFloatState = toneSliderValue,
onValueChange = { onValueChange = {
@@ -334,7 +331,7 @@ fun TransparencySettingsScreen(navController: NavController) {
) )
StyledSlider( StyledSlider(
label = stringResource(R.string.ambient_noise_reduction).uppercase(), label = stringResource(R.string.ambient_noise_reduction),
valueRange = 0f..1f, valueRange = 0f..1f,
mutableFloatState = ambientNoiseReductionSliderValue, mutableFloatState = ambientNoiseReductionSliderValue,
onValueChange = { onValueChange = {
@@ -356,20 +353,20 @@ fun TransparencySettingsScreen(navController: NavController) {
// Only show transparency mode EQ section if SDP offset is available // Only show transparency mode EQ section if SDP offset is available
if (isSdpOffsetAvailable.value) { if (isSdpOffsetAvailable.value) {
Text( Text(
text = stringResource(R.string.equalizer).uppercase(), text = stringResource(R.string.equalizer),
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f), color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro)) fontFamily = FontFamily(Font(R.font.sf_pro))
), ),
modifier = Modifier.padding(8.dp, bottom = 2.dp) modifier = Modifier.padding(16.dp, bottom = 4.dp)
) )
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxWidth() .fillMaxWidth()
.background(backgroundColor, RoundedCornerShape(14.dp)) .background(backgroundColor, RoundedCornerShape(28.dp))
.padding(16.dp), .padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally, horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.SpaceBetween verticalArrangement = Arrangement.SpaceBetween

View File

@@ -85,6 +85,8 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import androidx.navigation.NavController 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.hazeSource
import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
@@ -208,6 +210,8 @@ fun TroubleshootingScreen(navController: NavController) {
showBottomSheet = true showBottomSheet = true
} }
val backdrop = rememberLayerBackdrop()
Box( Box(
modifier = Modifier.fillMaxSize() modifier = Modifier.fillMaxSize()
) { ) {
@@ -217,28 +221,30 @@ fun TroubleshootingScreen(navController: NavController) {
StyledIconButton( StyledIconButton(
onClick = { navController.popBackStack() }, onClick = { navController.popBackStack() },
icon = "􀯶", icon = "􀯶",
darkMode = isDarkTheme darkMode = isDarkTheme,
backdrop = backdrop
) )
} }
){ spacerHeight, hazeState -> ){ spacerHeight, hazeState ->
Column( Column(
modifier = Modifier modifier = Modifier
.fillMaxSize() .fillMaxSize()
.verticalScroll(scrollState) .layerBackdrop(backdrop)
.hazeSource(state = hazeState) .hazeSource(state = hazeState)
.verticalScroll(scrollState)
.padding(horizontal = 16.dp) .padding(horizontal = 16.dp)
) { ) {
Spacer(modifier = Modifier.height(spacerHeight)) Spacer(modifier = Modifier.height(spacerHeight))
Text( Text(
text = stringResource(R.string.saved_logs).uppercase(), text = stringResource(R.string.saved_logs),
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Bold,
color = textColor.copy(alpha = 0.6f), color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro)) 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)) Spacer(modifier = Modifier.height(2.dp))
@@ -249,7 +255,7 @@ fun TroubleshootingScreen(navController: NavController) {
.fillMaxWidth() .fillMaxWidth()
.background( .background(
backgroundColor, backgroundColor,
RoundedCornerShape(14.dp) RoundedCornerShape(28.dp)
) )
.padding(16.dp), .padding(16.dp),
horizontalAlignment = Alignment.CenterHorizontally horizontalAlignment = Alignment.CenterHorizontally
@@ -266,7 +272,7 @@ fun TroubleshootingScreen(navController: NavController) {
.fillMaxWidth() .fillMaxWidth()
.background( .background(
backgroundColor, backgroundColor,
RoundedCornerShape(14.dp) RoundedCornerShape(28.dp)
) )
.padding(horizontal = 16.dp, vertical = 8.dp) .padding(horizontal = 16.dp, vertical = 8.dp)
) { ) {
@@ -372,14 +378,14 @@ fun TroubleshootingScreen(navController: NavController) {
Spacer(modifier = Modifier.height(16.dp)) Spacer(modifier = Modifier.height(16.dp))
Text( Text(
text = "TROUBLESHOOTING STEPS".uppercase(), text = "TROUBLESHOOTING STEPS",
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
fontWeight = FontWeight.Light, fontWeight = FontWeight.Light,
color = textColor.copy(alpha = 0.6f), color = textColor.copy(alpha = 0.6f),
fontFamily = FontFamily(Font(R.font.sf_pro)) 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)) Spacer(modifier = Modifier.height(2.dp))
@@ -389,7 +395,7 @@ fun TroubleshootingScreen(navController: NavController) {
.fillMaxWidth() .fillMaxWidth()
.background( .background(
backgroundColor, backgroundColor,
RoundedCornerShape(14.dp) RoundedCornerShape(28.dp)
) )
.padding(16.dp) .padding(16.dp)
) { ) {

View File

@@ -15,12 +15,13 @@
<string name="case_alt">Case</string> <string name="case_alt">Case</string>
<string name="test">Test</string> <string name="test">Test</string>
<string name="name">Name</string> <string name="name">Name</string>
<string name="noise_control">Noise Control</string> <string name="noise_control">Listening Mode</string>
<string name="off">Off</string> <string name="off">Off</string>
<string name="transparency">Transparency</string> <string name="transparency">Transparency</string>
<string name="adaptive">Adaptive</string> <string name="adaptive">Adaptive</string>
<string name="noise_cancellation">Noise Cancellation</string> <string name="noise_cancellation">Noise Cancellation</string>
<string name="press_and_hold_airpods">Press and Hold AirPods</string> <string name="press_and_hold_airpods">Press and Hold AirPods</string>
<string name="press_and_hold_noise_control_description">Press and hold the stem to cycle between the selected listening modes.</string>
<string name="head_gestures">Head Gestures</string> <string name="head_gestures">Head Gestures</string>
<string name="left">Left</string> <string name="left">Left</string>
<string name="right">Right</string> <string name="right">Right</string>
@@ -110,7 +111,7 @@
<string name="press_speed">Press Speed</string> <string name="press_speed">Press Speed</string>
<string name="press_speed_description">Adjust the speed required to press two or three times on your AirPods.</string> <string name="press_speed_description">Adjust the speed required to press two or three times on your AirPods.</string>
<string name="press_and_hold_duration">Press and Hold Duration</string> <string name="press_and_hold_duration">Press and Hold Duration</string>
<string name="press_and_hold_duration_description">Adjust the duration required to press and hold on your AirPods</string> <string name="press_and_hold_duration_description">Adjust the duration required to press and hold on your AirPods.</string>
<string name="volume_swipe_speed">Volume Swipe Speed</string> <string name="volume_swipe_speed">Volume Swipe Speed</string>
<string name="volume_swipe_speed_description">To prevent unintended volume adjustments, select preferred wait time between swipes.</string> <string name="volume_swipe_speed_description">To prevent unintended volume adjustments, select preferred wait time between swipes.</string>
<string name="equalizer">Equalizer</string> <string name="equalizer">Equalizer</string>
@@ -133,7 +134,7 @@
<string name="ambient_noise_reduction">Ambient Noise Reduction</string> <string name="ambient_noise_reduction">Ambient Noise Reduction</string>
<string name="conversation_boost">Conversation Boost</string> <string name="conversation_boost">Conversation Boost</string>
<string name="conversation_boost_description">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.</string> <string name="conversation_boost_description">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.</string>
<string name="hearing_aid_description">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.</string> <string name="hearing_aid_description">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.</string>
<string name="media_assist">Media Assist</string> <string name="media_assist">Media Assist</string>
<string name="media_assist_description">AirPods Pro can use the results of a hearing test to make adjustments that improve the clarity of music, video, and calls.</string> <string name="media_assist_description">AirPods Pro can use the results of a hearing test to make adjustments that improve the clarity of music, video, and calls.</string>
<string name="adjust_media">Adjust Music and Video</string> <string name="adjust_media">Adjust Music and Video</string>
@@ -174,4 +175,5 @@
<string name="must_be_32_hex_chars">Must be exactly 32 hex characters</string> <string name="must_be_32_hex_chars">Must be exactly 32 hex characters</string>
<string name="error_converting_hex">Error converting hex:</string> <string name="error_converting_hex">Error converting hex:</string>
<string name="found_offset_restart_bluetooth">Found offset please restart the Bluetooth process</string> <string name="found_offset_restart_bluetooth">Found offset please restart the Bluetooth process</string>
<string name="digital_assistant">Digital Assistant</string>
</resources> </resources>