2026-06-16 20:03:58 -05:00
|
|
|
package app.closer.ui.components
|
2026-06-16 01:24:04 -05:00
|
|
|
|
2026-06-25 14:34:27 -05:00
|
|
|
import app.closer.R
|
2026-06-19 04:04:52 -05:00
|
|
|
import app.closer.ui.theme.closerCardColor
|
2026-06-22 19:18:49 -05:00
|
|
|
import android.provider.Settings
|
|
|
|
|
import androidx.compose.animation.core.FastOutSlowInEasing
|
2026-06-19 04:04:52 -05:00
|
|
|
import androidx.compose.animation.core.RepeatMode
|
|
|
|
|
import androidx.compose.animation.core.animateFloat
|
|
|
|
|
import androidx.compose.animation.core.infiniteRepeatable
|
|
|
|
|
import androidx.compose.animation.core.rememberInfiniteTransition
|
|
|
|
|
import androidx.compose.animation.core.tween
|
2026-06-25 14:34:27 -05:00
|
|
|
import androidx.compose.foundation.Image
|
2026-06-16 01:24:04 -05:00
|
|
|
import androidx.compose.foundation.layout.Arrangement
|
|
|
|
|
import androidx.compose.foundation.layout.Column
|
|
|
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
|
|
|
import androidx.compose.foundation.layout.padding
|
2026-06-22 19:18:49 -05:00
|
|
|
import androidx.compose.foundation.layout.size
|
2026-06-16 01:24:04 -05:00
|
|
|
import androidx.compose.material3.MaterialTheme
|
|
|
|
|
import androidx.compose.material3.Text
|
|
|
|
|
import androidx.compose.runtime.Composable
|
2026-06-22 19:18:49 -05:00
|
|
|
import androidx.compose.runtime.remember
|
|
|
|
|
import androidx.compose.ui.Alignment
|
2026-06-16 01:24:04 -05:00
|
|
|
import androidx.compose.ui.Modifier
|
2026-06-22 19:18:49 -05:00
|
|
|
import androidx.compose.ui.graphics.graphicsLayer
|
|
|
|
|
import androidx.compose.ui.platform.LocalContext
|
2026-06-25 14:34:27 -05:00
|
|
|
import androidx.compose.ui.res.painterResource
|
2026-06-22 19:18:49 -05:00
|
|
|
import androidx.compose.ui.semantics.clearAndSetSemantics
|
2026-06-16 01:24:04 -05:00
|
|
|
import androidx.compose.ui.text.style.TextAlign
|
2026-06-22 19:18:49 -05:00
|
|
|
import androidx.compose.ui.unit.Dp
|
2026-06-16 01:24:04 -05:00
|
|
|
import androidx.compose.ui.unit.dp
|
|
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
|
fun LoadingState(
|
|
|
|
|
message: String = "Loading…",
|
|
|
|
|
modifier: Modifier = Modifier
|
|
|
|
|
) {
|
2026-06-19 04:04:52 -05:00
|
|
|
CloserCard(
|
2026-06-16 01:24:04 -05:00
|
|
|
modifier = modifier.fillMaxWidth(),
|
2026-06-19 04:04:52 -05:00
|
|
|
containerColor = closerCardColor(alpha = 0.8f)
|
2026-06-16 01:24:04 -05:00
|
|
|
) {
|
|
|
|
|
Column(
|
|
|
|
|
modifier = Modifier
|
|
|
|
|
.fillMaxWidth()
|
2026-06-19 04:04:52 -05:00
|
|
|
.padding(CloserSpacing.Xxxl),
|
2026-06-22 19:18:49 -05:00
|
|
|
horizontalAlignment = Alignment.CenterHorizontally,
|
2026-06-19 04:04:52 -05:00
|
|
|
verticalArrangement = Arrangement.spacedBy(CloserSpacing.Md)
|
2026-06-16 01:24:04 -05:00
|
|
|
) {
|
2026-06-22 19:18:49 -05:00
|
|
|
CloserHeartLoader()
|
2026-06-16 01:24:04 -05:00
|
|
|
Text(
|
|
|
|
|
text = message,
|
|
|
|
|
style = MaterialTheme.typography.bodyMedium,
|
2026-06-17 22:44:14 -05:00
|
|
|
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
2026-06-16 01:24:04 -05:00
|
|
|
textAlign = TextAlign.Center
|
|
|
|
|
)
|
2026-06-19 20:24:50 -05:00
|
|
|
BrandMessageRotator(
|
|
|
|
|
color = MaterialTheme.colorScheme.onSurfaceVariant.copy(alpha = 0.82f),
|
|
|
|
|
style = MaterialTheme.typography.bodySmall
|
|
|
|
|
)
|
2026-06-16 01:24:04 -05:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-06-19 04:04:52 -05:00
|
|
|
|
|
|
|
|
@Composable
|
2026-06-22 19:18:49 -05:00
|
|
|
fun CloserHeartLoader(
|
|
|
|
|
modifier: Modifier = Modifier,
|
|
|
|
|
size: Dp = 76.dp
|
2026-06-25 14:34:27 -05:00
|
|
|
) {
|
|
|
|
|
CloserMarkLoader(modifier = modifier, size = size)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
|
fun CloserMarkLoader(
|
|
|
|
|
modifier: Modifier = Modifier,
|
|
|
|
|
size: Dp = 76.dp
|
2026-06-22 19:18:49 -05:00
|
|
|
) {
|
|
|
|
|
val context = LocalContext.current
|
|
|
|
|
val reducedMotion = remember {
|
|
|
|
|
Settings.Global.getFloat(
|
|
|
|
|
context.contentResolver,
|
|
|
|
|
Settings.Global.ANIMATOR_DURATION_SCALE,
|
|
|
|
|
1f
|
|
|
|
|
) == 0f
|
|
|
|
|
}
|
2026-06-25 14:34:27 -05:00
|
|
|
val transition = rememberInfiniteTransition(label = "closerMarkLoader")
|
2026-06-22 19:18:49 -05:00
|
|
|
val animatedPulse = transition.animateFloat(
|
|
|
|
|
initialValue = 0.96f,
|
|
|
|
|
targetValue = 1.04f,
|
|
|
|
|
animationSpec = infiniteRepeatable(
|
|
|
|
|
animation = tween(durationMillis = 900, easing = FastOutSlowInEasing),
|
|
|
|
|
repeatMode = RepeatMode.Reverse
|
2026-06-19 04:04:52 -05:00
|
|
|
),
|
2026-06-25 14:34:27 -05:00
|
|
|
label = "closerMarkPulse"
|
2026-06-19 04:04:52 -05:00
|
|
|
)
|
2026-06-22 19:18:49 -05:00
|
|
|
val pulse = if (reducedMotion) 1f else animatedPulse.value
|
|
|
|
|
|
2026-06-25 14:34:27 -05:00
|
|
|
Image(
|
|
|
|
|
painter = painterResource(R.drawable.closer_mark_loader),
|
|
|
|
|
contentDescription = null,
|
2026-06-19 04:04:52 -05:00
|
|
|
modifier = modifier
|
2026-06-22 19:18:49 -05:00
|
|
|
.size(size)
|
|
|
|
|
.graphicsLayer {
|
|
|
|
|
scaleX = pulse
|
|
|
|
|
scaleY = pulse
|
|
|
|
|
}
|
|
|
|
|
.clearAndSetSemantics {}
|
2026-06-25 14:34:27 -05:00
|
|
|
)
|
2026-06-19 04:04:52 -05:00
|
|
|
}
|