@momo-kits/native-kits 0.114.2-pu.1 → 0.117.1-beta.2

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.
@@ -4,6 +4,7 @@ import androidx.compose.runtime.Composable
4
4
  import androidx.compose.ui.Modifier
5
5
  import androidx.compose.ui.graphics.Color
6
6
  import androidx.compose.ui.text.style.TextAlign
7
+ import androidx.compose.ui.unit.sp
7
8
  import androidx.compose.ui.zIndex
8
9
  import vn.momo.kits.components.Text
9
10
  import vn.momo.kits.const.Typography
@@ -19,7 +20,10 @@ fun HeaderTitle(
19
20
  modifier = Modifier.then(modifier).zIndex(1f),
20
21
  text = title,
21
22
  textAlign = textAlign,
22
- style = Typography.actionSBold,
23
+ style = Typography.actionSBold.copy(
24
+ fontSize = 15.sp,
25
+ lineHeight = 22.sp,
26
+ ),
23
27
  color = color,
24
28
  maxLines = 1
25
29
  )
@@ -11,6 +11,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
11
11
  import androidx.compose.runtime.Composable
12
12
  import androidx.compose.ui.Alignment
13
13
  import androidx.compose.ui.Modifier
14
+ import androidx.compose.ui.graphics.Color
14
15
  import androidx.compose.ui.unit.dp
15
16
  import vn.momo.kits.const.AppTheme
16
17
  import vn.momo.kits.const.Colors
