diff --git a/modules/common-ui-components-workout-editor/src/main/java/com/ankitsuda/rebound/ui/components/workouteditor/durationeditor/WorkoutDurationEditorDialog.kt b/modules/common-ui-components-workout-editor/src/main/java/com/ankitsuda/rebound/ui/components/workouteditor/durationeditor/WorkoutDurationEditorDialog.kt
index 34dc17e5..75846dfb 100644
--- a/modules/common-ui-components-workout-editor/src/main/java/com/ankitsuda/rebound/ui/components/workouteditor/durationeditor/WorkoutDurationEditorDialog.kt
+++ b/modules/common-ui-components-workout-editor/src/main/java/com/ankitsuda/rebound/ui/components/workouteditor/durationeditor/WorkoutDurationEditorDialog.kt
@@ -21,11 +21,16 @@ import androidx.compose.material.TextButton
import androidx.compose.runtime.*
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.ui.Alignment
+import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.window.Dialog
-import com.ankitsuda.base.utils.toString
+import androidx.compose.ui.window.DialogProperties
+import com.ankitsuda.base.utils.toDurationStr
+import com.ankitsuda.base.utils.toEpochMillis
+import com.ankitsuda.rebound.ui.components.BasicInfoCard
+import com.ankitsuda.rebound.ui.components.BasicInfoCardType
import com.ankitsuda.rebound.ui.components.RButtonStyle2
import com.ankitsuda.rebound.ui.components.datetimepicker.DateTimePicker
import com.ankitsuda.rebound.ui.components.workouteditor.R
@@ -34,6 +39,7 @@ import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.time.format.FormatStyle
+@OptIn(ExperimentalComposeUiApi::class)
@Composable
fun WorkoutDurationEditorDialog(
initialStartDateTime: LocalDateTime,
@@ -77,8 +83,20 @@ fun WorkoutDurationEditorDialog(
getFormattedDateString(endDateTime)
}
+ val durationStr = remember(startDateTime, endDateTime) {
+ (endDateTime.toEpochMillis() - startDateTime.toEpochMillis()).toDurationStr()
+ }
+
+ val errorMessage = if (startDateTime > endDateTime) {
+ stringResource(id = R.string.duration_error_start_longer_than_end)
+ } else {
+ null
+ }
+
+
Dialog(
onDismissRequest = onDismissRequest,
+ properties = DialogProperties(usePlatformDefaultWidth = false)
) {
Surface(
modifier = Modifier
@@ -90,53 +108,79 @@ fun WorkoutDurationEditorDialog(
Column(
modifier = Modifier
.fillMaxWidth()
+// .verticalScroll(state = rememberScrollState())
+ .padding(
+ start = 16.dp,
+ end = 16.dp,
+ top = 16.dp,
+ bottom = 8.dp
+ ),
+ verticalArrangement = Arrangement.spacedBy(12.dp)
) {
- Column(
- modifier =
- Modifier.padding(start = 16.dp, end = 16.dp, top = 16.dp, bottom = 8.dp),
- verticalArrangement = Arrangement.spacedBy(12.dp)
- ) {
- Text(
- text = stringResource(R.string.adjust_duration),
- style = ReboundTheme.typography.h6,
- color = ReboundTheme.colors.onBackground
- )
+ Text(
+ text = stringResource(R.string.adjust_duration),
+ style = ReboundTheme.typography.h6,
+ color = ReboundTheme.colors.onBackground
+ )
+ if (durationStr.isNotBlank()) {
Text(
- text = stringResource(R.string.start_time),
+ text = stringResource(R.string.duration),
style = ReboundTheme.typography.caption,
color = ReboundTheme.colors.onBackground.copy(0.75f)
)
- RButtonStyle2(
- modifier = Modifier.fillMaxWidth(),
- text = formattedStartDateTime,
- onClick = {
- currentPickerActiveFor = 1
- }
- )
-
Text(
- text = stringResource(R.string.end_time),
- style = ReboundTheme.typography.caption,
- color = ReboundTheme.colors.onBackground.copy(0.75f)
+ text = durationStr,
+ style = ReboundTheme.typography.body1,
+ color = ReboundTheme.colors.onBackground
)
+ }
- RButtonStyle2(
+ Text(
+ text = stringResource(R.string.start_time),
+ style = ReboundTheme.typography.caption,
+ color = ReboundTheme.colors.onBackground.copy(0.75f)
+ )
+
+ RButtonStyle2(
+ modifier = Modifier.fillMaxWidth(),
+ text = formattedStartDateTime,
+ onClick = {
+ currentPickerActiveFor = 1
+ }
+ )
+
+ Text(
+ text = stringResource(R.string.end_time),
+ style = ReboundTheme.typography.caption,
+ color = ReboundTheme.colors.onBackground.copy(0.75f)
+ )
+
+ RButtonStyle2(
+ modifier = Modifier.fillMaxWidth(),
+ text = formattedEndDateTime,
+ onClick = {
+ currentPickerActiveFor = 2
+ }
+ )
+
+ errorMessage?.let {
+ BasicInfoCard(
modifier = Modifier.fillMaxWidth(),
- text = formattedEndDateTime,
- onClick = {
- currentPickerActiveFor = 2
- }
- )
-
- DialogButtonsRow(
- onClickSave = ::handleSaveClick,
- onClickCancel = onDismissRequest
+ type = BasicInfoCardType.ERROR,
+ message = it
)
}
+
+ DialogButtonsRow(
+ isSaveEnabled = errorMessage == null,
+ onClickSave = ::handleSaveClick,
+ onClickCancel = onDismissRequest
+ )
}
}
+
}
if (currentPickerActiveFor == 1 || currentPickerActiveFor == 2) {
@@ -161,6 +205,7 @@ fun WorkoutDurationEditorDialog(
@Composable
private fun ColumnScope.DialogButtonsRow(
+ isSaveEnabled: Boolean = true,
onClickSave: () -> Unit,
onClickCancel: () -> Unit
) {
@@ -172,7 +217,7 @@ private fun ColumnScope.DialogButtonsRow(
TextButton(onClick = onClickCancel) {
Text(stringResource(id = R.string.cancel))
}
- TextButton(onClick = onClickSave) {
+ TextButton(enabled = isSaveEnabled, onClick = onClickSave) {
Text(stringResource(id = R.string.save))
}
}
diff --git a/modules/common-ui-components/src/main/java/com/ankitsuda/rebound/ui/components/BasicInfoCard.kt b/modules/common-ui-components/src/main/java/com/ankitsuda/rebound/ui/components/BasicInfoCard.kt
new file mode 100644
index 00000000..06664161
--- /dev/null
+++ b/modules/common-ui-components/src/main/java/com/ankitsuda/rebound/ui/components/BasicInfoCard.kt
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2022 Ankit Suda.
+ *
+ * Licensed under the GNU General Public License v3
+ *
+ * This is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
+ *
+ * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details.
+ */
+
+package com.ankitsuda.rebound.ui.components
+
+import androidx.compose.foundation.layout.*
+import androidx.compose.material.Icon
+import androidx.compose.material.Text
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.outlined.Done
+import androidx.compose.material.icons.outlined.Error
+import androidx.compose.material.icons.outlined.Info
+import androidx.compose.material.icons.outlined.Warning
+import androidx.compose.runtime.Composable
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.vector.ImageVector
+import androidx.compose.ui.unit.dp
+import com.ankitsuda.rebound.ui.theme.ReboundTheme
+
+enum class BasicInfoCardType {
+ INFO,
+ WARNING,
+ ERROR,
+ SUCCESS;
+}
+
+@Composable
+fun BasicInfoCard(
+ modifier: Modifier = Modifier,
+ type: BasicInfoCardType = BasicInfoCardType.INFO,
+ iconEnabled: Boolean = true,
+ customIcon: ImageVector? = null,
+ title: String? = null,
+ message: String,
+) {
+ val icon = customIcon ?: when (type) {
+ BasicInfoCardType.INFO -> Icons.Outlined.Info
+ BasicInfoCardType.WARNING -> Icons.Outlined.Warning
+ BasicInfoCardType.ERROR -> Icons.Outlined.Error
+ BasicInfoCardType.SUCCESS -> Icons.Outlined.Done
+ }
+
+ AppCard(
+ modifier = modifier,
+// backgroundColor = cardColor,
+ ) {
+ Row(
+ modifier = Modifier
+ .fillMaxWidth()
+ .padding(16.dp),
+ horizontalArrangement = Arrangement.spacedBy(16.dp),
+ verticalAlignment = Alignment.CenterVertically
+ ) {
+ if (iconEnabled) {
+ Icon(
+ imageVector = icon, contentDescription = null
+ )
+ }
+ Column(
+ modifier = Modifier.fillMaxWidth(),
+ verticalArrangement = Arrangement.spacedBy(4.dp)
+ ) {
+ title?.let {
+ Text(
+ text = it,
+ style = ReboundTheme.typography.body1.copy(color = ReboundTheme.colors.onBackground)
+ )
+ }
+ Text(
+ text = message,
+ style = ReboundTheme.typography.body2.copy(
+ color = ReboundTheme.colors.onBackground.copy(
+ alpha = 0.75f
+ )
+ )
+ )
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/modules/common-ui-resources/src/main/res/values/strings.xml b/modules/common-ui-resources/src/main/res/values/strings.xml
index 4b66fb4c..e15fd1ce 100644
--- a/modules/common-ui-resources/src/main/res/values/strings.xml
+++ b/modules/common-ui-resources/src/main/res/values/strings.xml
@@ -251,4 +251,5 @@
Adjust duration
Start time
End time
+ Start time is longer than end time
\ No newline at end of file