@momo-kits/native-kits 0.0.1-beta.4 → 0.2.0-kt22

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 (131) hide show
  1. package/README.md +176 -5
  2. package/ios/Application/ApplicationEnvironment.swift +50 -0
  3. package/ios/Application/Components.swift +263 -0
  4. package/ios/Application/ComposeApi.swift +22 -0
  5. package/ios/Application/FloatingButton.swift +172 -0
  6. package/ios/Application/HeaderRight.swift +271 -0
  7. package/ios/Application/Screen.swift +249 -0
  8. package/ios/Badge/Badge.swift +85 -0
  9. package/ios/Badge/BadgeDot.swift +31 -0
  10. package/ios/Badge/BadgeRibbon.swift +242 -0
  11. package/ios/Button/Button.swift +169 -89
  12. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
  13. package/ios/Checkbox/Checkbox.swift +81 -0
  14. package/ios/Chip/Chip.swift +96 -0
  15. package/ios/{Colors+Spacing → Colors+Radius+Spacing}/Colors.swift +21 -19
  16. package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
  17. package/ios/Icon/Icon.swift +51 -0
  18. package/ios/Image/Image.swift +70 -0
  19. package/ios/Input/ErrorView.swift +55 -0
  20. package/ios/Input/Input.swift +159 -50
  21. package/ios/Input/InputPhoneNumber.swift +158 -0
  22. package/ios/Input/InputSearch.swift +238 -0
  23. package/ios/Input/InputTextArea.swift +242 -0
  24. package/ios/Lottie/LottieView.swift +86 -0
  25. package/ios/OTPKeyboard/KeyboardButton.swift +12 -4
  26. package/ios/OTPKeyboard/OTPKeyboard.swift +1 -1
  27. package/ios/Popup/PopupDisplay.swift +287 -0
  28. package/ios/Popup/PopupInput.swift +96 -0
  29. package/ios/Popup/PopupPromotion.swift +73 -0
  30. package/ios/PopupView/FullscreenPopup.swift +251 -0
  31. package/ios/{Popup → PopupView}/Modifiers.swift +6 -20
  32. package/ios/{Popup → PopupView}/PopupView.swift +38 -146
  33. package/ios/PopupView/Utils++.swift +281 -0
  34. package/ios/ScrollIndicator/ScrollIndicator.swift +110 -0
  35. package/ios/Swipeable/SwipeCell.swift +39 -31
  36. package/ios/Switch/Switch.swift +44 -0
  37. package/ios/Template/Logo/Logo.swift +75 -0
  38. package/ios/Template/TrustBanner/TrustBanner.swift +120 -0
  39. package/ios/Typography/Text.swift +140 -0
  40. package/ios/Typography/Typography.swift +70 -5
  41. package/ios/native-kits.podspec +20 -15
  42. package/package.json +6 -6
  43. package/CODE_OF_CONDUCT.md +0 -133
  44. package/CONTRIBUTING.md +0 -114
  45. package/LICENSE +0 -20
  46. package/android/build.gradle +0 -82
  47. package/android/gradle.properties +0 -5
  48. package/android/src/main/AndroidManifest.xml +0 -4
  49. package/android/src/main/java/com/momoplatform/nativekits/NativeKitsPackage.kt +0 -17
  50. package/android/src/main/java/com/momoplatform/nativekits/NativeKitsViewManager.kt +0 -20
  51. package/example/ios/Example/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -63
  52. package/example/ios/Example/Assets.xcassets/Background.colorset/Contents.json +0 -38
  53. package/example/ios/Example/Assets.xcassets/Border.colorset/Contents.json +0 -38
  54. package/example/ios/Example/Assets.xcassets/Card.colorset/Contents.json +0 -38
  55. package/example/ios/Example/Assets.xcassets/Contents.json +0 -6
  56. package/example/ios/Example/Assets.xcassets/Error.colorset/Contents.json +0 -38
  57. package/example/ios/Example/Assets.xcassets/Primary.colorset/Contents.json +0 -38
  58. package/example/ios/Example/Assets.xcassets/PrimaryDark.colorset/Contents.json +0 -38
  59. package/example/ios/Example/Assets.xcassets/PrimaryLight.colorset/Contents.json +0 -38
  60. package/example/ios/Example/Assets.xcassets/Secondary.colorset/Contents.json +0 -38
  61. package/example/ios/Example/Assets.xcassets/Success.colorset/Contents.json +0 -38
  62. package/example/ios/Example/Assets.xcassets/Text.colorset/Contents.json +0 -38
  63. package/example/ios/Example/Assets.xcassets/TextSecondary.colorset/Contents.json +0 -38
  64. package/example/ios/Example/Assets.xcassets/Warning.colorset/Contents.json +0 -38
  65. package/example/ios/Example/ComponentDetail.swift +0 -35
  66. package/example/ios/Example/ComponentItem.swift +0 -24
  67. package/example/ios/Example/ComponentModel.swift +0 -33
  68. package/example/ios/Example/ContentView.swift +0 -53
  69. package/example/ios/Example/Example.entitlements +0 -10
  70. package/example/ios/Example/Foundation/ButtonDemo.swift +0 -80
  71. package/example/ios/Example/Foundation/Popup/ActionSheets.swift +0 -136
  72. package/example/ios/Example/Foundation/Popup/Floats.swift +0 -127
  73. package/example/ios/Example/Foundation/Popup/Popups.swift +0 -101
  74. package/example/ios/Example/Foundation/PopupDemo.swift +0 -366
  75. package/example/ios/Example/Foundation/TextInputDemo.swift +0 -31
  76. package/example/ios/Example/Foundation/TypographyDemo.swift +0 -53
  77. package/example/ios/Example/Foundation.swift +0 -26
  78. package/example/ios/Example/Info.plist +0 -18
  79. package/example/ios/Example/Library/SwipeableDemo.swift +0 -105
  80. package/example/ios/Example/Library.swift +0 -26
  81. package/example/ios/Example/Main.swift +0 -11
  82. package/example/ios/Example/Overview.swift +0 -20
  83. package/example/ios/Example/Preview Content/Preview Assets.xcassets/Contents.json +0 -6
  84. package/example/ios/Example/Resource/SFProText-Black.ttf +0 -0
  85. package/example/ios/Example/Resource/SFProText-Bold.ttf +0 -0
  86. package/example/ios/Example/Resource/SFProText-Heavy.ttf +0 -0
  87. package/example/ios/Example/Resource/SFProText-Light.ttf +0 -0
  88. package/example/ios/Example/Resource/SFProText-Medium.ttf +0 -0
  89. package/example/ios/Example/Resource/SFProText-Regular.ttf +0 -0
  90. package/example/ios/Example/Resource/SFProText-Semibold.ttf +0 -0
  91. package/example/ios/Example/Resource/SFProText-Thin.ttf +0 -0
  92. package/example/ios/Example/Resource/SFProText-Ultralight.ttf +0 -0
  93. package/example/ios/Example/Resource/foundation.json +0 -33
  94. package/example/ios/Example/Resource/library.json +0 -8
  95. package/example/ios/Example/Utils.swift +0 -30
  96. package/example/ios/Example/ViewModifier/DarkViewModifier.swift +0 -22
  97. package/example/ios/Example.xcodeproj/project.pbxproj +0 -570
  98. package/example/ios/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
  99. package/example/ios/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  100. package/example/ios/Example.xcodeproj/project.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  101. package/example/ios/Example.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
  102. package/example/ios/Example.xcworkspace/contents.xcworkspacedata +0 -10
  103. package/example/ios/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
  104. package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
  105. package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
  106. package/example/ios/Podfile +0 -6
  107. package/example/ios/Podfile.lock +0 -16
  108. package/example/ios/Pods/Local Podspecs/MoMoUIKits.podspec.json +0 -29
  109. package/example/ios/Pods/Manifest.lock +0 -16
  110. package/example/ios/Pods/Pods.xcodeproj/project.pbxproj +0 -661
  111. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
  112. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
  113. package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -25
  114. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-dummy.m +0 -5
  115. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-prefix.pch +0 -12
  116. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-umbrella.h +0 -16
  117. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.debug.xcconfig +0 -12
  118. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.modulemap +0 -6
  119. package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.release.xcconfig +0 -12
  120. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.markdown +0 -3
  121. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.plist +0 -29
  122. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-dummy.m +0 -5
  123. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-umbrella.h +0 -16
  124. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig +0 -14
  125. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.modulemap +0 -6
  126. package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig +0 -14
  127. package/ios/Colors+Spacing/Radius.swift +0 -11
  128. package/ios/Popup/Utils++.swift +0 -163
  129. package/ios/Theme.md +0 -18
  130. package/publish.sh +0 -28
  131. /package/ios/{Colors+Spacing → Colors+Radius+Spacing}/Spacing.swift +0 -0
