@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.
- package/compose/build.gradle.kts +1 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +28 -30
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +29 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +4 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +3 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +3 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +3 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +3 -3
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +4 -4
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +1 -1
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +3 -2
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/dateTimePicker/DateTimePicker.kt +178 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/dateTimePicker/DateTimePickerExample.kt +90 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/dateTimePicker/DateTimePickerTypes.kt +15 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/dateTimePicker/DateTimePickerUtils.kt +226 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/dateTimePicker/WheelPicker.kt +201 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +84 -124
- package/ios/Application/ApplicationEnvironment.swift +17 -9
- package/ios/Application/HeaderRight.swift +29 -30
- package/ios/Template/TrustBanner/TrustBanner.swift +75 -144
- package/local.properties +2 -2
- package/package.json +1 -1
package/compose/build.gradle.kts
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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 =
|
|
265
|
+
size = 20.dp
|
|
268
266
|
)
|
|
269
267
|
}
|
|
270
268
|
|
|
@@ -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
|
-
|
|
32
|
-
|
|
33
|
-
fun
|
|
34
|
-
|
|
35
|
-
|
|
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
|
}
|
|
@@ -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.
|
|
78
|
-
Size.MEDIUM.name -> Typography.
|
|
79
|
-
Size.SMALL.name -> Typography.
|
|
80
|
-
else -> Typography.
|
|
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
|
|
|
@@ -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.
|
|
77
|
+
Text(title, style = Typography.labelDefaultMedium)
|
|
78
78
|
}
|
|
79
|
-
Text(description, style = Typography.
|
|
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.
|
|
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.
|
|
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.
|
|
264
|
+
style = Typography.labelSMedium,
|
|
265
265
|
color = floatingTitleColor
|
|
266
266
|
)
|
|
267
267
|
if (required) {
|
|
268
268
|
Text(
|
|
269
269
|
"*",
|
|
270
|
-
style = Typography.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
132
|
+
style = Typography.labelSMedium,
|
|
133
133
|
color = floatingTitleColor
|
|
134
134
|
)
|
|
135
135
|
if (required) {
|
|
136
136
|
Text(
|
|
137
137
|
"*",
|
|
138
|
-
style = Typography.
|
|
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.
|
|
216
|
+
style = Typography.descriptionXsRegular,
|
|
217
217
|
color = AppTheme.current.colors.text.hint
|
|
218
218
|
)
|
|
219
219
|
}
|
|
@@ -75,7 +75,7 @@ fun PopupNotify(
|
|
|
75
75
|
Text(
|
|
76
76
|
text = description,
|
|
77
77
|
onTextLayout = { layoutResult.value = it },
|
|
78
|
-
style = Typography.
|
|
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.
|
|
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.
|
|
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.
|
|
124
|
+
style = Typography.descriptionXsRegular,
|
|
125
125
|
color = AppTheme.current.colors.text.hint,
|
|
126
126
|
maxLines = 1,
|
|
127
127
|
modifier = Modifier.padding(top = Spacing.S)
|
|
@@ -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.
|
|
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,
|
package/compose/src/commonMain/kotlin/vn/momo/kits/components/dateTimePicker/DateTimePicker.kt
ADDED
|
@@ -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
|
+
}
|