@momo-kits/native-kits 0.152.4-beta.6 → 0.152.4-maxapi

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 (155) hide show
  1. package/CODE_OF_CONDUCT.md +133 -0
  2. package/CONTRIBUTING.md +114 -0
  3. package/LICENSE +20 -0
  4. package/README.md +7 -0
  5. package/build.gradle.kts +32 -0
  6. package/compose/MoMoComposeKits.podspec +54 -0
  7. package/compose/build.gradle.kts +149 -0
  8. package/compose/src/androidMain/AndroidManifest.xml +2 -0
  9. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +105 -0
  10. package/compose/src/commonMain/composeResources/files/lottie_circle_loader.json +1 -0
  11. package/compose/src/commonMain/composeResources/font/momosignature.otf +0 -0
  12. package/compose/src/commonMain/composeResources/font/momotrustdisplay.otf +0 -0
  13. package/compose/src/commonMain/composeResources/font/sfprotext_black.otf +0 -0
  14. package/compose/src/commonMain/composeResources/font/sfprotext_black.ttf +0 -0
  15. package/compose/src/commonMain/composeResources/font/sfprotext_bold.ttf +0 -0
  16. package/compose/src/commonMain/composeResources/font/sfprotext_heavy.ttf +0 -0
  17. package/compose/src/commonMain/composeResources/font/sfprotext_light.ttf +0 -0
  18. package/compose/src/commonMain/composeResources/font/sfprotext_medium.ttf +0 -0
  19. package/compose/src/commonMain/composeResources/font/sfprotext_regular.ttf +0 -0
  20. package/compose/src/commonMain/composeResources/font/sfprotext_semibold.ttf +0 -0
  21. package/compose/src/commonMain/composeResources/font/sfprotext_thin.otf +0 -0
  22. package/compose/src/commonMain/composeResources/font/sfprotext_thin.ttf +0 -0
  23. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.otf +0 -0
  24. package/compose/src/commonMain/composeResources/font/sfprotext_ultralight.ttf +0 -0
  25. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +57 -0
  26. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +201 -0
  27. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +222 -0
  28. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +48 -0
  29. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +86 -0
  30. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +76 -0
  31. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +76 -0
  32. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +306 -0
  33. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +33 -0
  34. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +715 -0
  35. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +214 -0
  36. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +236 -0
  37. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +69 -0
  38. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +77 -0
  39. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +27 -0
  40. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +334 -0
  41. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +345 -0
  42. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +90 -0
  43. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +131 -0
  44. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +543 -0
  45. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
  46. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +58 -0
  47. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +143 -0
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +179 -0
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +111 -0
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +384 -0
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +160 -0
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +234 -0
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +223 -0
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +232 -0
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +236 -0
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +228 -0
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +364 -0
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +50 -0
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +34 -0
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +85 -0
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +33 -0
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +338 -0
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +95 -0
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +64 -0
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +89 -0
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +91 -0
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +86 -0
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +84 -0
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +208 -0
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +172 -0
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +199 -0
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +29 -0
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +237 -0
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +191 -0
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +306 -0
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +13 -0
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +191 -0
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +258 -0
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +35 -0
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +59 -0
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +68 -0
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +11 -0
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +49 -0
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +51 -0
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +232 -0
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +111 -0
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +94 -0
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +159 -0
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +232 -0
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScaleSizeScope.kt +17 -0
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +459 -0
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +169 -0
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +216 -0
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +86 -0
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +180 -0
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +251 -0
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +80 -0
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +306 -0
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +31 -0
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +385 -0
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +38 -0
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1329 -0
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +62 -0
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +88 -0
  108. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +144 -0
  109. package/gradle.properties +19 -0
  110. package/gradlew +240 -0
  111. package/gradlew.bat +91 -0
  112. package/ios/Application/ApplicationEnvironment.swift +50 -0
  113. package/ios/Application/Components.swift +263 -0
  114. package/ios/Application/ComposeApi.swift +22 -0
  115. package/ios/Application/FloatingButton.swift +172 -0
  116. package/ios/Application/HeaderRight.swift +271 -0
  117. package/ios/Application/Screen.swift +249 -0
  118. package/ios/Badge/BadgeDot.swift +31 -0
  119. package/ios/Button/Button.swift +211 -0
  120. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
  121. package/ios/Checkbox/Checkbox.swift +81 -0
  122. package/ios/Chip/Chip.swift +96 -0
  123. package/ios/Colors+Radius+Spacing/Colors.swift +172 -0
  124. package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
  125. package/ios/Colors+Radius+Spacing/Spacing.swift +12 -0
  126. package/ios/Extensions/Color++.swift +25 -0
  127. package/ios/Icon/Icon.swift +51 -0
  128. package/ios/Image/Image.swift +70 -0
  129. package/ios/Input/Input.swift +207 -0
  130. package/ios/Input/InputPhoneNumber.swift +176 -0
  131. package/ios/Input/InputSearch.swift +238 -0
  132. package/ios/Input/InputTextArea.swift +242 -0
  133. package/ios/Lottie/LottieView.swift +86 -0
  134. package/ios/OTPKeyboard/KeyboardButton.swift +41 -0
  135. package/ios/OTPKeyboard/OTPKeyboard.swift +145 -0
  136. package/ios/Popup/PopupDisplay.swift +284 -0
  137. package/ios/Popup/PopupInput.swift +96 -0
  138. package/ios/Popup/PopupPromotion.swift +73 -0
  139. package/ios/PopupView/FullscreenPopup.swift +251 -0
  140. package/ios/PopupView/Modifiers.swift +158 -0
  141. package/ios/PopupView/PopupView.swift +289 -0
  142. package/ios/PopupView/Utils++.swift +281 -0
  143. package/ios/ScrollIndicator/ScrollIndicator.swift +110 -0
  144. package/ios/Swipeable/SwipeCell.swift +278 -0
  145. package/ios/Swipeable/SwipeCellModel.swift +86 -0
  146. package/ios/Switch/Switch.swift +44 -0
  147. package/ios/Template/Logo/Logo.swift +75 -0
  148. package/ios/Template/TrustBanner/TrustBanner.swift +120 -0
  149. package/ios/Theme.md +18 -0
  150. package/ios/Typography/Text.swift +140 -0
  151. package/ios/Typography/Typography.swift +95 -0
  152. package/ios/native-kits.podspec +18 -0
  153. package/package.json +6 -7
  154. package/settings.gradle.kts +25 -0
  155. package/shared/build.gradle.kts +0 -74