@@ -0,0 +1,86 @@
1
+ //
2
+ // LottieView.swift
3
+ // MoMoPlatform
4
+ //
5
+ // Created by thanhdat on 16/01/2023.
6
+ // Copyright © 2023 Facebook. All rights reserved.
7
+ //
8
+
9
+ import SwiftUI
10
+ import Lottie
11
+
12
+ struct LottieView: UIViewRepresentable {
13
+ var name: String = ""
14
+ var url: String?
15
+ var loopMode: LottieLoopMode = .playOnce
16
+ var contentMode : UIView.ContentMode = .scaleAspectFit
17
+ var onDone: (() -> Void)?
18
+
19
+ // Add static cache for animations
20
+ private static var animationCache = NSCache<NSString, LottieAnimation>()
21
+
22
+ func makeUIView(context: UIViewRepresentableContext<LottieView>) -> UIView {
23
+ let view = UIView(frame: .zero)
24
+
25
+ // Configure Lottie with optimized settings
26
+ let configuration = LottieConfiguration(
27
+ renderingEngine: .coreAnimation,
28
+ decodingStrategy: .dictionaryBased
29
+ )
30
+
31
+ let animationView = LottieAnimationView(configuration: configuration)
32
+
33
+ if let url = url {
34
+ // Use cached animation if available
35
+ if let cachedAnimation = Self.animationCache.object(forKey: url as NSString) {
36
+ animationView.animation = cachedAnimation
37
+ setupAnimationView(animationView, view)
38
+ } else {
39
+ LottieAnimation.loadedFrom(url: URL(string: url)!, closure: { animation in
40
+ if let animation = animation {
41
+ Self.animationCache.setObject(animation, forKey: url as NSString)
42
+ animationView.animation = animation
43
+ setupAnimationView(animationView, view)
44
+ }
45
+ }, animationCache: nil)
46
+ }
47
+ } else {
48
+ // Use cached animation if available
49
+ if let cachedAnimation = Self.animationCache.object(forKey: name as NSString) {
50
+ animationView.animation = cachedAnimation
51
+ setupAnimationView(animationView, view)
52
+ } else if let animation = LottieAnimation.named(name) {
53
+ Self.animationCache.setObject(animation, forKey: name as NSString)
54
+ animationView.animation = animation
55
+ setupAnimationView(animationView, view)
56
+ }
57
+ }
58
+
59
+ return view
60
+ }
61
+
62
+ private func setupAnimationView(_ animationView: LottieAnimationView, _ containerView: UIView) {
63
+ animationView.contentMode = contentMode
64
+ animationView.loopMode = loopMode
65
+ animationView.backgroundBehavior = loopMode == .loop ? .pauseAndRestore : .pause
66
+
67
+ // Optimize rendering
68
+ animationView.shouldRasterizeWhenIdle = true
69
+
70
+ animationView.translatesAutoresizingMaskIntoConstraints = false
71
+ containerView.addSubview(animationView)
72
+
73
+ NSLayoutConstraint.activate([
74
+ animationView.widthAnchor.constraint(equalTo: containerView.widthAnchor),
75
+ animationView.heightAnchor.constraint(equalTo: containerView.heightAnchor)
76
+ ])
77
+
78
+ animationView.play { finished in
79
+ if finished {
80
+ onDone?()
81
+ }
82
+ }
83
+ }
84
+
85
+ func updateUIView(_ uiView: UIView, context: UIViewRepresentableContext<LottieView>) {}
86
+ }
@@ -8,9 +8,13 @@ typealias SwiftButton = SwiftUI.Button
8
8
  public struct KeyboardButton: View {
9
9
  // MARK: Lifecycle
10
10
 
11
- public init(_ key: String, action: @escaping (_ key: String)->Void) {
11
+ public init(_ key: String, action: @escaping (_ key: String)->Void, width: CGFloat = .infinity, height: CGFloat = 48, color: Color = Colors.card, textColor: Color = Colors.text) {
12
12
  self.key = key
13
13
  self.action = action
14
+ self.width = width
15
+ self.height = height
16
+ self.color = color
17
+ self.textColor = textColor
14
18
  }
15
19
 
16
20
  // MARK: Public
@@ -19,9 +23,9 @@ public struct KeyboardButton: View {
19
23
  SwiftUI.Button(action: { self.action(key) }) {
20
24
  HStack {
21
25
  Text(key).font(.system(size: 24, weight: .bold))
22
- }.frame(maxWidth: .infinity, minHeight: 48)
23
- .background(Colors.card)
24
- .foregroundColor(Colors.text)
26
+ }.frame(maxWidth: CGFloat(width), minHeight: height)
27
+ .background(color)
28
+ .foregroundColor(textColor)
25
29
  .clipShape(RoundedRectangle(cornerRadius: 8))
26
30
  }
27
31
  }
@@ -30,4 +34,8 @@ public struct KeyboardButton: View {
30
34
 
31
35
  var key: String = ""
32
36
  var action: (_ key: String)->Void
37
+ var width: CGFloat
38
+ var height: CGFloat
39
+ var color: Color
40
+ var textColor: Color
33
41
  }
@@ -119,7 +119,7 @@ public struct OTPKeyboard: View {
119
119
  private struct ValueView: View {
120
120
  // MARK: Lifecycle
121
121
 
122
- public init(_ value: String, valueLength: Int) {
122
+ init(_ value: String, valueLength: Int) {
123
123
  self.value = value
124
124
  self.valueLength = valueLength
125
125
  }
@@ -0,0 +1,287 @@
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
+ let language = UserDefaults.standard.string(forKey: "language")?.replacingOccurrences(of: "\"", with: "") ?? "vi"
93
+ let errorCodeLabels: [String: String] = ["vi": "Mã lỗi: ", "en": "Error code: "]
94
+
95
+ var shouldUseColumn: Bool {
96
+ buttonDirection == .column || (buttonDirection == .auto && (closeButtonTitle.count > 12 || actionButtonTitle.count > 12))
97
+ }
98
+
99
+ VStack(spacing: 12) {
100
+ ZStack(alignment: .topTrailing) {
101
+ if(isShowCloseIcon) {
102
+ SwiftUI.Button(action: onClose) {
103
+ Image(systemName: "xmark.circle.fill")
104
+ .resizable()
105
+ .frame(width: 22, height: 22)
106
+ .overlay(RoundedRectangle(cornerRadius: Radius.L).stroke(Colors.black01, lineWidth: 2))
107
+ }.foregroundColor(Colors.black20)
108
+ .background(Colors.black01.cornerRadius(15))
109
+ .padding(.trailing, -11)
110
+ .padding(.top, -11)
111
+ .zIndex(1)
112
+ .accessibility(identifier: "ic_popup_close")
113
+ }
114
+
115
+ VStack(spacing: 0) {
116
+ if(!url.isEmpty) {
117
+ WebImage(url: URL(string: url), isAnimating: .constant(true))
118
+ .resizable()
119
+ .placeholder {
120
+ Rectangle()
121
+ .fill(Color.gray.opacity(0.3))
122
+ .frame(maxWidth: .infinity, maxHeight: 184)
123
+ }
124
+ .aspectRatio(1.777, contentMode: .fit)
125
+ .frame(maxWidth: .infinity, alignment: .center)
126
+ .clipShape(RoundedCorner(radius: 15, corners: [.topLeft, .topRight]))
127
+ .clipped()
128
+ }
129
+ VStack(alignment: .leading, spacing: 0) {
130
+ Text(title)
131
+ .foregroundColor(.black)
132
+ .font(.header_default_semibold)
133
+ .padding(.top, 24)
134
+ .padding(.bottom, 8)
135
+ .lineLimit(2)
136
+ .accessibility(identifier: "title_popup_permission")
137
+
138
+ Group {
139
+ if isScrollable {
140
+ ScrollView(showsIndicators: false) {
141
+ Text(description)
142
+ .font(.body_default_regular)
143
+ .foregroundColor(Colors.black17)
144
+ .multilineTextAlignment(.leading)
145
+ .background(GeometryReader { geo in
146
+ Color.clear.onAppear { textHeight = geo.size.height }
147
+ })
148
+ .measureLineHeights(font: .body_default_regular,
149
+ oneLine: $oneLineH,
150
+ twoLines: $twoLineH)
151
+ }
152
+ // Cap the visible height to ~8.5 lines
153
+ .frame(height: min(maxHeight8_5, textHeight))
154
+ } else {
155
+ Text(description)
156
+ .font(.body_default_regular)
157
+ .foregroundColor(Colors.black17)
158
+ .multilineTextAlignment(.leading)
159
+ .background(GeometryReader { geo in
160
+ Color.clear.onAppear {
161
+ textHeight = geo.size.height
162
+ // Trigger scroll at ~8.5 lines
163
+ isScrollable = textHeight > maxHeight8_5
164
+ }
165
+ })
166
+ .measureLineHeights(font: .body_default_regular,
167
+ oneLine: $oneLineH,
168
+ twoLines: $twoLineH)
169
+ }
170
+ }
171
+ .padding(.bottom, 8)
172
+
173
+ if(!errorCode.isEmpty) {
174
+ Text((errorCodeLabels[language] ?? "Mã lỗi: ") + errorCode)
175
+ .foregroundColor(Colors.black12)
176
+ .font(.description_xs_regular)
177
+ .lineLimit(1)
178
+ .padding(.bottom, 8)
179
+ }
180
+ }
181
+ .frame(maxWidth: .infinity, alignment: .leading)
182
+ .padding(.horizontal, 24)
183
+ .padding(.bottom, 16)
184
+
185
+ if shouldUseColumn {
186
+ if buttonType == .text {
187
+ ColumnTextButtons
188
+ } else {
189
+ ColumnButtons
190
+ }
191
+ } else {
192
+ if buttonType == .text {
193
+ RowTextButtons
194
+ } else {
195
+ RowButtons
196
+ }
197
+ }
198
+ }
199
+ .fixedSize(horizontal: false, vertical: true)
200
+ }
201
+ }
202
+ .background(Color.white.cornerRadius(15))
203
+ .padding(.horizontal, 12)
204
+ .accessibilityElement(children: .ignore)
205
+ .accessibility(identifier: "popup_notify")
206
+ }
207
+
208
+ // MARK: Internal
209
+
210
+ @Binding var isPresented: Bool
211
+ var title: String
212
+ var description: String
213
+ var url: String
214
+ var buttonDirection: PopupButtonDirection
215
+ var buttonType: PopupButtonType
216
+ var onPressAction: () -> Void
217
+ var onPressCloseButton: () -> Void
218
+ var onClose: () -> Void
219
+ var actionButtonTitle: String
220
+ var closeButtonTitle: String
221
+ var errorCode: String
222
+ var isShowCloseIcon: Bool
223
+
224
+ var RowTextButtons: some View {
225
+ HStack {
226
+ SwiftUI.Button(action: onPressCloseButton) {
227
+ Text(closeButtonTitle)
228
+ .font(.action2)
229
+ }.foregroundColor(Colors.black09)
230
+ .padding(.trailing, 12)
231
+
232
+ SwiftUI.Button(action: onPressAction) {
233
+ Text(actionButtonTitle)
234
+ .font(.action2)
235
+ }.foregroundColor(Colors.primary)
236
+ }
237
+ .frame(maxWidth: .infinity, alignment: .trailing)
238
+ .padding(EdgeInsets(top: 0, leading: 0, bottom: 24, trailing: 24))
239
+ }
240
+
241
+ var ColumnTextButtons: some View {
242
+ VStack(alignment: .trailing) {
243
+ SwiftUI.Button(action: onPressAction) {
244
+ Text(actionButtonTitle)
245
+ .font(.action2)
246
+ }.foregroundColor(Colors.primary)
247
+ .padding(.bottom, 6)
248
+
249
+ SwiftUI.Button(action: onPressCloseButton) {
250
+ Text(closeButtonTitle)
251
+ .font(.action2)
252
+ }.foregroundColor(Colors.black09)
253
+ }
254
+ .frame(maxWidth: .infinity, alignment: .trailing)
255
+ .padding(EdgeInsets(top: 0, leading: 0, bottom: 24, trailing: 24))
256
+ }
257
+
258
+ var RowButtons: some View {
259
+ HStack {
260
+ if(!closeButtonTitle.isEmpty) {
261
+ Button(title: closeButtonTitle, action: onPressCloseButton, type: .text, size: .medium).accessibility(identifier: "btn_popup_cancel")
262
+ }
263
+ Button(title: actionButtonTitle, action: onPressAction, size: .medium)
264
+ .accessibility(identifier: "btn_popup_allow")
265
+ }
266
+ .frame(maxWidth: .infinity, alignment: .center)
267
+ .padding(.horizontal, 24)
268
+ .padding(.bottom, 24)
269
+ }
270
+
271
+ var ColumnButtons: some View {
272
+ VStack(alignment: .trailing) {
273
+ Button(
274
+ title: actionButtonTitle,
275
+ action: onPressAction,
276
+ size: .medium
277
+ ).accessibility(identifier: "btn_popup_allow")
278
+ if(!closeButtonTitle.isEmpty) {
279
+ Button(title: closeButtonTitle, action: onPressCloseButton, type: .text, size: .medium).accessibility(identifier: "btn_popup_cancel")
280
+ }
281
+ }
282
+ .frame(maxWidth: .infinity, alignment: .trailing)
283
+ .padding(.horizontal, 24)
284
+ .padding(.bottom, 24)
285
+ }
286
+
287
+ }
@@ -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
+