@@ -27,8 +28,8 @@ fun CheckBox(
27
28
  title: String = "",
28
29
  ) {
29
30
  var borderColor = AppTheme.current.colors.text.default
30
- var backgroundColor = AppTheme.current.colors.background.surface
31
- val iconSource = if (indeterminate) "minus" else "ic_checked"
31
+ var backgroundColor = Color.Transparent
32
+ val iconSource = if (indeterminate) "navigation_minus" else "ic_checked"
32
33
 
33
34
  if (checked) {
34
35
  borderColor = AppTheme.current.colors.primary
@@ -36,7 +37,7 @@ fun CheckBox(
36
37
  }
37
38
  if (disabled) {
38
39
  borderColor = AppTheme.current.colors.border.disable
39
- backgroundColor = AppTheme.current.colors.background.surface
40
+ backgroundColor = Color.Transparent
40
41
  if (checked) {
41
42
  borderColor = AppTheme.current.colors.background.tonal
42
43
  backgroundColor = AppTheme.current.colors.background.tonal
@@ -20,6 +20,7 @@ import androidx.compose.foundation.text.BasicTextField
20
20
  import androidx.compose.foundation.text.KeyboardOptions
21
21
  import androidx.compose.material3.CircularProgressIndicator
22
22
  import androidx.compose.runtime.Composable
23
+ import androidx.compose.runtime.MutableState
23
24
  import androidx.compose.runtime.getValue
24
25
  import androidx.compose.runtime.mutableStateOf
25
26
  import androidx.compose.runtime.remember
@@ -28,11 +29,13 @@ import androidx.compose.ui.Alignment
28
29
  import androidx.compose.ui.Modifier
29
30
  import androidx.compose.ui.focus.onFocusChanged
30
31
  import androidx.compose.ui.graphics.Color
32
+ import androidx.compose.ui.semantics.contentDescription
33
+ import androidx.compose.ui.semantics.semantics
34
+ import androidx.compose.ui.semantics.testTag
31
35
  import androidx.compose.ui.text.TextStyle
32
36
  import androidx.compose.ui.text.font.FontWeight
33
37
  import androidx.compose.ui.text.input.KeyboardType
34
38
  import androidx.compose.ui.text.input.PasswordVisualTransformation
35
- import androidx.compose.ui.text.input.TextFieldValue
36
39
  import androidx.compose.ui.text.input.VisualTransformation
37
40
  import androidx.compose.ui.unit.Dp
38
41
  import androidx.compose.ui.unit.dp
@@ -151,7 +154,7 @@ fun ErrorView(errorMessage: String, errorSpacing: Boolean, hintText: String) {
151
154
 
152
155
  @Composable
153
156
  fun Input(
154
- text: String = "",
157
+ text: MutableState<String> = remember { mutableStateOf("") },
155
158
  floatingValue: String = "",
156
159
  floatingValueColor: Color = AppTheme.current.colors.text.hint,
157
160
  floatingIcon: String = "",
@@ -178,10 +181,6 @@ fun Input(
178
181
  keyboardType: KeyboardType = KeyboardType.Text,
179
182
  modifier: Modifier = Modifier,
180
183
  ) {
181
- var textFieldValueState by remember { mutableStateOf(TextFieldValue(text = text)) }
182
- val textFieldValue = textFieldValueState.copy(text = text)
183
- var lastTextValue by remember(text) { mutableStateOf(text) }
184
-
185
184
  var isFocused by remember { mutableStateOf(false) }
186
185
  var passHidden by remember { mutableStateOf(false) }
187
186
  var isBlurred = false
@@ -210,10 +209,10 @@ fun Input(
210
209
  modifier = modifier.setAutomationId(testId)
211
210
  ) {
212
211
  BasicTextField(
213
- value = text,
214
212
  enabled = !disabled,
215
213
  readOnly = readOnly,
216
214
  singleLine = true,
215
+ value = text.value,
217
216
  textStyle = TextStyle(
218
217
  color = textColor,
219
218
  fontSize = 16.sp,
@@ -230,15 +229,7 @@ fun Input(
230
229
  if (!it.isFocused && isBlurred) onBlur()
231
230
  if (it.isFocused && !isBlurred) isBlurred = true
232
231
  },
233
- onValueChange = { newValue ->
234
- textFieldValueState.copy(text = newValue)
235
- val stringChangedSinceLastInvocation = lastTextValue != newValue
236
- lastTextValue = newValue
237
-
238
- if (stringChangedSinceLastInvocation) {
239
- onChangeText(newValue)
240
- }
241
- },
232
+ onValueChange = onChangeText,
242
233
  decorationBox = { innerTextField ->
243
234
  // Floating Icon
244
235
  if (floatingValue.isNotEmpty() || floatingIcon.isNotEmpty()) {
@@ -300,7 +291,7 @@ fun Input(
300
291
  )
301
292
  }
302
293
  Box(Modifier.weight(1f)) {
303
- if (textFieldValue.text.isEmpty()) {
294
+ if (text.value.isEmpty()) {
304
295
  Text(
305
296
  text = placeholder,
306
297
  style = TextStyle(
@@ -313,7 +304,7 @@ fun Input(
313
304
  }
314
305
  innerTextField()
315
306
  }
316
- if (isFocused && textFieldValue.text.isNotEmpty()) {
307
+ if (isFocused && text.value.isNotEmpty()) {
317
308
  Row {
318
309
  Spacer(Modifier.width(Spacing.XS))
319
310
  Icon(
@@ -321,10 +312,7 @@ fun Input(
321
312
  size = 16.dp,
322
313
  color = AppTheme.current.colors.text.hint,
323
314
  modifier = Modifier.clickable(
324
- onClick = {
325
- onChangeText("")
326
- textFieldValueState = TextFieldValue(text = "")
327
- },
315
+ onClick = { text.value = "" },
328
316
  interactionSource = remember { MutableInteractionSource() },
329
317
  indication = null
330
318
  )
@@ -13,6 +13,7 @@ import androidx.compose.foundation.layout.padding
13
13
  import androidx.compose.foundation.layout.wrapContentSize
14
14
  import androidx.compose.foundation.shape.RoundedCornerShape
15
15
  import androidx.compose.runtime.Composable
16
+ import androidx.compose.runtime.MutableState
16
17
  import androidx.compose.runtime.getValue
17
18
  import androidx.compose.runtime.mutableStateOf
18
19
  import androidx.compose.runtime.remember
@@ -32,7 +33,7 @@ import vn.momo.kits.const.Typography
32
33
 
33
34
  @Composable
34
35
  fun InputDropDown(
35
- text: String = "",
36
+ value: MutableState<String> = remember { mutableStateOf("") },
36
37
  floatingValue: String = "",
37
38
  floatingValueColor: Color = AppTheme.current.colors.text.hint,
38
39
  floatingIcon: String = "",
@@ -139,12 +140,12 @@ fun InputDropDown(
139
140
  }
140
141
  Box(Modifier.weight(1f)) {
141
142
  Text(
142
- text = text.ifEmpty { placeholder },
143
+ text = value.value.ifEmpty { placeholder },
143
144
  style = TextStyle(
144
145
  fontSize = 16.sp,
145
146
  lineHeight = 24.sp
146
147
  ),
147
- color = if (text.isEmpty()) placeholderColor else textColor
148
+ color = if (value.value.isEmpty()) placeholderColor else textColor
148
149
  )
149
150
  }
150
151
  RenderRightIcon(
@@ -18,6 +18,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
18
18
  import androidx.compose.foundation.text.BasicTextField
19
19
  import androidx.compose.foundation.text.KeyboardOptions
20
20
  import androidx.compose.runtime.Composable
21
+ import androidx.compose.runtime.MutableState
21
22
  import androidx.compose.runtime.getValue
22
23
  import androidx.compose.runtime.mutableStateOf
23
24
  import androidx.compose.runtime.remember
@@ -62,7 +63,7 @@ class CustomConverter : VisualTransformation {
62
63
 
63
64
  @Composable
64
65
  fun InputMoney(
65
- text: String = "0",
66
+ text: MutableState<String> = remember { mutableStateOf("0") },
66
67
  floatingValue: String = "",
67
68
  floatingValueColor: Color = AppTheme.current.colors.text.hint,
68
69
  floatingIcon: String = "",
@@ -114,7 +115,7 @@ fun InputMoney(
114
115
  BasicTextField(
115
116
  enabled = !disabled,
116
117
  singleLine = true,
117
- value = text,
118
+ value = text.value,
118
119
  textStyle = TextStyle(
119
120
  color = textColor,
120
121
  fontSize = 20.sp,
@@ -194,7 +195,7 @@ fun InputMoney(
194
195
  )
195
196
  }
196
197
  Box(Modifier.weight(9f).padding(start = 0.dp)) {
197
- if (text.isEmpty()) {
198
+ if (text.value.isEmpty()) {
198
199
  Text(
199
200
  text = placeholder,
200
201
  style = TextStyle(
@@ -208,7 +209,7 @@ fun InputMoney(
208
209
  innerTextField()
209
210
  }
210
211
  }
211
- if (isFocused && text.isNotEmpty()) {
212
+ if (isFocused && text.value.isNotEmpty()) {
212
213
  Row {
213
214
  Spacer(Modifier.width(Spacing.XS))
214
215
  Icon(
@@ -216,7 +217,7 @@ fun InputMoney(
216
217
  size = 16.dp,
217
218
  color = AppTheme.current.colors.text.hint,
218
219
  modifier = Modifier.clickable(
219
- onClick = { onChangeText("") },
220
+ onClick = { text.value = "" },
220
221
  interactionSource = remember { MutableInteractionSource() },
221
222
  indication = null
222
223
  )
@@ -87,12 +87,12 @@ fun InputOTP(
87
87
  dataType: String = "number",
88
88
  modifier: Modifier = Modifier
89
89
  ) {
90
- val MAX_LENGTH = 10
90
+ val maxLength = 10
91
91
  var isFocused by remember { mutableStateOf(false) }
92
92
  var isBlurred = false
93
93
 
94
94
  val handleChangeText: (String) -> Unit = { text ->
95
- if (text.length <= MAX_LENGTH &&
95
+ if (text.length <= maxLength &&
96
96
  (dataType != "number" || !text.any { !it.isDigit() }) &&
97
97
  (text.length < value.length || value.length < text.length)
98
98
  ) {
@@ -115,7 +115,7 @@ fun InputOTP(
115
115
  if (!it.isFocused && isBlurred) onBlur()
116
116
  if (it.isFocused && !isBlurred) isBlurred = true
117
117
  },
118
- decorationBox = { innerTextField ->
118
+ decorationBox = { _ ->
119
119
  Box {
120
120
  if (floatingValue.isNotEmpty()) {
121
121
  Box(
@@ -19,6 +19,7 @@ import androidx.compose.foundation.text.KeyboardActions
19
19
  import androidx.compose.foundation.text.KeyboardOptions
20
20
  import androidx.compose.material3.CircularProgressIndicator
21
21
  import androidx.compose.runtime.Composable
22
+ import androidx.compose.runtime.MutableState
22
23
  import androidx.compose.runtime.getValue
23
24
  import androidx.compose.runtime.mutableStateOf
24
25
  import androidx.compose.runtime.remember
@@ -77,7 +78,7 @@ fun RenderRightIconSearch(
77
78
  }
78
79
 
79
80
  data class InputSearchProps(
80
- val text: String = "",
81
+ val text: MutableState<String>,
81
82
  val buttonText: String = "",
82
83
  val showButtonText: Boolean = false,
83
84
  val placeholder: String = "",
@@ -105,7 +106,7 @@ data class InputSearchProps(
105
106
  @Composable
106
107
  fun InputSearch(
107
108
  inputSearchProps: InputSearchProps = InputSearchProps(
108
- text = "",
109
+ text = remember { mutableStateOf("") },
109
110
  iconColor = AppTheme.current.colors.text.default
110
111
  ),
111
112
  ) {
@@ -126,7 +127,7 @@ fun InputSearch(
126
127
  BasicTextField(
127
128
  enabled = !inputSearchProps.disabled,
128
129
  singleLine = true,
129
- value = inputSearchProps.text,
130
+ value = inputSearchProps.text.value,
130
131
  textStyle = TextStyle(
131
132
  color = textColor,
132
133
  fontSize = 14.sp,
@@ -174,7 +175,7 @@ fun InputSearch(
174
175
  color = AppTheme.current.colors.text.hint
175
176
  )
176
177
  Box(Modifier.weight(1f)) {
177
- if (inputSearchProps.text.isEmpty()) {
178
+ if (inputSearchProps.text.value.isEmpty()) {
178
179
  Text(
179
180
  text = inputSearchProps.placeholder,
180
181
  style = TextStyle(
@@ -189,7 +190,7 @@ fun InputSearch(
189
190
  }
190
191
  innerTextField()
191
192
  }
192
- if (inputSearchProps.clearCondition?.invoke() == true || (isFocused && inputSearchProps.text.isNotEmpty())) {
193
+ if (inputSearchProps.clearCondition?.invoke() == true || (isFocused && inputSearchProps.text.value.isNotEmpty())) {
193
194
  Row {
194
195
  Spacer(Modifier.width(Spacing.XS))
195
196
  Icon(
@@ -198,7 +199,7 @@ fun InputSearch(
198
199
  color = AppTheme.current.colors.text.hint,
199
200
  modifier = Modifier.clickable(
200
201
  onClick = {
201
- inputSearchProps.onChangeText("")
202
+ inputSearchProps.text.value = ""
202
203
  inputSearchProps.onClearPress.invoke()
203
204
  },
204
205
  interactionSource = remember { MutableInteractionSource() },
@@ -18,6 +18,7 @@ import androidx.compose.foundation.shape.RoundedCornerShape
18
18
  import androidx.compose.foundation.text.BasicTextField
19
19
  import androidx.compose.foundation.text.KeyboardOptions
20
20
  import androidx.compose.runtime.Composable
21
+ import androidx.compose.runtime.MutableState
21
22
  import androidx.compose.runtime.getValue
22
23
  import androidx.compose.runtime.mutableStateOf
23
24
  import androidx.compose.runtime.remember
@@ -41,7 +42,7 @@ val DEFAULT_HEIGHT = 104.dp
41
42
 
42
43
  @Composable
43
44
  fun InputTextArea(
44
- text: String = "",
45
+ text: MutableState<String> = remember { mutableStateOf("") },
45
46
  maxLength: Int = MAX_LENGTH,
46
47
  height: Dp = DEFAULT_HEIGHT,
47
48
  floatingValue: String = "",
@@ -91,7 +92,7 @@ fun InputTextArea(
91
92
  BasicTextField(
92
93
  enabled = !disabled,
93
94
  singleLine = false,
94
- value = text,
95
+ value = text.value,
95
96
  textStyle = TextStyle(
96
97
  color = textColor,
97
98
  fontSize = 16.sp,
@@ -172,7 +173,7 @@ fun InputTextArea(
172
173
  verticalAlignment = Alignment.Top
173
174
  ) {
174
175
  Box(Modifier.weight(1f)) {
175
- if (text.isEmpty()) {
176
+ if (text.value.isEmpty()) {
176
177
  Text(
177
178
  text = placeholder,
178
179
  style = TextStyle(
@@ -185,7 +186,7 @@ fun InputTextArea(
185
186
  }
186
187
  innerTextField()
187
188
  }
188
- if (isFocused && text.isNotEmpty()) {
189
+ if (isFocused && text.value.isNotEmpty()) {
189
190
  Row {
190
191
  Spacer(Modifier.width(Spacing.XS))
191
192
  Icon(
@@ -193,7 +194,7 @@ fun InputTextArea(
193
194
  size = 16.dp,
194
195
  color = AppTheme.current.colors.text.hint,
195
196
  modifier = Modifier.clickable(
196
- onClick = { onChangeText("") },
197
+ onClick = { text.value = "" },
197
198
  interactionSource = remember { MutableInteractionSource() },
198
199
  indication = null
199
200
  )
@@ -211,7 +212,7 @@ fun InputTextArea(
211
212
  contentAlignment = Alignment.CenterEnd
212
213
  ) {
213
214
  Text(
214
- "${text.length}/$maxLength",
215
+ "${text.value.length}/$maxLength",
215
216
  style = Typography.descriptionXsRegular,
216
217
  color = AppTheme.current.colors.text.hint
217
218
  )
@@ -25,15 +25,22 @@ import vn.momo.kits.const.Radius
25
25
  import vn.momo.kits.const.Spacing
26
26
 
27
27
  @Composable
28
- fun PromotionPopup(
28
+ fun PopupPromotion(
29
29
  source: String = "",
30
+ onPress: (() -> Unit) = {},
30
31
  onClose: (() -> Unit) = {},
31
32
  ) {
32
33
  Column(Modifier.semantics { testTag = "popup_notify" }) {
33
34
  if (source.isNotEmpty()) {
34
35
  Image(
35
36
  source = source,
36
- modifier = Modifier.fillMaxWidth().aspectRatio(0.72f),
37
+ modifier = Modifier.fillMaxWidth()
38
+ .aspectRatio(0.72f)
39
+ .clickable(
40
+ interactionSource = remember { MutableInteractionSource() },
41
+ indication = null,
42
+ onClick = onPress
43
+ ),
37
44
  )
38
45
  }
39
46
  Box(
@@ -1,11 +1,6 @@
1
1
  package vn.momo.kits.modifier
2
2
 
3
- import androidx.compose.foundation.clickable
4
- import androidx.compose.foundation.interaction.MutableInteractionSource
5
- import androidx.compose.runtime.remember
6
3
  import androidx.compose.ui.Modifier
7
- import androidx.compose.ui.composed
8
- import androidx.compose.ui.semantics.Role
9
4
  import androidx.compose.ui.semantics.contentDescription
10
5
  import androidx.compose.ui.semantics.semantics
11
6
  import androidx.compose.ui.semantics.testTag
@@ -45,13 +45,24 @@ func safeAreaTopInset() -> CGFloat {
45
45
  public struct HeaderBackground: View {
46
46
  var headerType: HeaderType = .default
47
47
  var scrollState: CGFloat
48
+ var isTransparent: Bool = false
49
+
50
+ public init(
51
+ headerType: HeaderType = .default,
52
+ scrollState: CGFloat = 0,
53
+ isTransparent: Bool = false
54
+ ) {
55
+ self.headerType = headerType
56
+ self.scrollState = scrollState
57
+ self.isTransparent = isTransparent
58
+ }
48
59
 
49
60
  public var body: some View {
50
61
 
51
62
  let statusBarHeight = safeAreaTopInset()
52
63
 
53
64
  let opacity = 1 - CGFloat(scrollState) / 200
54
- let backgroundColor = scrollState == 0 ? Color.clear : Colors.black01
65
+ let backgroundColor = isTransparent ? Color.clear : Colors.black01
55
66
 
56
67
  Group {
57
68
  if headerType == .default {
@@ -62,7 +73,9 @@ public struct HeaderBackground: View {
62
73
  .fill(backgroundColor)
63
74
  .frame(height: height)
64
75
  .shadow(color: Colors.black20.opacity(0.2), radius: 10, x: 0, y: -2)
65
- .overlay(Rectangle()
76
+ .overlay(
77
+ isTransparent ? nil :
78
+ Rectangle()
66
79
  .fill(LinearGradient(
67
80
  gradient: Gradient(colors: [
68
81
  Color(red: 1, green: 0.8, blue: 0.87),
@@ -111,6 +124,7 @@ public struct Header: View {
111
124
  var animatedHeader: AnimatedHeader? = nil
112
125
  var scrollState: CGFloat = 0
113
126
  var inputSearchProps: InputSearchProps? = nil
127
+ var tintColor: Color? = nil
114
128
 
115
129
  @State private var colorFraction: CGFloat = 0
116
130
 
@@ -123,7 +137,8 @@ public struct Header: View {
123
137
  opacity: CGFloat? = nil,
124
138
  animatedHeader: AnimatedHeader? = nil,
125
139
  scrollState: CGFloat = 0,
126
- inputSearchProps: InputSearchProps? = nil
140
+ inputSearchProps: InputSearchProps? = nil,
141
+ tintColor: Color? = nil
127
142
  ) {
128
143
  self.headerType = headerType
129
144
  self.titlePosition = titlePosition
@@ -134,27 +149,27 @@ public struct Header: View {
134
149
  self.animatedHeader = animatedHeader
135
150
  self.scrollState = scrollState
136
151
  self.inputSearchProps = inputSearchProps
152
+ self.tintColor = tintColor
137
153
  }
138
154
 
139
155
  public var body: some View {
140
156
 
141
- let statusBarHeight = safeAreaTopInset()
142
- let tintIconColor = Colors.black17
143
- let backgroundButton = Colors.black01.opacity(0.6)
157
+ // let tintIconColor = Colors.black17
158
+ let backgroundButton = tintColor == Colors.black01 ? Color.white.opacity(0.2) : Colors.black01.opacity(0.6)
159
+ let borderColor: Color = tintColor == Colors.black01 ? Color.black.opacity(0.6) : Color.black.opacity(0.2)
144
160
 
145
161
  if headerType != .none {
146
- VStack(spacing: 0) {
162
+ VStack(spacing: 0) {
147
163
  ZStack {
148
164
  HStack {
149
165
  if let goBack = goBack {
150
166
  SwiftUI.Button(action: goBack) {
151
167
  Circle()
152
- .stroke(Color.black.opacity(0.2), lineWidth: 0.2)
168
+ .stroke(borderColor, lineWidth: 0.2)
153
169
  .background(Circle().fill(backgroundButton))
154
170
  .frame(width: 28, height: 28)
155
171
  .overlay(
156
- Image(systemName: "arrow.backward")
157
- .foregroundColor(.black)
172
+ Icon(source: "arrow-back", size: 20, color: tintColor)
158
173
  )
159
174
  }
160
175
 
@@ -167,14 +182,11 @@ public struct Header: View {
167
182
  }
168
183
 
169
184
  }
170
- .frame(height: 52)
171
- .padding(.horizontal)
172
-
173
-
185
+ .padding(.horizontal, 12)
174
186
 
175
187
  HStack {
176
188
  if titlePosition == .left, goBack != nil {
177
- Spacer().frame(width: 40)
189
+ Spacer().frame(width: 38)
178
190
  }
179
191
 
180
192
  if inputSearchProps != nil {
@@ -201,20 +213,22 @@ public struct Header: View {
201
213
  }
202
214
  } else {
203
215
  Text(title)
204
- .font(.headline)
205
- .foregroundColor(tintIconColor)
206
- .frame(maxWidth: titlePosition == .center ? .infinity : nil, alignment: titlePosition == .center ? .center : .leading)
216
+ .font(Font.system(size: 17).weight(.bold)) .lineSpacing(22)
217
+ .foregroundColor(Colors.black17)
218
+ .frame(maxWidth: titlePosition == .center ? UIScreen.main.bounds.width - 252 : nil)
219
+ .frame(maxWidth: titlePosition == .center ? .infinity : UIScreen.main.bounds.width - 172, alignment: titlePosition == .center ? .center : .leading)
220
+ .lineLimit(1)
221
+
207
222
  }
208
223
  Spacer()
209
224
  }
210
- .frame(height: 52)
211
225
  .padding(.horizontal)
212
226
  }
213
227
  .background(Color.clear)
214
228
  }
215
- }
229
+ .frame(height: 52)
216
230
  }
217
-
231
+ }
218
232
  }
219
233
 
220
234
 
@@ -9,6 +9,8 @@ import SwiftUI
9
9
 
10
10
  public struct Screen<Content: View>: View {
11
11
  var backgroundColor: Color?
12
+ var headerTransparent: Bool = false
13
+ var tintColor: Color? = Colors.black17
12
14
  var isBack: Bool
13
15
  var headerType: HeaderType
14
16
  var verticalAlignment: VerticalAlignment
@@ -29,12 +31,14 @@ public struct Screen<Content: View>: View {
29
31
 
30
32
  public init(
31
33
  backgroundColor: Color? = nil,
34
+ headerTransparent: Bool = false,
35
+ tintColor: Color = Colors.black17,
32
36
  isBack: Bool = true,
33
37
  headerType: HeaderType = .default,
34
38
  verticalAlignment: VerticalAlignment = .top,
35
39
  horizontalAlignment: HorizontalAlignment = .leading,
36
40
  title: String = "Stack",
37
- titlePosition: TitlePosition = .center,
41
+ titlePosition: TitlePosition = .left,
38
42
  goBack: (() -> Void)? = nil,
39
43
  scrollable: Bool = true,
40
44
  onContentLayout: ((CGRect) -> Void)? = nil,
@@ -48,6 +52,8 @@ public struct Screen<Content: View>: View {
48
52
  @ViewBuilder content: @escaping () -> Content
49
53
  ) {
50
54
  self.backgroundColor = backgroundColor
55
+ self.headerTransparent = headerTransparent
56
+ self.tintColor = tintColor
51
57
  self.isBack = isBack
52
58
  self.headerType = headerType
53
59
  self.verticalAlignment = verticalAlignment
@@ -71,23 +77,25 @@ public struct Screen<Content: View>: View {
71
77
 
72
78
  public var body: some View {
73
79
  GeometryReader { geometry in
74
- let safeAreaInsets = geometry.safeAreaInsets
75
- let statusBarHeight = safeAreaInsets.top
80
+ let topInset = geometry.safeAreaInsets.top
76
81
  let keyboardHeight: CGFloat = 0
77
82
  let keyboardSize: CGFloat = useAvoidKeyboard ? max(keyboardHeight, 0) : 0
83
+ let height = geometry.size.height
84
+ let bottomInset = geometry.safeAreaInsets.bottom
85
+ let screenHeight = height + topInset + bottomInset
78
86
 
79
87
  ZStack {
80
88
  (backgroundColor ?? Color.white).edgesIgnoringSafeArea(.all)
81
89
 
82
90
  VStack(spacing: 0) {
83
- ZStack {
84
- if animatedHeader == nil {
85
- HeaderBackground(headerType: headerType, scrollState: scrollOffset)
86
- } else {
87
- Color.white.opacity(Double(min(scrollOffset / 114, 1)))
88
- .overlay(HeaderBackground(headerType: headerType, scrollState: scrollOffset))
89
-
90
- }
91
+ ZStack(alignment: .top) {
92
+ // if animatedHeader == nil {
93
+ // HeaderBackground(headerType: headerType, scrollState: scrollOffset)
94
+ // } else {
95
+ // Color.white.opacity(Double(min(scrollOffset / 114, 1)))
96
+ // .overlay(HeaderBackground(headerType: headerType, scrollState: scrollOffset))
97
+ //
98
+ // }
91
99
 
92
100
  Header(
93
101
  headerType: headerType,
@@ -98,14 +106,19 @@ public struct Screen<Content: View>: View {
98
106
  opacity: min(scrollOffset / 114, 1),
99
107
  animatedHeader: animatedHeader,
100
108
  scrollState: scrollOffset,
101
- inputSearchProps: inputSearchProps
102
- ).padding(.bottom, headerType == .extended ? 0 : -safeAreaTopInset())
103
- }.padding(.top, -safeAreaTopInset())
109
+ inputSearchProps: inputSearchProps,
110
+ tintColor: tintColor
111
+ )
112
+ .background(HeaderBackground(headerType: headerType, scrollState: scrollOffset, isTransparent: headerTransparent).edgesIgnoringSafeArea(.top))
113
+ .offset(y: topInset)
114
+
115
+ }
116
+ .offset(y: -topInset)
104
117
 
105
118
 
106
119
  VStack(alignment: horizontalAlignment, spacing: 0) {
107
120
  if animatedHeader != nil {
108
- Spacer().frame(height: statusBarHeight + 52 + layoutOffset)
121
+ Spacer().frame(height: topInset + 52 + layoutOffset)
109
122
  }
110
123
 
111
124
  if scrollable {
@@ -75,7 +75,7 @@ public struct Checkbox: View{
75
75
  } else if checked {
76
76
  return Colors.primary
77
77
  } else {
78
- return Colors.black01
78
+ return Color.clear
79
79
  }
80
80
  }
81
81
  }
@@ -20,7 +20,7 @@ public enum PopupButtonType {
20
20
  public struct PopupDisplay: View {
21
21
  // MARK: Lifecycle
22
22
 
23
- public init(isPresented: Binding<Bool>, title: String = "", description: String = "", url: String = "", buttonDirection: PopupButtonDirection = .column, buttonType: PopupButtonType = .button, actionButtonTitle: String = "", closeButtonTitle: String = "", onPressAction: @escaping () -> Void = {}, onPressCloseButton: @escaping () -> Void = {}, onClose: @escaping () -> Void = {}) {
23
+ public init(isPresented: Binding<Bool>, title: String = "", description: String = "", url: String = "", buttonDirection: PopupButtonDirection = .column, buttonType: PopupButtonType = .button, actionButtonTitle: String = "", closeButtonTitle: String = "", onPressAction: @escaping () -> Void = {}, onPressCloseButton: @escaping () -> Void = {}, onClose: @escaping () -> Void = {}, errorCode: String = "") {
24
24
  self._isPresented = isPresented
25
25
  self.title = title
26
26
  self.description = description
@@ -32,6 +32,7 @@ public struct PopupDisplay: View {
32
32
  self.onClose = onClose
33
33
  self.closeButtonTitle = closeButtonTitle
34
34
  self.actionButtonTitle = actionButtonTitle
35
+ self.errorCode = errorCode
35
36
  }
36
37
 
37
38
  // MARK: Public
@@ -39,7 +40,7 @@ public struct PopupDisplay: View {
39
40
  public var body: some View {
40
41
  VStack(spacing: 12) {
41
42
  ZStack(alignment: .topTrailing) {
42
- SwiftUI.Button(action: onPressClose) {
43
+ SwiftUI.Button(action: onClose) {
43
44
  Image(systemName: "xmark.circle.fill")
44
45
  .resizable()
45
46
  .frame(width: 22, height: 22)
@@ -51,20 +52,20 @@ public struct PopupDisplay: View {
51
52
  .zIndex(1)
52
53
  .accessibility(identifier: "ic_popup_close")
53
54
 
54
- VStack {
55
- if(!url.isEmpty) {
56
- WebImage(url: URL(string: url), isAnimating: .constant(true))
57
- .resizable()
58
- .placeholder {
59
- Rectangle()
60
- .fill(Color.gray.opacity(0.3))
61
- .frame(maxWidth: .infinity, maxHeight: 184)
62
- }
63
- .scaledToFill()
64
- .frame(maxWidth: .infinity)
65
- .clipShape(RoundedCorner(radius: 8, corners: [.topLeft, .topRight]))
66
- .aspectRatio(2, contentMode: .fit)
67
- }
55
+ VStack {
56
+ if(!url.isEmpty) {
57
+ WebImage(url: URL(string: url), isAnimating: .constant(true))
58
+ .resizable()
59
+ .placeholder {
60
+ Rectangle()
61
+ .fill(Color.gray.opacity(0.3))
62
+ .frame(maxWidth: .infinity, maxHeight: 184)
63
+ }
64
+ .scaledToFill()
65
+ .frame(maxWidth: .infinity)
66
+ .clipShape(RoundedCorner(radius: 15, corners: [.topLeft, .topRight]))
67
+ .aspectRatio(2, contentMode: .fit)
68
+ }
68
69
  VStack(alignment: .leading) {
69
70
  Text(title)
70
71
  .foregroundColor(.black)
@@ -79,10 +80,18 @@ public struct PopupDisplay: View {
79
80
  .font(.paragraph)
80
81
  .opacity(0.6)
81
82
  .multilineTextAlignment(.leading)
82
- .padding(.bottom, 20)
83
+ .padding(.bottom, 8)
84
+
85
+ if(!errorCode.isEmpty) {
86
+ Text(errorCode)
87
+ .foregroundColor(Colors.black12)
88
+ .font(.description_xs_regular)
89
+ .lineLimit(1)
90
+ }
83
91
  }
84
92
  .frame(maxWidth: .infinity, alignment: .leading)
85
93
  .padding(.horizontal, 24)
94
+ .padding(.bottom, 24)
86
95
 
87
96
  if buttonDirection == .row {
88
97
  if buttonType == .text {
@@ -120,7 +129,8 @@ public struct PopupDisplay: View {
120
129
  var onClose: () -> Void
121
130
  var actionButtonTitle: String
122
131
  var closeButtonTitle: String
123
-
132
+ var errorCode: String
133
+
124
134
  var RowTextButtons: some View {
125
135
  HStack {
126
136
  SwiftUI.Button(action: onPressCloseButton) {
@@ -181,9 +191,4 @@ public struct PopupDisplay: View {
181
191
  .padding(.bottom, 24)
182
192
  }
183
193
 
184
-
185
- func onPressClose(){
186
- isPresented = false
187
- onClose()
188
- }
189
194
  }
@@ -1,52 +1,66 @@
1
- import SDWebImageSwiftUI
2
1
  import SwiftUI
2
+ import SDWebImageSwiftUI
3
3
 
4
4
  public struct PopupPromotion: View {
5
- // MARK: Lifecycle
6
-
7
- public init(isPresented: Binding<Bool>, url: String = "", buttonTitle: String = "", onPressAction: @escaping () -> Void = {}, onClose: @escaping () -> Void = {}) {
8
- self._isPresented = isPresented
9
- self.onPressAction = onPressAction
10
- self.buttonTitle = buttonTitle
11
- self.onClose = onClose
12
- self.url = url
13
- }
5
+ var imageUrl: String
6
+ var onIconClose: (() -> Void)?
7
+ var onAction: (() -> Void)?
14
8
 
15
- // MARK: Public
9
+
10
+ public init(
11
+ imageUrl: String,
12
+ onIconClose: (() -> Void)? = nil,
13
+ onAction: (() -> Void)? = nil
14
+ ) {
15
+ self.imageUrl = imageUrl
16
+ self.onIconClose = onIconClose
17
+ self.onAction = onAction
18
+ }
16
19
 
17
20
  public var body: some View {
18
- VStack(spacing: 12) {
19
- ZStack(alignment: .bottom) {
20
- WebImage(url: URL(string: url), isAnimating: .constant(true))
21
- .resizable()
22
- .placeholder {
23
- Circle().foregroundColor(.gray)
24
- }
25
- .scaledToFill()
26
- .frame(maxWidth: .infinity, maxHeight: .infinity)
27
- .cornerRadius(8)
28
-
29
- Button(title: buttonTitle, action: onPressAction)
30
- .padding(.horizontal, 24)
31
- .padding(.bottom, 24)
32
- }.clipped()
21
+ VStack(spacing: 8) {
22
+ WebImage(url: URL(string: imageUrl)!)
23
+ .resizable()
24
+ .placeholder {
25
+ Color.gray
26
+ .aspectRatio(0.72, contentMode: .fit)
27
+ .frame(maxWidth: UIScreen.main.bounds.width - Spacing.XL * 2)
28
+ .clipped()
29
+ }
30
+ .aspectRatio(0.72, contentMode: .fit)
31
+ .frame(maxWidth: UIScreen.main.bounds.width - Spacing.XL * 2)
32
+ .clipped()
33
+ .onTapGesture {
34
+ onAction?()
35
+ }
36
+
37
+ buildCloseIcon()
33
38
  }
34
- .frame(maxWidth: .infinity, maxHeight: 400)
35
- .shadow(color: .black.opacity(0.08), radius: 2, x: 0, y: 0)
36
- .shadow(color: .black.opacity(0.16), radius: 24, x: 0, y: 0)
37
- .padding(.horizontal, 40)
39
+ .accessibility(identifier: "popup_promotion")
38
40
  }
39
41
 
40
- // MARK: Internal
42
+ @ViewBuilder
43
+ private func buildCloseIcon() -> some View {
44
+ HStack {
45
+ Spacer()
46
+ SwiftUI.Button(action: {
47
+ onIconClose?()
48
+ }) {
49
+ ZStack {
50
+ Circle()
51
+ .strokeBorder(Colors.black01, lineWidth: 2)
52
+ .background(Circle().fill(Colors.black17))
53
+ .frame(width: 20, height: 20)
41
54
 
42
- @Binding var isPresented: Bool
43
- var onPressAction: () -> Void
44
- var onClose: () -> Void
45
- var buttonTitle: String
46
- var url: String
47
-
48
- func onPressClose(){
49
- isPresented = false
50
- onClose()
55
+ Icon(source: "navigation_close", size: 14, color: Colors.black01)
56
+ }
57
+ }
58
+ .padding(8)
59
+ Spacer()
60
+ }
51
61
  }
62
+
52
63
  }
64
+
65
+
66
+
package/local.properties CHANGED
@@ -4,5 +4,5 @@
4
4
  # Location of the SDK. This is only used by Gradle.
5
5
  # For customization when using a Version Control System, please read the
6
6
  # header note.
7
- #Thu Jan 09 10:43:10 ICT 2025
8
- sdk.dir=/Users/sophia/Library/Android/sdk
7
+ #Wed Aug 21 14:20:12 ICT 2024
8
+ sdk.dir=/Users/huynhdung/Library/Android/sdk
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@momo-kits/native-kits",
3
- "version": "0.114.2-pu.1",
3
+ "version": "0.117.1-beta.2",
4
4
  "private": false,
5
5
  "dependencies": {},
6
6
  "devDependencies": {},