From 730f6b179f490cdf604551255a3690297468a1dd Mon Sep 17 00:00:00 2001 From: Maciej Procyk Date: Fri, 15 Mar 2024 12:43:42 +0100 Subject: [PATCH] better select visible expiration date --- .../in/procyk/shin/component/ShinComponent.kt | 18 +++++-- .../in/procyk/shin/ui/ShortenRequest.kt | 50 +++++++++++++------ 2 files changed, 51 insertions(+), 17 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/in/procyk/shin/component/ShinComponent.kt b/composeApp/src/commonMain/kotlin/in/procyk/shin/component/ShinComponent.kt index e1bfe51..60babf4 100644 --- a/composeApp/src/commonMain/kotlin/in/procyk/shin/component/ShinComponent.kt +++ b/composeApp/src/commonMain/kotlin/in/procyk/shin/component/ShinComponent.kt @@ -19,6 +19,7 @@ import kotlinx.coroutines.launch import kotlinx.datetime.* import kotlinx.datetime.Clock.System.now import toLocalDate +import toNullable interface ShinComponent : Component { @@ -27,6 +28,8 @@ interface ShinComponent : Component { val expirationDate: Value + val expirationDateVisible: Value + val url: Value val shortenedUrl: Value> @@ -37,6 +40,8 @@ interface ShinComponent : Component { fun onExpirationDateChange(expirationDate: LocalDate?): Boolean + fun onExpirationDateVisibleChange(visible: Boolean) + fun onUrlChange(url: String) fun onProtocolChange(protocol: ShortenedProtocol) @@ -59,6 +64,9 @@ class ShinComponentImpl( private val _expirationDate = MutableStateFlow(tomorrow) override val expirationDate: Value = _expirationDate.asValue() + private val _expirationDateVisible = MutableStateFlow(false) + override val expirationDateVisible: Value = _expirationDateVisible.asValue() + private val _url = MutableStateFlow("") override val url: Value = _url.asValue() @@ -87,6 +95,10 @@ class ShinComponentImpl( } } + override fun onExpirationDateVisibleChange(visible: Boolean) { + _expirationDateVisible.update { visible } + } + override fun onUrlChange(url: String) { val (updatedUrl, updatedProtocol) = ShortenedProtocol.simplifyInputUrl(url) updatedProtocol?.let { protocol -> _protocol.update { protocol } } @@ -107,7 +119,7 @@ class ShinComponentImpl( httpClient.requestShortenedUrl( url = _url.value, shortenedProtocol = _protocol.value, - expirationDate = _expirationDate.value.takeIfVisible(), + expirationDate = _expirationDate.value.takeIfExtraElementsVisibleAnd(expirationDateVisible), onResponse = { response -> val some = Some(response) _shortenedUrl.update { some } @@ -117,8 +129,8 @@ class ShinComponentImpl( } } - private inline fun T.takeIfVisible(): T? = - takeIf { _extraElementsVisible.value } + private inline fun T.takeIfExtraElementsVisibleAnd(value: Value): T? = + takeIf { _extraElementsVisible.value && value.value } } private suspend fun HttpClient.requestShortenedUrl( diff --git a/composeApp/src/commonMain/kotlin/in/procyk/shin/ui/ShortenRequest.kt b/composeApp/src/commonMain/kotlin/in/procyk/shin/ui/ShortenRequest.kt index 617f123..7a5f1ab 100644 --- a/composeApp/src/commonMain/kotlin/in/procyk/shin/ui/ShortenRequest.kt +++ b/composeApp/src/commonMain/kotlin/in/procyk/shin/ui/ShortenRequest.kt @@ -27,6 +27,7 @@ import `in`.procyk.compose.calendar.rememberSelectableCalendarState import `in`.procyk.compose.calendar.year.YearMonth import `in`.procyk.shin.component.ShinComponent import `in`.procyk.shin.model.ShortenedProtocol +import toNullable @Composable internal fun ShortenRequest( @@ -80,7 +81,6 @@ private fun ShortenRequestExtraElements( component: ShinComponent, ) { val extraElementsVisible by component.extraElementsVisible.subscribeAsState() - val expirationDate by component.expirationDate.subscribeAsState() val rotation by animateFloatAsState(if (extraElementsVisible) 180f else 0f) OutlinedButton(onClick = component::onExtraElementsVisibleChange) { Text("Extra Options") @@ -90,11 +90,7 @@ private fun ShortenRequestExtraElements( contentDescription = "Extra Options" ) } - AnimatedVisibility( - visible = extraElementsVisible, - enter = fadeIn() + expandVertically(expandFrom = Alignment.Top), - exit = shrinkVertically(shrinkTowards = Alignment.Top) + fadeOut() - ) { + VerticalAnimatedVisibility(extraElementsVisible) { Column( modifier = Modifier .padding(top = 12.dp) @@ -102,14 +98,27 @@ private fun ShortenRequestExtraElements( verticalArrangement = Arrangement.spacedBy(4.dp, alignment = Alignment.CenterVertically), horizontalAlignment = Alignment.CenterHorizontally, ) { - Text("Expiration Date", style = MaterialTheme.typography.headlineSmall) - val calendarState = rememberSelectableCalendarState( - initialMonth = YearMonth.now(), - minMonth = YearMonth.now(), - initialSelection = listOf(expirationDate), - confirmSelectionChange = { component.onExpirationDateChange(it.singleOrNull()) }, - ) - SelectableCalendar(calendarState = calendarState) + val expirationDate by component.expirationDate.subscribeAsState() + val expirationDateVisible by component.expirationDateVisible.subscribeAsState() + Row( + horizontalArrangement = Arrangement.spacedBy(12.dp, Alignment.CenterHorizontally), + verticalAlignment = Alignment.CenterVertically + ) { + Text("Expiration Date", fontSize = 16.sp) + Switch( + checked = expirationDateVisible, + onCheckedChange = component::onExpirationDateVisibleChange + ) + } + VerticalAnimatedVisibility(expirationDateVisible) { + val calendarState = rememberSelectableCalendarState( + initialMonth = YearMonth.now(), + minMonth = YearMonth.now(), + initialSelection = listOf(expirationDate), + confirmSelectionChange = { component.onExpirationDateChange(it.singleOrNull()) }, + ) + SelectableCalendar(calendarState = calendarState) + } } } } @@ -211,3 +220,16 @@ private fun ProtocolChooser( } } } + +@Composable +private inline fun VerticalAnimatedVisibility( + visible: Boolean, + crossinline content: @Composable() AnimatedVisibilityScope.() -> Unit, +) { + AnimatedVisibility( + visible = visible, + enter = fadeIn() + expandVertically(expandFrom = Alignment.Top), + exit = shrinkVertically(shrinkTowards = Alignment.Top) + fadeOut(), + content = { content() } + ) +}