@momo-kits/native-kits 0.114.2-beta.1 → 0.114.2-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (29) hide show
  1. package/compose/build.gradle.kts +1 -0
  2. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +1 -1
  3. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +28 -30
  4. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +1 -1
  5. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +29 -9
  6. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +1 -1
  7. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +4 -4
  8. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +1 -1
  9. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +3 -3
  10. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +3 -3
  11. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +3 -3
  12. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +1 -1
  13. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +3 -3
  14. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +1 -1
  15. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +4 -4
  16. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +1 -1
  17. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +1 -1
  18. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +3 -2
  19. package/compose/src/commonMain/kotlin/vn/momo/kits/components/dateTimePicker/DateTimePicker.kt +178 -0
  20. package/compose/src/commonMain/kotlin/vn/momo/kits/components/dateTimePicker/DateTimePickerExample.kt +90 -0
  21. package/compose/src/commonMain/kotlin/vn/momo/kits/components/dateTimePicker/DateTimePickerTypes.kt +15 -0
  22. package/compose/src/commonMain/kotlin/vn/momo/kits/components/dateTimePicker/DateTimePickerUtils.kt +226 -0
  23. package/compose/src/commonMain/kotlin/vn/momo/kits/components/dateTimePicker/WheelPicker.kt +201 -0
  24. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +84 -124
  25. package/ios/Application/ApplicationEnvironment.swift +17 -9
  26. package/ios/Application/HeaderRight.swift +29 -30
  27. package/ios/Template/TrustBanner/TrustBanner.swift +75 -144
  28. package/local.properties +2 -2
  29. package/package.json +1 -1
@@ -41,6 +41,7 @@ kotlin {
41
41
  implementation(libs.coil.multiplatform.core)
42
42
  implementation(libs.coil.multiplatform.network.ktor)
43
43
  implementation(libs.jetbrains.serialization.json)
44
+ implementation(libs.kotlinx.datetime)
44
45
  }
45
46
  }
46
47
  val androidMain by getting {
@@ -163,7 +163,7 @@ fun FloatingButton(
163
163
  Text(
164
164
  text ?: "",
165
165
  color = Color.White,
166
- style = Typography.actionDefault
166
+ style = Typography.actionDefaultBold
167
167
  )
168
168
  }
169
169
  }
@@ -88,8 +88,32 @@ fun HeaderRight(
88
88
  }
89
89
  }
90
90
 
91
+ private fun getNavigationButtonConfig(
92
+ headerRight: HeaderRightData? = null,
93
+ isFavorite: Boolean = false,
94
+ onPressShortcut: () -> Unit,
95
+ onPressMore: () -> Unit
96
+ ): NavigationButtonConfig {
97
+ val totalTools = headerRight?.tools?.sumOf { it.items.size } ?: 0
98
+ var icon = if (isFavorite) "pin_star_checked" else "pin_star"
99
+ var onClickHandler = onPressShortcut
100
+ if (totalTools > 1 || headerRight?.useMore == true) {
101
+ icon = "navigation_more_icon"
102
+ onClickHandler = onPressMore
103
+ } else if (totalTools == 1 && !headerRight?.tools.isNullOrEmpty()) {
104
+ val singleTool = headerRight?.tools?.first()?.items?.firstOrNull()
105
+ if (singleTool != null) {
106
+ icon = singleTool.icon
107
+ onClickHandler = {
108
+ headerRight.toolCallback?.invoke(singleTool.key)
109
+ }
110
+ }
111
+ }
112
+ return NavigationButtonConfig(icon, onClickHandler)
113
+ }
114
+
91
115
  @Composable
