android: bring back original confirmation dialog

too lazy to fix/implement properly the glassy one
This commit is contained in:
Kavish Devar
2025-09-29 00:17:02 +05:30
parent 48b715af68
commit 504e70371b
2 changed files with 118 additions and 218 deletions

View File

@@ -18,289 +18,188 @@
package me.kavishdevar.librepods.composables package me.kavishdevar.librepods.composables
import android.graphics.RuntimeShader import androidx.compose.foundation.background
import android.os.Build
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.VectorConverter
import androidx.compose.animation.core.VisibilityThreshold
import androidx.compose.animation.core.spring
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.scaleIn
import androidx.compose.animation.scaleOut
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
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.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.fillMaxHeight
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.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.requiredWidthIn import androidx.compose.foundation.layout.requiredWidthIn
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.HorizontalDivider
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.MutableState import androidx.compose.runtime.MutableState
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.rememberCoroutineScope
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.geometry.Offset import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ShaderBrush import androidx.compose.ui.input.pointer.PointerEventType
import androidx.compose.ui.graphics.toArgb
import androidx.compose.ui.input.pointer.pointerInput import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.text.TextStyle import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.Font import androidx.compose.ui.text.font.Font
import androidx.compose.ui.text.font.FontFamily import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp import androidx.compose.ui.unit.sp
import androidx.compose.ui.util.fastCoerceAtMost import androidx.compose.ui.window.Dialog
import androidx.compose.ui.util.fastCoerceIn import dev.chrisbanes.haze.HazeState
import androidx.compose.ui.util.lerp import dev.chrisbanes.haze.hazeEffect
import com.kyant.backdrop.Backdrop import dev.chrisbanes.haze.materials.CupertinoMaterials
import com.kyant.backdrop.drawBackdrop import dev.chrisbanes.haze.materials.ExperimentalHazeMaterialsApi
import com.kyant.backdrop.effects.blur
import com.kyant.backdrop.effects.colorControls
import com.kyant.backdrop.effects.refraction
import com.kyant.backdrop.highlight.Highlight
import kotlinx.coroutines.launch
import me.kavishdevar.librepods.R import me.kavishdevar.librepods.R
import me.kavishdevar.librepods.utils.inspectDragGestures
import kotlin.math.abs
import kotlin.math.atan2
import kotlin.math.cos
import kotlin.math.sin
import kotlin.math.tanh
@ExperimentalHazeMaterialsApi
@Composable @Composable
fun ConfirmationDialog( fun ConfirmationDialog(
showDialog: MutableState<Boolean>, showDialog: MutableState<Boolean>,
title: String, title: String,
message: String, message: String,
confirmText: String = "Ok", confirmText: String = "Enable",
dismissText: String = "Cancel", dismissText: String = "Cancel",
onConfirm: () -> Unit, onConfirm: () -> Unit,
onDismiss: () -> Unit = { showDialog.value = false }, onDismiss: () -> Unit = { showDialog.value = false },
backdrop: Backdrop, hazeState: HazeState,
) { ) {
AnimatedVisibility( val isDarkTheme = isSystemInDarkTheme()
visible = showDialog.value, val textColor = if (isDarkTheme) Color.White else Color.Black
enter = fadeIn() + scaleIn(initialScale = 1.25f), val accentColor = if (isDarkTheme) Color(0xFF007AFF) else Color(0xFF3C6DF5)
exit = fadeOut() + scaleOut(targetScale = 0.9f) if (showDialog.value) {
) { Dialog(onDismissRequest = { showDialog.value = false }) {
val animationScope = rememberCoroutineScope()
val progressAnimation = remember { Animatable(0f) }
var pressStartPosition by remember { mutableStateOf(Offset.Zero) }
val offsetAnimation = remember { Animatable(Offset.Zero, Offset.VectorConverter) }
val interactiveHighlightShader = remember {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
RuntimeShader(
"""
uniform float2 size;
layout(color) uniform half4 color;
uniform float radius;
uniform float2 offset;
half4 main(float2 coord) {
float2 center = offset;
float dist = distance(coord, center);
float intensity = smoothstep(radius, radius * 0.5, dist);
return color * intensity;
}"""
)
} else {
null
}
}
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(0xFFFFFFFF).copy(0.6f) else Color(0xFF101010).copy(0.6f)
Box(
Modifier
.fillMaxSize()
.clickable(onClick = onDismiss, indication = null, interactionSource = remember { MutableInteractionSource() } )
) {
Box( Box(
Modifier modifier = Modifier
.align(Alignment.Center) // .fillMaxWidth(0.75f)
.clickable(onClick = {}, indication = null, interactionSource = remember { MutableInteractionSource() } )
.drawBackdrop(
backdrop,
{ RoundedCornerShape(48f.dp) },
highlight = {
Highlight.SolidDefault
},
onDrawSurface = { drawRect(containerColor) },
effects = {
colorControls(
brightness = if (isLightTheme) 0.4f else 0.2f,
saturation = 1.5f
)
blur(if (isLightTheme) 16f.dp.toPx() else 8f.dp.toPx())
refraction(24f.dp.toPx(), 48f.dp.toPx(), true)
},
layerBlock = {
val width = size.width
val height = size.height
val progress = progressAnimation.value
val maxScale = 0f
val scale = lerp(1f, 1f + maxScale, progress)
val maxOffset = size.minDimension
val initialDerivative = 0.05f
val offset = offsetAnimation.value
translationX = maxOffset * tanh(initialDerivative * offset.x / maxOffset)
translationY = maxOffset * tanh(initialDerivative * offset.y / maxOffset)
val maxDragScale = 0.1f
val offsetAngle = atan2(offset.y, offset.x)
scaleX =
scale +
maxDragScale * abs(cos(offsetAngle) * offset.x / size.maxDimension) *
(width / height).fastCoerceAtMost(1f)
scaleY =
scale +
maxDragScale * abs(sin(offsetAngle) * offset.y / size.maxDimension) *
(height / width).fastCoerceAtMost(1f)
},
onDrawFront = {
val progress = progressAnimation.value.fastCoerceIn(0f, 1f)
if (progress > 0f) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU && interactiveHighlightShader != null) {
drawRect(
Color.White.copy(0.05f * progress),
blendMode = BlendMode.Plus
)
interactiveHighlightShader.apply {
val offset = pressStartPosition + offsetAnimation.value
setFloatUniform("size", size.width, size.height)
setColorUniform("color", Color.White.copy(0.075f * progress).toArgb())
setFloatUniform("radius", size.maxDimension / 2)
setFloatUniform(
"offset",
offset.x.fastCoerceIn(0f, size.width),
offset.y.fastCoerceIn(0f, size.height)
)
}
drawRect(
ShaderBrush(interactiveHighlightShader),
blendMode = BlendMode.Plus
)
} else {
drawRect(
Color.White.copy(0.125f * progress),
blendMode = BlendMode.Plus
)
}
}
},
contentEffects = {
refraction(8f.dp.toPx(), 24f.dp.toPx(), false)
}
)
.fillMaxWidth(0.75f)
.requiredWidthIn(min = 200.dp, max = 360.dp) .requiredWidthIn(min = 200.dp, max = 360.dp)
.pointerInput(animationScope) { .background(Color.Transparent, RoundedCornerShape(14.dp))
val progressAnimationSpec = spring(0.5f, 300f, 0.001f) .clip(RoundedCornerShape(14.dp))
val offsetAnimationSpec = spring(1f, 300f, Offset.VisibilityThreshold) .hazeEffect(
val onDragStop: () -> Unit = { hazeState,
animationScope.launch { style = CupertinoMaterials.regular(
launch { progressAnimation.animateTo(0f, progressAnimationSpec) } containerColor = if (isDarkTheme) Color(0xFF1C1C1E).copy(alpha = 0.95f) else Color.White.copy(alpha = 0.95f)
launch { offsetAnimation.animateTo(Offset.Zero, offsetAnimationSpec) } )
} )
}
inspectDragGestures(
onDragStart = { down ->
pressStartPosition = down.position
animationScope.launch {
launch { progressAnimation.animateTo(1f, progressAnimationSpec) }
launch { offsetAnimation.snapTo(Offset.Zero) }
}
},
onDragEnd = { onDragStop() },
onDragCancel = onDragStop
) { _, dragAmount ->
animationScope.launch {
offsetAnimation.snapTo(offsetAnimation.value + dragAmount)
}
}
}
) { ) {
Column(horizontalAlignment = Alignment.Start) { Column(horizontalAlignment = Alignment.CenterHorizontally) {
Spacer(modifier = Modifier.height(28.dp)) androidx.compose.foundation.layout.Spacer(modifier = Modifier.height(24.dp))
Text( Text(
title, title,
style = TextStyle( style = TextStyle(
fontSize = 18.sp, fontSize = 16.sp,
fontWeight = FontWeight.Bold, fontWeight = FontWeight.Bold,
color = contentColor, color = textColor,
fontFamily = FontFamily(Font(R.font.sf_pro)) fontFamily = FontFamily(Font(R.font.sf_pro))
), ),
textAlign = TextAlign.Center,
modifier = Modifier.padding(horizontal = 16.dp) modifier = Modifier.padding(horizontal = 16.dp)
) )
Spacer(modifier = Modifier.height(16.dp)) androidx.compose.foundation.layout.Spacer(modifier = Modifier.height(12.dp))
Text( Text(
message, message,
style = TextStyle( style = TextStyle(
fontSize = 14.sp, fontSize = 14.sp,
color = contentColor.copy(alpha = 0.8f), color = textColor.copy(alpha = 0.8f),
fontFamily = FontFamily(Font(R.font.sf_pro)) fontFamily = FontFamily(Font(R.font.sf_pro))
), ),
textAlign = TextAlign.Center,
modifier = Modifier.padding(horizontal = 16.dp) modifier = Modifier.padding(horizontal = 16.dp)
) )
Spacer(modifier = Modifier.height(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)
Row( Row(
Modifier modifier = Modifier
.padding(horizontal = 12.dp) .fillMaxWidth()
.padding(top = 12.dp, bottom = 24.dp) .height(48.dp)
.fillMaxWidth(), .pointerInput(Unit) {
horizontalArrangement = Arrangement.spacedBy(12.dp), 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,
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
StyledButton( Box(
onClick = onDismiss, modifier = Modifier
backdrop = backdrop, .weight(1f)
surfaceColor = if (isLightTheme) Color(0xFFAAAAAA).copy(0.8f) else Color(0xFF202020).copy(0.8f), .fillMaxHeight()
modifier = Modifier.weight(1f), .background(if (leftPressed) pressedColor else Color.Transparent),
isInteractive = false contentAlignment = Alignment.Center
) { ) {
Text( Text(dismissText, color = accentColor)
dismissText,
style = TextStyle(contentColor, 16.sp)
)
} }
StyledButton( Box(
onClick = onConfirm, modifier = Modifier
backdrop = backdrop, .width(1.dp)
surfaceColor = accentColor, .fillMaxHeight()
modifier = Modifier.weight(1f), .background(Color(0x40888888))
isInteractive = false )
Box(
modifier = Modifier
.weight(1f)
.fillMaxHeight()
.background(if (rightPressed) pressedColor else Color.Transparent),
contentAlignment = Alignment.Center
) { ) {
Text( Text(confirmText, color = accentColor)
confirmText,
style = TextStyle(Color.White, 16.sp)
)
} }
} }
} }
} }
} }
} }
} }

View File

@@ -287,6 +287,7 @@ fun HearingAidScreen(navController: NavController) {
} }
} }
}, },
backdrop = backdrop hazeState = hazeState,
// backdrop = backdrop
) )
} }