Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@ import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.heightIn
import androidx.compose.foundation.layout.padding
Expand All @@ -31,10 +29,20 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.drawWithContent
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.ClipOp
import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.Path
import androidx.compose.ui.graphics.drawscope.clipPath
import androidx.compose.ui.graphics.layer.drawLayer
import androidx.compose.ui.graphics.rememberGraphicsLayer
import androidx.compose.ui.input.pointer.PointerEventPass
import androidx.compose.ui.input.pointer.PointerInputChange
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.layout.positionInRoot
import androidx.compose.ui.semantics.Role
import androidx.compose.ui.semantics.heading
import androidx.compose.ui.semantics.semantics
Expand Down Expand Up @@ -69,19 +77,21 @@ fun SettingsScreen(
val graphicsLayer = rememberGraphicsLayer()
val scope = rememberCoroutineScope()
var bitmap by remember { mutableStateOf<ImageBitmap?>(null) }
var bitmapVisibility = remember { Animatable(1f) }
var animationProgress = remember { Animatable(0f) }
var animationCenter by remember { mutableStateOf(Offset.Zero) }

val currentTheme by viewModel.theme.collectAsStateWithLifecycle()

Box(Modifier.fillMaxSize()) {
SettingsScreenImpl(
onBack = onBack,
currentTheme = currentTheme,
onThemeChange = { theme ->
onThemeChange = { theme, center ->
scope.launch {
bitmap = graphicsLayer.toImageBitmap()
bitmapVisibility.snapTo(1f)
bitmapVisibility.animateTo(0f, tween(500, easing = EaseOutQuad))
animationCenter = center
animationProgress.snapTo(0f)
animationProgress.animateTo(1f, tween(5000, easing = EaseOutQuad))
bitmap = null
}
viewModel.setTheme(theme)
Expand All @@ -101,11 +111,21 @@ fun SettingsScreen(
bitmap = bitmap,
contentDescription = null,
modifier = Modifier
.fillMaxHeight(fraction = bitmapVisibility.value)
.fillMaxWidth()
.align(Alignment.BottomCenter),
contentScale = ContentScale.Crop,
alignment = Alignment.BottomCenter
.fillMaxSize()
.drawWithContent {
val path = Path()
// Draw a circle path
path.addOval(
Rect(
center = animationCenter,
radius = size.maxDimension * animationProgress.value
)
)
clipPath(path, clipOp = ClipOp.Difference) {
[email protected]()
}
},
contentScale = ContentScale.Crop
)
}
}
Expand All @@ -115,7 +135,7 @@ fun SettingsScreen(
private fun SettingsScreenImpl(
onBack: () -> Unit,
currentTheme: Theme,
onThemeChange: (Theme) -> Unit,
onThemeChange: (Theme, Offset) -> Unit,
viewModel: SettingsViewModel,
modifier: Modifier = Modifier,
) {
Expand Down Expand Up @@ -164,7 +184,7 @@ private val themes = listOf(Theme.SYSTEM, Theme.DARK, Theme.LIGHT)
@Composable
private fun ThemeSelector(
currentTheme: Theme,
onThemeChange: (Theme) -> Unit,
onThemeChange: (Theme, Offset) -> Unit,
modifier: Modifier = Modifier
) {
Row(
Expand All @@ -175,7 +195,7 @@ private fun ThemeSelector(
ThemeBox(
theme = theme,
isSelected = currentTheme == theme,
onClick = { onThemeChange(theme) },
onClick = { position -> onThemeChange(theme, position) },
modifier = Modifier.weight(1f),
)
}
Expand All @@ -186,15 +206,38 @@ private fun ThemeSelector(
private fun ThemeBox(
theme: Theme,
isSelected: Boolean,
onClick: () -> Unit,
onClick: (Offset) -> Unit,
modifier: Modifier = Modifier
) {
var boxPosition by remember { mutableStateOf(Offset.Zero) }
var clickPosition by remember { mutableStateOf(Offset.Zero) }

Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = modifier
.onGloballyPositioned { coordinates ->
boxPosition = coordinates.positionInRoot()
}
.pointerInput(Unit) {

awaitPointerEventScope {
while (true) {
val eventOnInitialPass = awaitPointerEvent(PointerEventPass.Initial)
val firstRelevantChange: PointerInputChange? =
eventOnInitialPass.changes.firstOrNull { it.pressed }
if (firstRelevantChange != null) {
println("Setting click pos to $clickPosition (based on ${firstRelevantChange.position})")
clickPosition = boxPosition + firstRelevantChange.position
}
}
}
}
.selectable(
selected = isSelected,
onClick = onClick,
onClick = {
println("onClick triggered with $clickPosition")
onClick(clickPosition)
},
role = Role.RadioButton,
indication = null,
interactionSource = remember { MutableInteractionSource() },
Expand Down
Loading