92
- fun ToolkitHeaderRight(headerRight: HeaderRightData? = null) {
116
+ private fun ToolkitHeaderRight(headerRight: HeaderRightData? = null) {
93
117
  var isFavorite by remember { mutableStateOf(false) }
94
118
  val isLoading by remember { mutableStateOf(false) }
95
119
  val api = PlatformApi.current as? ComposeApi
@@ -148,34 +172,8 @@ fun ToolkitHeaderRight(headerRight: HeaderRightData? = null) {
148
172
  }
149
173
  }
150
174
 
151
- fun getNavigationButtonConfig(
152
- tools: List<ToolGroup>? = emptyList(),
153
- useMore: Boolean? = false,
154
- isFavorite: Boolean = false,
155
- onPressShortcut: () -> Unit,
156
- onPressMore: () -> Unit
157
- ): NavigationButtonConfig {
158
- val totalTools = tools?.sumOf { it.items.size } ?: 0
159
- var icon = if (isFavorite) "pin_star_checked" else "pin_star"
160
- var onClickHandler = onPressShortcut
161
- if (totalTools > 1 || useMore == true) {
162
- icon = "navigation_more_icon"
163
- onClickHandler = onPressMore
164
- } else if (totalTools == 1 && !tools.isNullOrEmpty()) {
165
- val singleTool = tools.first().items.firstOrNull()
166
- if (singleTool != null) {
167
- icon = singleTool.icon
168
- onClickHandler = {
169
- headerRight?.toolCallback?.invoke(singleTool.key)
170
- }
171
- }
172
- }
173
- return NavigationButtonConfig(icon, onClickHandler)
174
- }
175
-
176
175
  val navButtonConfig = getNavigationButtonConfig(
177
- headerRight?.tools,
178
- headerRight?.useMore,
176
+ headerRight,
179
177
  isFavorite,
180
178
  ::onPressShortcut,
181
179
  ::onPressMore
@@ -188,7 +186,7 @@ fun ToolkitHeaderRight(headerRight: HeaderRightData? = null) {
188
186
  val toolkitWidth = if (context !== null) 65.dp else 28.dp
189
187
 
190
188
  var isShowShortcut = headerRight?.useShortcut == true
191
- //backup case context null of more icon
189
+
192
190
  if (headerRight?.useMore == true && context == null) {
193
191
  isShowShortcut = false
194
192
  }
@@ -264,7 +262,7 @@ fun NavigationButton(
264
262
  ) {
265
263
  Icon(
266
264
  source = icon,
267
- size = 16.dp
265
+ size = 20.dp
268
266
  )
269
267
  }
270
268
 
@@ -19,7 +19,7 @@ fun HeaderTitle(
19
19
  modifier = Modifier.then(modifier).zIndex(1f),
20
20
  text = title,
21
21
  textAlign = textAlign,
22
- style = Typography.actionS,
22
+ style = Typography.actionSBold,
23
23
  color = color,
24
24
  maxLines = 1
25
25
  )
@@ -9,7 +9,6 @@ import androidx.compose.runtime.remember
9
9
  import androidx.compose.runtime.setValue
10
10
  import androidx.compose.runtime.staticCompositionLocalOf
11
11
  import androidx.compose.ui.unit.Dp
12
- import kotlinx.serialization.Serializable
13
12
  import vn.momo.kits.components.TrustBannerData
14
13
  import vn.momo.kits.const.AppStatusBar
15
14
  import vn.momo.kits.const.AppTheme
@@ -27,20 +26,35 @@ interface ComposeApi {
27
26
  }
28
27
 
29
28
  class Navigator {
30
- fun push(content: @Composable () -> Unit) {}
31
- fun present(content: @Composable () -> Unit) {}
32
- fun reset(content: @Composable () -> Unit) {}
33
- fun pop() {}
34
- fun replace(content: @Composable () -> Unit) {}
35
- fun popToTop() {}
29
+ fun push(content: @Composable () -> Unit) {
30
+ //implement
31
+ }
32
+ fun present(content: @Composable () -> Unit) {
33
+ //implement
34
+ }
35
+ fun reset(content: @Composable () -> Unit) {
36
+ //implement
37
+ }
38
+ fun pop() {
39
+ //implement
40
+ }
41
+ fun replace(content: @Composable () -> Unit) {
42
+ //implement
43
+ }
44
+ fun popToTop() {
45
+ //implement
46
+ }
36
47
  fun showModal(
37
48
  onClose: () -> Unit = {},
38
49
  canBackgroundClose: Boolean = true,
39
50
  content: @Composable () -> Unit,
40
51
  ) {
52
+ //implement
41
53
  }
42
54
 
43
- fun showBottomSheet(content: @Composable () -> Unit) {}
55
+ fun showBottomSheet(content: @Composable () -> Unit) {
56
+ //implement
57
+ }
44
58
  }
45
59
 
46
60
  data class MiniAppContext(
@@ -69,6 +83,10 @@ val AppConfig = staticCompositionLocalOf<KitConfig?> {
69
83
  null
70
84
  }
71
85
 
86
+ val AppLanguage = staticCompositionLocalOf<String?> {
87
+ null
88
+ }
89
+
72
90
  data class KitConfig(
73
91
  val trustBanner: TrustBannerData? = null,
74
92
  val headerBar: String? = null,
@@ -82,6 +100,7 @@ fun ApplicationContainer(
82
100
  statusBarHeight: Dp? = AppStatusBar.current,
83
101
  applicationContext: MiniAppContext? = null,
84
102
  config: KitConfig? = null,
103
+ language: String? = null,
85
104
  content: @Composable () -> Unit,
86
105
  ) {
87
106
  var appTheme by remember { mutableStateOf(theme) }
@@ -110,7 +129,8 @@ fun ApplicationContainer(
110
129
  AppNavigator provides Navigator(),
111
130
  AppStatusBar provides appStatusBarHeight,
112
131
  ApplicationContext provides applicationContext,
113
- AppConfig provides config
132
+ AppConfig provides config,
133
+ AppLanguage provides language
114
134
  ) {
115
135
  content()
116
136
  }
@@ -72,7 +72,7 @@ fun Badge(label: String = "Label", backgroundColor: Color? = null) {
72
72
  Text(
73
73
  text = formatTitle(label),
74
74
  color = Colors.black_01,
75
- style = Typography.actionXxs
75
+ style = Typography.actionXxsBold
76
76
  )
77
77
  }
78
78
  }
@@ -74,10 +74,10 @@ enum class Size(val value: ButtonSpecs) {
74
74
 
75
75
  fun getStyle(size: Size): TextStyle {
76
76
  return when (size.name) {
77
- Size.LARGE.name -> Typography.actionDefault
78
- Size.MEDIUM.name -> Typography.actionS
79
- Size.SMALL.name -> Typography.actionXs
80
- else -> Typography.actionDefault
77
+ Size.LARGE.name -> Typography.actionDefaultBold
78
+ Size.MEDIUM.name -> Typography.actionSBold
79
+ Size.SMALL.name -> Typography.actionXsBold
80
+ else -> Typography.actionDefaultBold
81
81
  }
82
82
  }
83
83
 
@@ -68,7 +68,7 @@ fun CheckBox(
68
68
  if (title.isNotEmpty()) {
69
69
  Spacer(Modifier.size(Spacing.S))
70
70
  Text(
71
- style = Typography.descriptionDefault,
71
+ style = Typography.descriptionDefaultRegular,
72
72
  text = title,
73
73
  )
74
74
  }
@@ -74,9 +74,9 @@ fun Information(
74
74
  }
75
75
  Column(modifier = Modifier.weight(1f)) {
76
76
  if (title != null) {
77
- Text(title, style = Typography.labelDefault)
77
+ Text(title, style = Typography.labelDefaultMedium)
78
78
  }
79
- Text(description, style = Typography.descriptionS)
79
+ Text(description, style = Typography.descriptionDefaultRegular)
80
80
  }
81
81
  if (onPressClose != null && showIconClose) {
82
82
  Icon(source = "navigation_close", size = 16.dp, modifier = Modifier.clickable(onClick = onPressClose))
@@ -84,7 +84,7 @@ fun Information(
84
84
  }
85
85
  if (CTA != null && onPressCTA != null) {
86
86
  Row(modifier = Modifier.padding(top = Spacing.S)) {
87
- Text(CTA, modifier = Modifier.weight(1f).clickable(onClick = onPressCTA), textAlign = TextAlign.End, style = Typography.actionXs, color = color)
87
+ Text(CTA, modifier = Modifier.weight(1f).clickable(onClick = onPressCTA), textAlign = TextAlign.End, style = Typography.actionXsBold, color = color)
88
88
  }
89
89
  }
90
90
  }
@@ -144,7 +144,7 @@ fun ErrorView(errorMessage: String, errorSpacing: Boolean, hintText: String) {
144
144
  )
145
145
  Text(
146
146
  errorMessage.ifEmpty { hintTextDefault },
147
- style = Typography.descriptionS,
147
+ style = Typography.descriptionDefaultRegular,
148
148
  modifier = Modifier.padding(start = Spacing.XS),
149
149
  color = color,
150
150
  )
@@ -261,13 +261,13 @@ fun Input(
261
261
  ) {
262
262
  Text(
263
263
  floatingValue,
264
- style = Typography.labelS,
264
+ style = Typography.labelSMedium,
265
265
  color = floatingTitleColor
266
266
  )
267
267
  if (required) {
268
268
  Text(
269
269
  "*",
270
- style = Typography.labelS,
270
+ style = Typography.labelSMedium,
271
271
  color = AppTheme.current.colors.error.primary,
272
272
  )
273
273
  }
@@ -133,7 +133,7 @@ fun InputOTP(
133
133
  ) {
134
134
  Text(
135
135
  floatingValue,
136
- style = Typography.labelS,
136
+ style = Typography.labelSMedium,
137
137
  color = AppTheme.current.colors.text.hint
138
138
  )
139
139
  }
@@ -164,7 +164,7 @@ fun InputOTP(
164
164
  val textColor =
165
165
  if (value.getOrNull(i) != null) AppTheme.current.colors.text.default else AppTheme.current.colors.text.hint
166
166
  val typo =
167
- if (value.getOrNull(i) != null) Typography.titleS else Typography.descriptionDefault
167
+ if (value.getOrNull(i) != null) Typography.headerDefaultBold else Typography.descriptionDefaultRegular
168
168
  Text(
169
169
  text = value.getOrNull(i)?.toString() ?: "-",
170
170
  color = textColor,
@@ -182,7 +182,7 @@ fun InputOTP(
182
182
  } else {
183
183
  for (i in value.indices) {
184
184
  Text(
185
- style = Typography.titleS,
185
+ style = Typography.headerDefaultBold,
186
186
  text = value[i].toString()
187
187
  )
188
188
  if (i != value.length - 1 || (isFocused && value.length != MAX_LENGTH)) {
@@ -223,7 +223,7 @@ fun InputSearch(
223
223
  if (inputSearchProps.showButtonText) {
224
224
  Text(
225
225
  text = inputSearchProps.buttonText,
226
- style = Typography.actionDefault,
226
+ style = Typography.actionDefaultBold,
227
227
  color = AppTheme.current.colors.text.default,
228
228
  modifier = Modifier.padding(start = Spacing.L).clickable(
229
229
  interactionSource = remember { MutableInteractionSource() },
@@ -129,13 +129,13 @@ fun InputTextArea(
129
129
  ) {
130
130
  Text(
131
131
  floatingValue,
132
- style = Typography.labelS,
132
+ style = Typography.labelSMedium,
133
133
  color = floatingTitleColor
134
134
  )
135
135
  if (required) {
136
136
  Text(
137
137
  "*",
138
- style = Typography.labelS,
138
+ style = Typography.labelSMedium,
139
139
  color = AppTheme.current.colors.error.primary,
140
140
  )
141
141
  }
@@ -213,7 +213,7 @@ fun InputTextArea(
213
213
  ) {
214
214
  Text(
215
215
  "${text.value.length}/$maxLength",
216
- style = Typography.descriptionXs,
216
+ style = Typography.descriptionXsRegular,
217
217
  color = AppTheme.current.colors.text.hint
218
218
  )
219
219
  }
@@ -31,7 +31,7 @@ fun PaginationNumber(
31
31
  modifier = Modifier.padding(horizontal = Spacing.S),
32
32
  text = "${1 + activeIndex}/$dataLength",
33
33
  color = Colors.black_01,
34
- style = Typography.labelDefault
34
+ style = Typography.labelDefaultMedium
35
35
  )
36
36
  }
37
37
  }
@@ -75,7 +75,7 @@ fun PopupNotify(
75
75
  Text(
76
76
  text = description,
77
77
  onTextLayout = { layoutResult.value = it },
78
- style = Typography.paragraphDefault
78
+ style = Typography.bodyDefaultRegular
79
79
  )
80
80
  }
81
81
  }
@@ -86,7 +86,7 @@ fun PopupNotify(
86
86
  Text(
87
87
  text = description,
88
88
  onTextLayout = { layoutResult.value = it },
89
- style = Typography.paragraphDefault
89
+ style = Typography.bodyDefaultRegular
90
90
  )
91
91
  }
92
92
  }
@@ -116,12 +116,12 @@ fun PopupNotify(
116
116
  )
117
117
 
118
118
  Column(modifier = Modifier.padding(Spacing.XL)) {
119
- Text(style = Typography.titleXs, maxLines = 2, text = title, modifier = Modifier.setAutomationId("title_popup_permission"))
119
+ Text(style = Typography.headerDefaultBold, maxLines = 2, text = title, modifier = Modifier.setAutomationId("title_popup_permission"))
120
120
  content(Modifier.padding(top = Spacing.S))
121
121
  if (error.isNotEmpty()) {
122
122
  Text(
123
123
  text = error,
124
- style = Typography.descriptionXs,
124
+ style = Typography.descriptionXsRegular,
125
125
  color = AppTheme.current.colors.text.hint,
126
126
  maxLines = 1,
127
127
  modifier = Modifier.padding(top = Spacing.S)
@@ -57,7 +57,7 @@ fun Radio(
57
57
  )
58
58
  if (label.isNotEmpty()) {
59
59
  Text(
60
- style = Typography.descriptionDefault,
60
+ style = Typography.descriptionDefaultRegular,
61
61
  text = label,
62
62
  )
63
63
  }
@@ -20,7 +20,7 @@ import vn.momo.kits.modifier.setAutomationId
20
20
  fun Text(
21
21
  text: String,
22
22
  color: Color? = null,
23
- style: TextStyle = Typography.paragraphDefault,
23
+ style: TextStyle = Typography.bodyDefaultRegular,
24
24
  textAlign: TextAlign? = TextAlign.Start,
25
25
  modifier: Modifier = Modifier,
26
26
  maxLines: Int = Int.MAX_VALUE,
@@ -20,6 +20,7 @@ import androidx.compose.ui.layout.ContentScale
20
20
  import androidx.compose.ui.unit.dp
21
21
  import androidx.compose.ui.unit.sp
22
22
  import vn.momo.kits.application.AppConfig
23
+ import vn.momo.kits.application.AppLanguage
23
24
  import vn.momo.kits.modifier.noFeedbackClickable
24
25
 
25
26
  val defaultBanner = TrustBannerData(
@@ -62,10 +63,10 @@ fun TrustBanner(
62
63
  serviceName: String = "",
63
64
  screenName: String = "",
64
65
  onPress: ((Map<String, String>) -> Unit)? = null,
65
- trackEvent: ((String, Map<String, String>) -> Unit)? = null,
66
- language: String = "vi"
66
+ trackEvent: ((String, Map<String, String>) -> Unit)? = null
67
67
  ) {
68
68
  val appConfig = AppConfig.current
69
+ val language = AppLanguage.current ?: "vi"
69
70
  val trustBanner = appConfig?.trustBanner ?: defaultBanner
70
71
  val trackParams = mapOf(
71
72
  "service_name" to serviceName,
@@ -0,0 +1,178 @@
1
+ package vn.momo.kits.components.dateTimePicker
2
+
3
+ import androidx.compose.foundation.background
4
+ import androidx.compose.foundation.layout.Column
5
+ import androidx.compose.foundation.layout.Row
6
+ import androidx.compose.foundation.layout.Spacer
7
+ import androidx.compose.foundation.layout.fillMaxWidth
8
+ import androidx.compose.foundation.layout.height
9
+ import androidx.compose.foundation.layout.padding
10
+ import androidx.compose.foundation.layout.width
11
+ import androidx.compose.runtime.Composable
12
+ import androidx.compose.runtime.getValue
13
+ import androidx.compose.runtime.mutableStateOf
14
+ import androidx.compose.runtime.remember
15
+ import androidx.compose.ui.Alignment
16
+ import androidx.compose.ui.Modifier
17
+ import androidx.compose.ui.unit.dp
18
+ import kotlinx.datetime.LocalDateTime
19
+ import kotlinx.datetime.number
20
+ import vn.momo.kits.components.Text
21
+ import vn.momo.kits.const.AppTheme
22
+ import vn.momo.kits.const.Spacing
23
+ import vn.momo.kits.const.Typography
24
+
25
+ private val datePickerHeight = 210.dp
26
+ private val datePickerWithLabelsHeight = 238.dp
27
+
28
+ private fun onPickerChange(
29
+ name: String,
30
+ value: String,
31
+ currentDate: PickerData,
32
+ effectiveMinDate: LocalDateTime,
33
+ effectiveMaxDate: LocalDateTime,
34
+ onChange: (LocalDateTime) -> Unit
35
+ ){
36
+ when (name) {
37
+ "day" -> currentDate.day = value.toInt()
38
+ "month" -> currentDate.month = value.toInt()
39
+ "year" -> currentDate.year = value.toInt()
40
+ "hour" -> currentDate.hour = value.toInt()
41
+ "minute" -> currentDate.minute = value.toInt()
42
+ "timeMode" -> currentDate.timeMode = value
43
+ }
44
+
45
+ if (name == "month" || name == "year") {
46
+ val maxDayOfMonth = when (currentDate.month) {
47
+ 1, 3, 5, 7, 8, 10, 12 -> 31
48
+ 4, 6, 9, 11 -> 30
49
+ 2 -> if (currentDate.year % 4 == 0 && (currentDate.year % 100 != 0 || currentDate.year % 400 == 0)) 29 else 28
50
+ else -> 31
51
+ }
52
+
53
+ if (currentDate.day > maxDayOfMonth) {
54
+ currentDate.day = maxDayOfMonth
55
+ }
56
+ }
57
+
58
+ val changedDate = LocalDateTime(
59
+ year = currentDate.year,
60
+ monthNumber = currentDate.month,
61
+ dayOfMonth = currentDate.day,
62
+ hour = currentDate.hour,
63
+ minute = currentDate.minute,
64
+ second = 0,
65
+ nanosecond = 0
66
+ )
67
+
68
+ if (changedDate in effectiveMinDate..effectiveMaxDate) {
69
+ onChange(changedDate)
70
+ }
71
+ }
72
+
73
+ @Composable
74
+ fun DateTimePicker(
75
+ modifier: Modifier = Modifier,
76
+ format: String = "DD-MM-YYYY",
77
+ minuteInterval: Int = 1,
78
+ onChange: (LocalDateTime) -> Unit,
79
+ selectedValue: LocalDateTime? = null,
80
+ minDate: LocalDateTime? = null,
81
+ maxDate: LocalDateTime? = null,
82
+ arrayLabelTime: List<String> = emptyList()
83
+ ) {
84
+ val now = remember { getCurrentDateTime() }
85
+
86
+ val minDateDefault = remember { createRelativeDate(-10) }
87
+
88
+ val maxDateDefault = remember { createRelativeDate(10) }
89
+
90
+ val effectiveSelectedValue = selectedValue ?: now
91
+ val effectiveMinDate = minDate ?: minDateDefault
92
+ val effectiveMaxDate = maxDate ?: maxDateDefault
93
+
94
+ val initialValue = remember {
95
+ when {
96
+ effectiveSelectedValue < effectiveMinDate -> effectiveMinDate
97
+ effectiveSelectedValue > effectiveMaxDate -> effectiveMaxDate
98
+ else -> effectiveSelectedValue
99
+ }
100
+ }
101
+
102
+ val currentDate by remember {
103
+ mutableStateOf(
104
+ PickerData(
105
+ day = initialValue.dayOfMonth,
106
+ month = initialValue.month.number,
107
+ year = initialValue.year,
108
+ hour = initialValue.hour,
109
+ minute = initialValue.minute
110
+ )
111
+ )
112
+ }
113
+
114
+ val pickerHeight = if (arrayLabelTime.isNotEmpty())
115
+ datePickerWithLabelsHeight else
116
+ datePickerHeight
117
+
118
+ Row(
119
+ modifier = modifier
120
+ .fillMaxWidth()
121
+ .height(pickerHeight)
122
+ .background(AppTheme.current.colors.background.surface)
123
+ .padding(horizontal = Spacing.M),
124
+ verticalAlignment = Alignment.CenterVertically
125
+ ) {
126
+ val dateComponents = getDateComponents(
127
+ format,
128
+ currentDate,
129
+ effectiveMinDate,
130
+ effectiveMaxDate,
131
+ minuteInterval,
132
+ )
133
+ dateComponents.forEachIndexed { index, component ->
134
+ val hasLabel = index < arrayLabelTime.size && arrayLabelTime[index].isNotEmpty()
135
+
136
+ Column(
137
+ horizontalAlignment = Alignment.CenterHorizontally,
138
+ modifier = Modifier.weight(1f)
139
+ ) {
140
+ if (hasLabel) {
141
+ Text(
142
+ text = arrayLabelTime[index],
143
+ style = Typography.actionS,
144
+ modifier = Modifier.padding(bottom = Spacing.S)
145
+ )
146
+ }
147
+
148
+ WheelPicker(
149
+ name = component.name,
150
+ data = component.data,
151
+ selectedData = when (component.name) {
152
+ "day" -> paddingNum(currentDate.day)
153
+ "month" -> paddingNum(currentDate.month)
154
+ "year" -> currentDate.year.toString()
155
+ "hour" -> paddingNum(currentDate.hour)
156
+ "minute" -> paddingNum(currentDate.minute)
157
+ "timeMode" -> currentDate.timeMode
158
+ else -> ""
159
+ },
160
+ onChange = { name, value ->
161
+ onPickerChange(
162
+ name,
163
+ value,
164
+ currentDate,
165
+ effectiveMinDate,
166
+ effectiveMaxDate,
167
+ onChange
168
+ )
169
+ }
170
+ )
171
+ }
172
+
173
+ if (index < dateComponents.size - 1) {
174
+ Spacer(modifier = Modifier.width(Spacing.M))
175
+ }
176
+ }
177
+ }
178
+ }