mirror of
https://github.com/kavishdevar/librepods.git
synced 2026-04-22 14:21:39 +00:00
android: bring back original confirmation dialog
too lazy to fix/implement properly the glassy one
This commit is contained in:
@@ -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)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -287,6 +287,7 @@ fun HearingAidScreen(navController: NavController) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
backdrop = backdrop
|
hazeState = hazeState,
|
||||||
|
// backdrop = backdrop
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user