diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/ConfirmationDialog.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/ConfirmationDialog.kt index 1378c33..c3310c5 100644 --- a/android/app/src/main/java/me/kavishdevar/librepods/composables/ConfirmationDialog.kt +++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/ConfirmationDialog.kt @@ -1,47 +1,39 @@ package me.kavishdevar.librepods.composables import androidx.compose.foundation.background +import androidx.compose.foundation.clickable import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Row -import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.requiredWidthIn -import androidx.compose.foundation.layout.width import androidx.compose.foundation.shape.RoundedCornerShape -import androidx.compose.material3.HorizontalDivider import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.MutableState -import androidx.compose.runtime.getValue -import androidx.compose.runtime.mutableStateOf -import androidx.compose.runtime.remember -import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.graphics.Color -import androidx.compose.ui.input.pointer.PointerEventType -import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontWeight -import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp -import androidx.compose.ui.window.Dialog -import dev.chrisbanes.haze.HazeState -import dev.chrisbanes.haze.hazeEffect -import dev.chrisbanes.haze.materials.CupertinoMaterials -import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi +import com.kyant.backdrop.Backdrop +import com.kyant.backdrop.drawBackdrop +import com.kyant.backdrop.effects.blur +import com.kyant.backdrop.effects.colorFilter +import com.kyant.backdrop.effects.refraction import me.kavishdevar.librepods.R -@ExperimentalHazeMaterialsApi @Composable fun ConfirmationDialog( showDialog: MutableState, @@ -51,133 +43,100 @@ fun ConfirmationDialog( dismissText: String = "Cancel", onConfirm: () -> Unit, onDismiss: () -> Unit = { showDialog.value = false }, - hazeState: HazeState, + backdrop: Backdrop, ) { - val isDarkTheme = isSystemInDarkTheme() - val textColor = if (isDarkTheme) Color.White else Color.Black - val accentColor = if (isDarkTheme) Color(0xFF007AFF) else Color(0xFF3C6DF5) if (showDialog.value) { - Dialog(onDismissRequest = { showDialog.value = false }) { + val isLightTheme = !isSystemInDarkTheme() + val contentColor = if (isLightTheme) Color.Black else Color.White + val accentColor = if (isLightTheme) Color(0xFF0088FF) else Color(0xFF0091FF) + val containerColor = if (isLightTheme) Color(0xFFFAFAFA).copy(0.6f) else Color(0xFF121212).copy(0.4f) + val dimColor = if (isLightTheme) Color(0xFF29293A).copy(0.23f) else Color(0xFF121212).copy(0.56f) + + Box( + Modifier + .background(dimColor) + .fillMaxSize() + .clickable(onClick = onDismiss) + ) { Box( - modifier = Modifier + Modifier + .align(Alignment.Center) + .drawBackdrop( + backdrop, + { RoundedCornerShape(48f.dp) }, +// highlight = { Highlight { HighlightStyle.Solid } }, + onDrawSurface = { drawRect(containerColor) } + ) { + colorFilter( + brightness = if (isLightTheme) 0.2f else 0.1f, + saturation = 1.5f + ) + blur(if (isLightTheme) 16f.dp.toPx() else 8f.dp.toPx()) + refraction(24f.dp.toPx(), 48f.dp.toPx(), true) + } .fillMaxWidth(0.75f) .requiredWidthIn(min = 200.dp, max = 360.dp) - .background(Color.Transparent, RoundedCornerShape(14.dp)) - .clip(RoundedCornerShape(14.dp)) - .hazeEffect( - hazeState, - style = CupertinoMaterials.regular( - containerColor = if (isDarkTheme) Color(0xFF1C1C1E).copy(alpha = 0.95f) else Color.White.copy(alpha = 0.95f) - ) - ) ) { - Column(horizontalAlignment = Alignment.CenterHorizontally) { - androidx.compose.foundation.layout.Spacer(modifier = Modifier.height(24.dp)) + Column(horizontalAlignment = Alignment.Start) { + Spacer(modifier = Modifier.height(28.dp)) Text( title, style = TextStyle( fontSize = 16.sp, fontWeight = FontWeight.Bold, - color = textColor, + color = contentColor, fontFamily = FontFamily(Font(R.font.sf_pro)) ), - textAlign = TextAlign.Center, modifier = Modifier.padding(horizontal = 16.dp) ) - androidx.compose.foundation.layout.Spacer(modifier = Modifier.height(12.dp)) + Spacer(modifier = Modifier.height(16.dp)) Text( message, style = TextStyle( fontSize = 14.sp, - color = textColor.copy(alpha = 0.8f), + color = contentColor.copy(alpha = 0.8f), fontFamily = FontFamily(Font(R.font.sf_pro)) ), - textAlign = TextAlign.Center, modifier = Modifier.padding(horizontal = 16.dp) ) - androidx.compose.foundation.layout.Spacer(modifier = Modifier.height(16.dp)) - HorizontalDivider( - thickness = 1.dp, - color = Color(0x40888888), - modifier = Modifier.fillMaxWidth() - ) - var leftPressed by remember { mutableStateOf(false) } - var rightPressed by remember { mutableStateOf(false) } - val pressedColor = if (isDarkTheme) Color(0x40888888) else Color(0x40D9D9D9) + Spacer(modifier = Modifier.height(16.dp)) + Row( - modifier = Modifier - .fillMaxWidth() - .height(48.dp) - .pointerInput(Unit) { - awaitPointerEventScope { - while (true) { - val event = awaitPointerEvent() - val position = event.changes.first().position - val width = size.width.toFloat() - val height = size.height.toFloat() - val isWithinBounds = position.y >= 0 && position.y <= height - val isLeft = position.x < width / 2 - event.changes.first().consume() - when (event.type) { - PointerEventType.Press -> { - if (isWithinBounds) { - leftPressed = isLeft - rightPressed = !isLeft - } else { - leftPressed = false - rightPressed = false - } - } - PointerEventType.Move -> { - if (isWithinBounds) { - leftPressed = isLeft - rightPressed = !isLeft - } else { - leftPressed = false - rightPressed = false - } - } - PointerEventType.Release -> { - if (isWithinBounds) { - if (leftPressed) { - onDismiss() - } else if (rightPressed) { - onConfirm() - } - } - leftPressed = false - rightPressed = false - } - } - } - } - }, - horizontalArrangement = Arrangement.Start, + Modifier + .padding(24.dp, 12.dp, 24.dp, 24.dp) + .fillMaxWidth(), + horizontalArrangement = Arrangement.spacedBy(16.dp), verticalAlignment = Alignment.CenterVertically ) { Box( - modifier = Modifier + Modifier + .clip(RoundedCornerShape(50.dp)) + .background(containerColor.copy(0.2f)) + .clickable(onClick = onDismiss) + .height(48.dp) .weight(1f) - .fillMaxHeight() - .background(if (leftPressed) pressedColor else Color.Transparent), + .padding(horizontal = 16.dp), contentAlignment = Alignment.Center ) { - Text(dismissText, color = accentColor) + Text( + dismissText, + style = TextStyle(contentColor, 16.sp) + ) } Box( - modifier = Modifier - .width(1.dp) - .fillMaxHeight() - .background(Color(0x40888888)) - ) - Box( - modifier = Modifier + Modifier + .clip(RoundedCornerShape(50.dp)) + .background(accentColor) + .clickable(onClick = onConfirm) + .height(48.dp) .weight(1f) - .fillMaxHeight() - .background(if (rightPressed) pressedColor else Color.Transparent), + .padding(horizontal = 16.dp), contentAlignment = Alignment.Center ) { - Text(confirmText, color = accentColor) + Text( + confirmText, + style = TextStyle(Color.White, 16.sp) + ) } } } diff --git a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSlider.kt b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSlider.kt index b5c629d..64187d1 100644 --- a/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSlider.kt +++ b/android/app/src/main/java/me/kavishdevar/librepods/composables/StyledSlider.kt @@ -133,16 +133,18 @@ fun StyledSlider( val density = LocalDensity.current val content = @Composable { - Box(Modifier.fillMaxWidth()) { + Box( + Modifier.fillMaxWidth(if (startIcon == null && endIcon == null) 0.95f else 1f) + ) { Box(Modifier .backdrop(sliderBackdrop) .fillMaxWidth()) { Column( modifier = Modifier .fillMaxWidth(1f) - .padding(vertical = 8.dp), + .padding(vertical = 12.dp), horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(8.dp) + verticalArrangement = Arrangement.spacedBy(12.dp) ) { if (label != null) { Text( @@ -152,13 +154,14 @@ fun StyledSlider( fontWeight = FontWeight.Medium, color = labelTextColor, fontFamily = FontFamily(Font(R.font.sf_pro)) - ) + ), ) } if (startLabel != null || endLabel != null) { Row( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth(), horizontalArrangement = Arrangement.SpaceBetween ) { Text( @@ -183,7 +186,10 @@ fun StyledSlider( } Row( - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 4.dp) + .then(if (startIcon == null && endIcon == null) Modifier.padding(horizontal = 12.dp) else Modifier), verticalAlignment = Alignment.CenterVertically, horizontalArrangement = Arrangement.spacedBy(0.dp) ) { @@ -191,7 +197,7 @@ fun StyledSlider( Text( text = startIcon, style = TextStyle( - fontSize = 16.sp, + fontSize = 18.sp, fontWeight = FontWeight.Normal, color = labelTextColor, fontFamily = FontFamily(Font(R.font.sf_pro)) @@ -240,7 +246,7 @@ fun StyledSlider( Text( text = endIcon, style = TextStyle( - fontSize = 16.sp, + fontSize = 18.sp, fontWeight = FontWeight.Normal, color = labelTextColor, fontFamily = FontFamily(Font(R.font.sf_pro)) @@ -260,10 +266,10 @@ fun StyledSlider( Modifier .graphicsLayer { val startOffset = - if (startIcon != null) startIconWidthState.floatValue + with(density) { 24.dp.toPx() } else 0f + if (startIcon != null) startIconWidthState.floatValue + with(density) { 24.dp.toPx() } else with(density) { 8.dp.toPx() } translationX = startOffset + fraction * trackWidthState.floatValue - size.width / 2f - translationY = trackPositionState.floatValue / 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() } } .draggable( rememberDraggableState { delta -> @@ -372,13 +378,13 @@ private fun snapIfClose(value: Float, points: List, threshold: Float = 0. return if (kotlin.math.abs(nearest - value) <= threshold) nearest else value } -@Preview(uiMode = Configuration.UI_MODE_NIGHT_NO) +@Preview(uiMode = Configuration.UI_MODE_NIGHT_YES) @Composable fun StyledSliderPreview() { val a = remember { mutableFloatStateOf(1f) } Box( Modifier - .background(if (isSystemInDarkTheme()) Color(0xFF121212) else Color(0xFFF0F0F0)) + .background(if (isSystemInDarkTheme()) Color(0xFF000000) else Color(0xFFF0F0F0)) .padding(16.dp) .fillMaxSize() ) { @@ -393,8 +399,8 @@ fun StyledSliderPreview() { }, valueRange = 0f..2f, independent = true, - startIcon = "A", - endIcon = "B" + startLabel = "A", + endLabel = "B" ) } } diff --git a/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidScreen.kt b/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidScreen.kt index 27752ec..cf022a4 100644 --- a/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidScreen.kt +++ b/android/app/src/main/java/me/kavishdevar/librepods/screens/HearingAidScreen.kt @@ -70,6 +70,8 @@ import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.navigation.NavController +import com.kyant.backdrop.backdrop +import com.kyant.backdrop.rememberBackdrop import dev.chrisbanes.haze.HazeEffectScope import dev.chrisbanes.haze.HazeState import dev.chrisbanes.haze.hazeEffect @@ -78,7 +80,6 @@ import dev.chrisbanes.haze.materials.CupertinoMaterials import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.Job import kotlinx.coroutines.launch import me.kavishdevar.librepods.R import me.kavishdevar.librepods.composables.ConfirmationDialog @@ -90,8 +91,6 @@ import me.kavishdevar.librepods.utils.parseTransparencySettingsResponse import me.kavishdevar.librepods.utils.sendTransparencySettings import kotlin.io.encoding.ExperimentalEncodingApi -private var debounceJob: Job? = null -private var phoneMediaDebounceJob: Job? = null private const val TAG = "AccessibilitySettings" @SuppressLint("DefaultLocale") @@ -109,6 +108,7 @@ fun HearingAidScreen(navController: NavController) { val aacpManager = remember { ServiceManager.getService()?.aacpManager } val showDialog = remember { mutableStateOf(false) } + val backdrop = rememberBackdrop() val hearingAidEnabled = remember { val aidStatus = aacpManager?.controlCommandStatusList?.find { it.identifier == AACPManager.Companion.ControlCommandIdentifiers.HEARING_AID } @@ -164,7 +164,9 @@ fun HearingAidScreen(navController: NavController) { ) ) }, - snackbarHost = { SnackbarHost(snackbarHostState) } + snackbarHost = { SnackbarHost(snackbarHostState) }, + modifier = Modifier + .backdrop(backdrop) ) { paddingValues -> Column( modifier = Modifier @@ -210,7 +212,7 @@ fun HearingAidScreen(navController: NavController) { } else { aacpManager?.sendControlCommand(AACPManager.Companion.ControlCommandIdentifiers.HEARING_AID.value, byteArrayOf(0x01, 0x02)) aacpManager?.sendControlCommand(AACPManager.Companion.ControlCommandIdentifiers.HEARING_ASSIST_CONFIG.value, 0x02.toByte()) - hearingAidEnabled.value = value + hearingAidEnabled.value = false } } @@ -450,6 +452,6 @@ fun HearingAidScreen(navController: NavController) { } } }, - hazeState = hazeState + backdrop = backdrop ) }