@@ -0,0 +1,145 @@
1
+
2
+ import Foundation
3
+ import SwiftUI
4
+
5
+ // MARK: - OTPKeyboard
6
+
7
+ public struct OTPKeyboard: View {
8
+ // MARK: Lifecycle
9
+
10
+ public init(value: Binding<String>, length: Int, content: AnyView? = nil, onChange: ((String) -> Void)? = nil, onClose: @escaping () -> Void) {
11
+ self._value = value
12
+ self.length = length
13
+ self.content = content
14
+ self.onChange = onChange
15
+ self.onClose = onClose
16
+ }
17
+
18
+ // MARK: Public
19
+
20
+ public var body: some View {
21
+ return VStack {
22
+ VStack {
23
+ HStack(){
24
+ SwiftUI.Button(action: onClose) {
25
+ Image(systemName: "xmark")
26
+ .foregroundColor(Colors.text)
27
+ }
28
+ Spacer()
29
+ }
30
+
31
+ ZStack(alignment: .trailing) {
32
+ ValueView(value, valueLength: length).padding(.trailing, 12)
33
+ SwiftUI.Button(action: onClear) {
34
+ Image(systemName: "xmark.circle.fill")
35
+ .resizable()
36
+ .frame(width: 12, height: 12)
37
+ .foregroundColor(Colors.text)
38
+ }.offset(x: -12)
39
+ }.frame(minWidth: 148, maxWidth: 180, minHeight: 40)
40
+ .background(Colors.card)
41
+ .clipShape(Capsule())
42
+ .padding(.bottom, Spacing.M)
43
+ }
44
+
45
+ content
46
+
47
+ HStack {
48
+ KeyboardButton("7", action: self.onPressKey)
49
+ KeyboardButton("8", action: self.onPressKey)
50
+ KeyboardButton("9", action: self.onPressKey)
51
+ }
52
+
53
+ HStack {
54
+ KeyboardButton("4", action: self.onPressKey)
55
+ KeyboardButton("5", action: self.onPressKey)
56
+ KeyboardButton("6", action: self.onPressKey)
57
+ }
58
+
59
+ HStack {
60
+ KeyboardButton("1", action: self.onPressKey)
61
+ KeyboardButton("2", action: self.onPressKey)
62
+ KeyboardButton("3", action: self.onPressKey)
63
+ }
64
+
65
+ HStack {
66
+ KeyboardButton("", action: self.onPressKey).disabled(true).opacity(0)
67
+ KeyboardButton("0", action: self.onPressKey)
68
+ SwiftUI.Button(action: onPressBack) {
69
+ HStack {
70
+ Image(
71
+ systemName: "delete.backward"
72
+ ).foregroundColor(Colors.text)
73
+ }
74
+ }.frame(maxWidth: .infinity, minHeight: 48)
75
+ .clipShape(RoundedRectangle(cornerRadius: 8))
76
+ }
77
+ }
78
+ .background(Colors.background)
79
+ .valueChanged(value: value) { otp in
80
+ if onChange != nil {
81
+ self.onChange!(otp)
82
+ }
83
+ }
84
+ }
85
+
86
+ public func buildContent(_ content: @escaping () -> AnyView) -> OTPKeyboard {
87
+ var newSelf = self
88
+ newSelf.content = content()
89
+ return newSelf
90
+ }
91
+
92
+ // MARK: Internal
93
+
94
+ @Binding var value: String
95
+ var length: Int
96
+ var content: AnyView?
97
+ var onChange: ((String) -> Void)?
98
+ var onClose: () -> Void
99
+
100
+ func onPressKey(key: String) {
101
+ if value.count < length {
102
+ value.append(key)
103
+ }
104
+ }
105
+
106
+ func onPressBack() {
107
+ if !value.isEmpty {
108
+ value.removeLast()
109
+ }
110
+ }
111
+
112
+ func onClear() {
113
+ value.removeAll()
114
+ }
115
+ }
116
+
117
+ // MARK: - ValueView
118
+
119
+ private struct ValueView: View {
120
+ // MARK: Lifecycle
121
+
122
+ init(_ value: String, valueLength: Int) {
123
+ self.value = value
124
+ self.valueLength = valueLength
125
+ }
126
+
127
+ // MARK: Public
128
+
129
+ public var body: some View {
130
+ return HStack {
131
+ ForEach(0 ..< valueLength, id: \.self) { i in
132
+ if i < value.count {
133
+ Circle().foregroundColor(Colors.text).frame(width: 8, height: 8)
134
+ } else {
135
+ Circle().foregroundColor(Colors.textSecondary).frame(width: 8, height: 8)
136
+ }
137
+ }
138
+ }.frame(maxWidth: .infinity, minHeight: 40)
139
+ }
140
+
141
+ // MARK: Internal
142
+
143
+ var value: String = ""
144
+ var valueLength: Int
145
+ }
@@ -0,0 +1,284 @@
1
+ import SDWebImageSwiftUI
2
+ import SwiftUI
3
+
4
+ // MARK: - PopupButtonDirection
5
+
6
+ public enum PopupButtonDirection {
7
+ case row
8
+ case column
9
+ case auto
10
+ }
11
+
12
+ // MARK: - PopupButtonType
13
+
14
+ public enum PopupButtonType {
15
+ case text
16
+ case button
17
+ }
18
+
19
+ extension View {
20
+ func measureLineHeights(font: Font,
21
+ oneLine: Binding<CGFloat>,
22
+ twoLines: Binding<CGFloat>) -> some View {
23
+ overlay(
24
+ VStack(spacing: 0) {
25
+ Text("A")
26
+ .font(font)
27
+ .lineLimit(1)
28
+ .fixedSize()
29
+ .background(
30
+ GeometryReader { g in
31
+ Color.clear.onAppear { oneLine.wrappedValue = g.size.height }
32
+ }
33
+ )
34
+ .hidden()
35
+
36
+ Text("A\nA")
37
+ .font(font)
38
+ .lineLimit(2)
39
+ .fixedSize(horizontal: false, vertical: true)
40
+ .background(
41
+ GeometryReader { g in
42
+ Color.clear.onAppear { twoLines.wrappedValue = g.size.height }
43
+ }
44
+ )
45
+ .hidden()
46
+ }
47
+ .frame(width: 0, height: 0)
48
+ )
49
+ }
50
+ }
51
+
52
+ // MARK: - PopupDisplay
53
+
54
+ public struct PopupDisplay: View {
55
+ // MARK: Lifecycle
56
+
57
+ 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 = "", isShowCloseIcon: Bool = true) {
58
+ self._isPresented = isPresented
59
+ self.title = title
60
+ self.description = description
61
+ self.url = url
62
+ self.buttonDirection = buttonDirection
63
+ self.buttonType = buttonType
64
+ self.onPressAction = onPressAction
65
+ self.onPressCloseButton = onPressCloseButton
66
+ self.onClose = onClose
67
+ self.closeButtonTitle = closeButtonTitle
68
+ self.actionButtonTitle = actionButtonTitle
69
+ self.errorCode = errorCode
70
+ self.isShowCloseIcon = isShowCloseIcon
71
+ }
72
+
73
+ // MARK: Public
74
+
75
+ @State private var oneLineH: CGFloat = 0
76
+ @State private var twoLineH: CGFloat = 0
77
+
78
+ private var fallbackLH: CGFloat { UIFont.preferredFont(forTextStyle: .body).lineHeight }
79
+ private var perLine: CGFloat { max(twoLineH - oneLineH, oneLineH > 0 ? oneLineH : fallbackLH) }
80
+
81
+ private func heightForLines(lines: CGFloat) -> CGFloat {
82
+ guard oneLineH > 0 && twoLineH > 0 else { return ceil(fallbackLH * lines) }
83
+ return ceil(oneLineH + max(0, lines - 1) * (twoLineH - oneLineH))
84
+ }
85
+ private var maxHeight8_5: CGFloat { heightForLines(lines: 8.5) }
86
+
87
+
88
+ @State private var textHeight: CGFloat = .zero
89
+ @State private var isScrollable = false
90
+
91
+ public var body: some View {
92
+ var shouldUseColumn: Bool {
93
+ buttonDirection == .column || (buttonDirection == .auto && (closeButtonTitle.count > 12 || actionButtonTitle.count > 12))
94
+ }
95
+
96
+ VStack(spacing: 12) {
97
+ ZStack(alignment: .topTrailing) {
98
+ if(isShowCloseIcon) {
99
+ SwiftUI.Button(action: onClose) {
100
+ Image(systemName: "xmark.circle.fill")
101
+ .resizable()
102
+ .frame(width: 22, height: 22)
103
+ .overlay(RoundedRectangle(cornerRadius: Radius.L).stroke(Colors.black01, lineWidth: 2))
104
+ }.foregroundColor(Colors.black20)
105
+ .background(Colors.black01.cornerRadius(15))
106
+ .padding(.trailing, -11)
107
+ .padding(.top, -11)
108
+ .zIndex(1)
109
+ .accessibility(identifier: "ic_popup_close")
110
+ }
111
+
112
+ VStack(spacing: 0) {
113
+ if(!url.isEmpty) {
114
+ WebImage(url: URL(string: url), isAnimating: .constant(true))
115
+ .resizable()
116
+ .placeholder {
117
+ Rectangle()
118
+ .fill(Color.gray.opacity(0.3))
119
+ .frame(maxWidth: .infinity, maxHeight: 184)
120
+ }
121
+ .aspectRatio(1.777, contentMode: .fit)
122
+ .frame(maxWidth: .infinity, alignment: .center)
123
+ .clipShape(RoundedCorner(radius: 15, corners: [.topLeft, .topRight]))
124
+ .clipped()
125
+ }
126
+ VStack(alignment: .leading, spacing: 0) {
127
+ Text(title)
128
+ .foregroundColor(.black)
129
+ .font(.header_default_semibold)
130
+ .padding(.top, 24)
131
+ .padding(.bottom, 8)
132
+ .lineLimit(2)
133
+ .accessibility(identifier: "title_popup_permission")
134
+
135
+ Group {
136
+ if isScrollable {
137
+ ScrollView(showsIndicators: false) {
138
+ Text(description)
139
+ .font(.body_default_regular)
140
+ .foregroundColor(Colors.black17)
141
+ .multilineTextAlignment(.leading)
142
+ .background(GeometryReader { geo in
143
+ Color.clear.onAppear { textHeight = geo.size.height }
144
+ })
145
+ .measureLineHeights(font: .body_default_regular,
146
+ oneLine: $oneLineH,
147
+ twoLines: $twoLineH)
148
+ }
149
+ // Cap the visible height to ~8.5 lines
150
+ .frame(height: min(maxHeight8_5, textHeight))
151
+ } else {
152
+ Text(description)
153
+ .font(.body_default_regular)
154
+ .foregroundColor(Colors.black17)
155
+ .multilineTextAlignment(.leading)
156
+ .background(GeometryReader { geo in
157
+ Color.clear.onAppear {
158
+ textHeight = geo.size.height
159
+ // Trigger scroll at ~8.5 lines
160
+ isScrollable = textHeight > maxHeight8_5
161
+ }
162
+ })
163
+ .measureLineHeights(font: .body_default_regular,
164
+ oneLine: $oneLineH,
165
+ twoLines: $twoLineH)
166
+ }
167
+ }
168
+ .padding(.bottom, 8)
169
+
170
+ if(!errorCode.isEmpty) {
171
+ Text("Mã lỗi: " + errorCode)
172
+ .foregroundColor(Colors.black12)
173
+ .font(.description_xs_regular)
174
+ .lineLimit(1)
175
+ .padding(.bottom, 8)
176
+ }
177
+ }
178
+ .frame(maxWidth: .infinity, alignment: .leading)
179
+ .padding(.horizontal, 24)
180
+ .padding(.bottom, 16)
181
+
182
+ if shouldUseColumn {
183
+ if buttonType == .text {
184
+ ColumnTextButtons
185
+ } else {
186
+ ColumnButtons
187
+ }
188
+ } else {
189
+ if buttonType == .text {
190
+ RowTextButtons
191
+ } else {
192
+ RowButtons
193
+ }
194
+ }
195
+ }
196
+ .fixedSize(horizontal: false, vertical: true)
197
+ }
198
+ }
199
+ .background(Color.white.cornerRadius(15))
200
+ .padding(.horizontal, 12)
201
+ .accessibilityElement(children: .ignore)
202
+ .accessibility(identifier: "popup_notify")
203
+ }
204
+
205
+ // MARK: Internal
206
+
207
+ @Binding var isPresented: Bool
208
+ var title: String
209
+ var description: String
210
+ var url: String
211
+ var buttonDirection: PopupButtonDirection
212
+ var buttonType: PopupButtonType
213
+ var onPressAction: () -> Void
214
+ var onPressCloseButton: () -> Void
215
+ var onClose: () -> Void
216
+ var actionButtonTitle: String
217
+ var closeButtonTitle: String
218
+ var errorCode: String
219
+ var isShowCloseIcon: Bool
220
+
221
+ var RowTextButtons: some View {
222
+ HStack {
223
+ SwiftUI.Button(action: onPressCloseButton) {
224
+ Text(closeButtonTitle)
225
+ .font(.action2)
226
+ }.foregroundColor(Colors.black09)
227
+ .padding(.trailing, 12)
228
+
229
+ SwiftUI.Button(action: onPressAction) {
230
+ Text(actionButtonTitle)
231
+ .font(.action2)
232
+ }.foregroundColor(Colors.primary)
233
+ }
234
+ .frame(maxWidth: .infinity, alignment: .trailing)
235
+ .padding(EdgeInsets(top: 0, leading: 0, bottom: 24, trailing: 24))
236
+ }
237
+
238
+ var ColumnTextButtons: some View {
239
+ VStack(alignment: .trailing) {
240
+ SwiftUI.Button(action: onPressAction) {
241
+ Text(actionButtonTitle)
242
+ .font(.action2)
243
+ }.foregroundColor(Colors.primary)
244
+ .padding(.bottom, 6)
245
+
246
+ SwiftUI.Button(action: onPressCloseButton) {
247
+ Text(closeButtonTitle)
248
+ .font(.action2)
249
+ }.foregroundColor(Colors.black09)
250
+ }
251
+ .frame(maxWidth: .infinity, alignment: .trailing)
252
+ .padding(EdgeInsets(top: 0, leading: 0, bottom: 24, trailing: 24))
253
+ }
254
+
255
+ var RowButtons: some View {
256
+ HStack {
257
+ if(!closeButtonTitle.isEmpty) {
258
+ Button(title: closeButtonTitle, action: onPressCloseButton, type: .text, size: .medium).accessibility(identifier: "btn_popup_cancel")
259
+ }
260
+ Button(title: actionButtonTitle, action: onPressAction, size: .medium)
261
+ .accessibility(identifier: "btn_popup_allow")
262
+ }
263
+ .frame(maxWidth: .infinity, alignment: .center)
264
+ .padding(.horizontal, 24)
265
+ .padding(.bottom, 24)
266
+ }
267
+
268
+ var ColumnButtons: some View {
269
+ VStack(alignment: .trailing) {
270
+ Button(
271
+ title: actionButtonTitle,
272
+ action: onPressAction,
273
+ size: .medium
274
+ ).accessibility(identifier: "btn_popup_allow")
275
+ if(!closeButtonTitle.isEmpty) {
276
+ Button(title: closeButtonTitle, action: onPressCloseButton, type: .text, size: .medium).accessibility(identifier: "btn_popup_cancel")
277
+ }
278
+ }
279
+ .frame(maxWidth: .infinity, alignment: .trailing)
280
+ .padding(.horizontal, 24)
281
+ .padding(.bottom, 24)
282
+ }
283
+
284
+ }
@@ -0,0 +1,96 @@
1
+ import SDWebImageSwiftUI
2
+ import SwiftUI
3
+
4
+ public struct PopupInput: View {
5
+ // MARK: Lifecycle
6
+
7
+ public init(isPresented: Binding<Bool>, title: String = "", description: String = "", numberOfButtons: Int = 1, actionButtonTitle: String = "", closeButtonTitle: String = "", onPressAction: @escaping () -> Void = {}, onPressCloseButton: @escaping () -> Void = {}, onClose: @escaping () -> Void = {}, inputPlaceholder: String = "", inputValue: Binding<String> = Binding.constant(""), onTextChange: ((String) -> Void)? = nil) {
8
+ self._isPresented = isPresented
9
+ self._inputValue = inputValue
10
+ self.title = title
11
+ self.description = description
12
+ self.onPressAction = onPressAction
13
+ self.onPressCloseButton = onPressCloseButton
14
+ self.onClose = onClose
15
+ self.inputPlaceholder = inputPlaceholder
16
+ self.onTextChange = onTextChange
17
+ self.numberOfButtons = numberOfButtons
18
+ self.closeButtonTitle = closeButtonTitle
19
+ self.actionButtonTitle = actionButtonTitle
20
+ }
21
+
22
+ // MARK: Public
23
+
24
+ public var body: some View {
25
+ VStack(spacing: 12) {
26
+ ZStack(alignment: .topTrailing) {
27
+ SwiftUI.Button(action: onPressClose) {
28
+ Image(systemName: "xmark.circle.fill")
29
+ .resizable()
30
+ .frame(width: 16, height: 16)
31
+ }.foregroundColor(Colors.black20)
32
+ .background(Colors.black01.cornerRadius(8))
33
+ .offset(x: 6, y: -6)
34
+ .zIndex(1)
35
+
36
+ VStack {
37
+ VStack(alignment: .leading) {
38
+ Text(title)
39
+ .foregroundColor(.black)
40
+ .font(.headerText1)
41
+ .padding(.top, 12)
42
+ .padding(.bottom, 24)
43
+
44
+ Text(description)
45
+ .foregroundColor(.black)
46
+ .font(.paragraph)
47
+ .opacity(0.6)
48
+ .multilineTextAlignment(.leading)
49
+ .padding(.bottom, 20)
50
+ }.padding(.horizontal, 24)
51
+
52
+ Input($inputValue, placeholder: inputPlaceholder, onChange: onTextChange)
53
+ .padding(.horizontal, 24)
54
+
55
+ if numberOfButtons == 1 {
56
+ Button(title: actionButtonTitle, action: onPressAction)
57
+ .padding(.horizontal, 24)
58
+ .padding(.bottom, 24)
59
+ } else {
60
+ HStack {
61
+ Button(title: closeButtonTitle, action: onPressCloseButton, type: .secondary)
62
+ Button(title: actionButtonTitle, action: onPressAction)
63
+ }.padding(.horizontal, 24)
64
+ .padding(.bottom, 24)
65
+ }
66
+
67
+ }.clipped()
68
+ }
69
+ }
70
+ .background(Color.white.cornerRadius(8))
71
+ .shadow(color: .black.opacity(0.08), radius: 2, x: 0, y: 0)
72
+ .shadow(color: .black.opacity(0.16), radius: 24, x: 0, y: 0)
73
+ .padding(.horizontal, 40)
74
+ }
75
+
76
+ // MARK: Internal
77
+
78
+ @Binding var isPresented: Bool
79
+ @Binding var inputValue: String
80
+ var title: String
81
+ var description: String
82
+ var onPressAction: () -> Void
83
+ var onPressCloseButton: () -> Void
84
+ var onClose: () -> Void
85
+ var inputPlaceholder: String
86
+ var onTextChange: ((String) -> Void)?
87
+ var numberOfButtons: Int
88
+ var actionButtonTitle: String
89
+ var closeButtonTitle: String
90
+
91
+
92
+ func onPressClose(){
93
+ isPresented = false
94
+ onClose()
95
+ }
96
+ }
@@ -0,0 +1,73 @@
1
+ import SwiftUI
2
+ import SDWebImageSwiftUI
3
+
4
+ public struct PopupPromotion: View {
5
+ var imageUrl: String
6
+ var onIconClose: (() -> Void)?
7
+ var onAction: (() -> Void)?
8
+
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
+ }
19
+
20
+ public var body: some View {
21
+ VStack(spacing: 8) {
22
+ if(imageUrl.isEmpty) {
23
+ Icon(source: "media_fail", size: UIScreen.main.bounds.width - Spacing.XL * 2)
24
+ }
25
+ else {
26
+ WebImage(url: URL(string: imageUrl)!)
27
+ .resizable()
28
+ .placeholder {
29
+ Color.gray
30
+ .aspectRatio(0.72, contentMode: .fit)
31
+ .frame(maxWidth: UIScreen.main.bounds.width - Spacing.XL * 2)
32
+ .clipped()
33
+ }
34
+ .scaledToFill()
35
+ .aspectRatio(0.72, contentMode: .fit)
36
+ .frame(maxWidth: UIScreen.main.bounds.width - Spacing.XL * 2, alignment: .center)
37
+ .clipped()
38
+ .onTapGesture {
39
+ onAction?()
40
+ }
41
+ }
42
+ buildCloseIcon()
43
+ .accessibility(identifier: "ic_popup_close")
44
+ }
45
+ .accessibilityElement(children: .ignore)
46
+ .accessibility(identifier: "popup_promotion")
47
+ }
48
+
49
+ @ViewBuilder
50
+ private func buildCloseIcon() -> some View {
51
+ HStack(alignment: .center, spacing: 0) {
52
+ SwiftUI.Button(action: {
53
+ onIconClose?()
54
+ }) {
55
+ ZStack {
56
+ Circle()
57
+ .strokeBorder(Colors.black01, lineWidth: 2)
58
+ .background(Circle().fill(Colors.black17))
59
+ .frame(width: 22, height: 22)
60
+
61
+ Icon(source: "navigation_close", size: 16, color: Colors.black01)
62
+ }
63
+ .frame(width: 40, height: 40)
64
+ .padding(8)
65
+ .zIndex(1)
66
+ }
67
+ }
68
+ }
69
+
70
+ }
71
+
72
+
73
+