diff --git a/clock/src/main/java/com/maxkeppeler/sheets/clock/ClockState.kt b/clock/src/main/java/com/maxkeppeler/sheets/clock/ClockState.kt index 0d8c6018..290a5729 100644 --- a/clock/src/main/java/com/maxkeppeler/sheets/clock/ClockState.kt +++ b/clock/src/main/java/com/maxkeppeler/sheets/clock/ClockState.kt @@ -53,6 +53,9 @@ internal class ClockState( var timeTextValues by mutableStateOf(getTimeInTextValues()) val keys by mutableStateOf(getInputKeys()) var disabledKeys by mutableStateOf(getCurrentDisabledKeys()) + var valid by mutableStateOf(isValid()) + + private fun isValid(): Boolean = config.boundary?.let { time in it } ?: true private fun isInit24HourFormat(): Boolean { return config.is24HourFormat ?: DateFormat.is24HourFormat(context) @@ -93,6 +96,11 @@ internal class ClockState( private fun refreshTimeValue() { time = getTimeOfTextValues() + checkValid() + } + + private fun checkValid() { + valid = isValid() } fun onChange12HourFormatValue(newIsAm: Boolean) { diff --git a/clock/src/main/java/com/maxkeppeler/sheets/clock/ClockView.kt b/clock/src/main/java/com/maxkeppeler/sheets/clock/ClockView.kt index 81017548..0b63418a 100644 --- a/clock/src/main/java/com/maxkeppeler/sheets/clock/ClockView.kt +++ b/clock/src/main/java/com/maxkeppeler/sheets/clock/ClockView.kt @@ -28,6 +28,7 @@ import com.maxkeppeker.sheets.core.views.base.FrameBase import com.maxkeppeler.sheets.clock.models.ClockConfig import com.maxkeppeler.sheets.clock.models.ClockSelection import com.maxkeppeler.sheets.clock.views.KeyboardComponent +import com.maxkeppeler.sheets.clock.views.TimeHintComponent import com.maxkeppeler.sheets.clock.views.TimeValueComponent /** @@ -61,6 +62,10 @@ fun ClockView( onGroupClick = clockState::onValueGroupClick, onAm = clockState::onChange12HourFormatValue, ) + TimeHintComponent( + valid = clockState.valid, + boundary = config.boundary, + ) KeyboardComponent( config = config, keys = clockState.keys, @@ -75,6 +80,7 @@ fun ClockView( selection = selection, onNegative = { selection.onNegativeClick?.invoke() }, onPositive = clockState::onFinish, + onPositiveValid = clockState.valid, onClose = sheetState::finish ) } diff --git a/clock/src/main/java/com/maxkeppeler/sheets/clock/models/ClockConfig.kt b/clock/src/main/java/com/maxkeppeler/sheets/clock/models/ClockConfig.kt index af961e9b..e0ee3974 100644 --- a/clock/src/main/java/com/maxkeppeler/sheets/clock/models/ClockConfig.kt +++ b/clock/src/main/java/com/maxkeppeler/sheets/clock/models/ClockConfig.kt @@ -23,11 +23,13 @@ import java.time.LocalTime /** * The general configuration for the clock dialog. * @param defaultTime The default time. + * @param boundary Optional [ClosedRange] of [LocalTime] representing the time boundary * @param is24HourFormat If the 24HourFormat is enabled. * @param icons The style of icons that are used for dialog/ view-specific icons. */ data class ClockConfig( val defaultTime: LocalTime? = null, + val boundary: ClosedRange? = null, val is24HourFormat: Boolean? = null, override val icons: LibIcons = DEFAULT_ICON_STYLE, ) : BaseConfigs() \ No newline at end of file diff --git a/clock/src/main/java/com/maxkeppeler/sheets/clock/views/TimeHintComponent.kt b/clock/src/main/java/com/maxkeppeler/sheets/clock/views/TimeHintComponent.kt new file mode 100644 index 00000000..509c284c --- /dev/null +++ b/clock/src/main/java/com/maxkeppeler/sheets/clock/views/TimeHintComponent.kt @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2022. Maximilian Keppeler (https://www.maxkeppeler.com) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +@file:OptIn(ExperimentalTextApi::class, ExperimentalMaterial3Api::class) + +package com.maxkeppeler.sheets.clock.views + +import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Row +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.material3.ExperimentalMaterial3Api +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.dimensionResource +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.ExperimentalTextApi +import androidx.compose.ui.text.style.TextAlign +import com.maxkeppeler.sheets.clock.R +import java.time.LocalTime +import java.time.format.DateTimeFormatter +import java.time.format.FormatStyle +import com.maxkeppeler.sheets.core.R as RC + +/** + * A component that displays a hint that the current time is out of the defined boundary, if set and invalid. + * + * @param valid Boolean representing the validity of the time + * @param boundary Optional [ClosedRange] of [LocalTime] representing the time boundary + */ +@Composable +internal fun TimeHintComponent( + valid: Boolean, + boundary: ClosedRange? = null +) { + if (valid || boundary == null) return + + val formatter = remember { DateTimeFormatter.ofLocalizedTime(FormatStyle.SHORT) } + val startTime = remember(boundary) { boundary.start.format(formatter) } + val endTime = remember(boundary) { boundary.endInclusive.format(formatter) } + + Row( + modifier = Modifier + .fillMaxWidth() + .padding(bottom = dimensionResource(RC.dimen.scd_normal_150)), + horizontalArrangement = Arrangement.Center, + verticalAlignment = Alignment.Bottom + ) { + Text( + text = stringResource(R.string.scd_clock_dialog_boundary_hint, startTime, endTime), + textAlign = TextAlign.Center, + style = MaterialTheme.typography.bodySmall + ) + } +} \ No newline at end of file diff --git a/clock/src/main/res/values-de-rDE/strings.xml b/clock/src/main/res/values-de-rDE/strings.xml index 0f049201..292249e6 100644 --- a/clock/src/main/res/values-de-rDE/strings.xml +++ b/clock/src/main/res/values-de-rDE/strings.xml @@ -9,5 +9,6 @@ PM Nächster Wert Letzter Wert + Muss zwischen %s und %s sein \ No newline at end of file diff --git a/clock/src/main/res/values/strings.xml b/clock/src/main/res/values/strings.xml index 198e64b7..2eec9ee5 100644 --- a/clock/src/main/res/values/strings.xml +++ b/clock/src/main/res/values/strings.xml @@ -10,5 +10,6 @@ PM Next value Previous value + Must be between %s and %s \ No newline at end of file