@momo-kits/native-kits 0.167.1-duo.3-debug → 0.167.1-duo.4

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 (189) hide show
  1. package/CLAUDE.md +17 -8
  2. package/ios/Application/ApplicationEnvironment.swift +6 -0
  3. package/ios/Application/Components.swift +1 -3
  4. package/ios/Application/HeaderRight.swift +19 -27
  5. package/ios/Application/Navigation/BottomTab/BottomTab.swift +9 -30
  6. package/ios/Application/Navigation/BottomTab/BottomTabBar.swift +2 -5
  7. package/ios/Application/Navigation/HeaderUser.swift +1 -7
  8. package/ios/Application/Navigation/NavigationContainer.swift +45 -45
  9. package/ios/Application/Navigation/Navigator.swift +122 -29
  10. package/ios/Application/Navigation/NavigatorManager.swift +13 -6
  11. package/ios/Application/Navigation/Overplay/BottomSheet.swift +4 -41
  12. package/ios/Application/Navigation/Overplay/ModalScreen.swift +1 -5
  13. package/ios/Application/Navigation/component/Header.swift +4 -12
  14. package/ios/Application/Navigation/component/HeaderBackground.swift +2 -3
  15. package/ios/Application/Navigation/component/NavigationFooter.swift +1 -1
  16. package/ios/Application/Navigation/component/NavigationHeaderRight.swift +9 -61
  17. package/ios/Application/StackScreen.swift +18 -135
  18. package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +59 -5
  19. package/ios/Colors+Radius+Spacing/Colors.swift +1 -1
  20. package/ios/Extensions/Color++.swift +20 -9
  21. package/ios/Extensions/OptionalEnvironmentObject.swift +12 -0
  22. package/ios/Icon/Icon.swift +14 -22
  23. package/ios/Icon/Icons.swift +1329 -0
  24. package/ios/Image/Image.swift +16 -5
  25. package/ios/Lottie/LottieView.swift +4 -2
  26. package/ios/Popup/PopupDisplay.swift +68 -84
  27. package/ios/Popup/PopupNotify.swift +32 -43
  28. package/ios/Popup/PopupPromotion.swift +6 -18
  29. package/ios/Resources/dot_loading.json +558 -0
  30. package/ios/Resources/lottie_circle_loader.json +1 -0
  31. package/ios/Template/TrustBanner/TrustBanner.swift +69 -31
  32. package/ios/native-kits.podspec +1 -1
  33. package/ios-demo/MoMoUIKitsDemo.podspec +1 -1
  34. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/Home.swift +0 -1
  35. package/package.json +1 -1
  36. package/scripts/gen-ios-icons.mjs +36 -0
  37. package/.claude/scheduled_tasks.lock +0 -1
  38. package/.claude/settings.local.json +0 -185
  39. package/build.gradle.kts +0 -11
  40. package/compose/build.gradle.kts +0 -204
  41. package/compose/build.gradle.kts.backup +0 -204
  42. package/compose/compose.podspec +0 -47
  43. package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
  44. package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
  45. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
  46. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
  47. package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -153
  48. package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
  49. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -124
  50. package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
  51. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
  52. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
  53. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
  54. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
  55. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
  56. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
  57. package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
  58. package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -831
  59. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
  60. package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
  61. package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
  62. package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
  63. package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
  64. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
  65. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -82
  66. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
  67. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
  68. package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
  69. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -356
  70. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -113
  71. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
  72. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
  73. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
  74. package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
  75. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -49
  76. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
  77. package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
  78. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
  79. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -189
  80. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -475
  81. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
  82. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -266
  83. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -240
  84. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -223
  85. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -264
  86. package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -185
  87. package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
  88. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
  89. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
  90. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
  91. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
  92. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
  93. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -361
  94. package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -108
  95. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -310
  96. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
  97. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
  98. package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
  99. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
  100. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -323
  101. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -220
  102. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
  103. package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
  104. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -199
  105. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
  106. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -552
  107. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -88
  108. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -125
  109. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -207
  110. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -498
  111. package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -176
  112. package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
  113. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
  114. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
  115. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -234
  116. package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -188
  117. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
  118. package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -16
  119. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +0 -18
  120. package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
  121. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
  122. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
  123. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
  124. package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -297
  125. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -54
  126. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -50
  127. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +0 -187
  128. package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -41
  129. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
  130. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
  131. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
  132. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
  133. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
  134. package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
  135. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -338
  136. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +0 -58
  137. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -137
  138. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -106
  139. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -205
  140. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -393
  141. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
  142. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -648
  143. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -148
  144. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -35
  145. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -194
  146. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -232
  147. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
  148. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +0 -281
  149. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
  150. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -408
  151. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -108
  152. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +0 -105
  153. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +0 -74
  154. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -354
  155. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -37
  156. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -363
  157. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +0 -169
  158. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
  159. package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
  160. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -12
  161. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
  162. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
  163. package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -74
  164. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
  165. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
  166. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
  167. package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -118
  168. package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -40
  169. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -45
  170. package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
  171. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -38
  172. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
  173. package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -217
  174. package/gradle/libs.versions.toml +0 -69
  175. package/gradle/wrapper/gradle-wrapper.jar +0 -0
  176. package/gradle/wrapper/gradle-wrapper.properties +0 -8
  177. package/gradle.properties +0 -26
  178. package/gradlew +0 -252
  179. package/gradlew.bat +0 -94
  180. package/ios/Application/Layout/ScreenLayout.swift +0 -196
  181. package/ios/Application/Navigation/BottomTab/DuoTabBar.swift +0 -275
  182. package/ios/Application/Navigation/component/DuoScrollGradient.swift +0 -55
  183. package/ios/Application/Navigation/component/SideBar.swift +0 -155
  184. package/ios/Popup/PopupLayout.swift +0 -45
  185. package/ios-demo/README.md +0 -120
  186. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/DuoTabDemo.swift +0 -76
  187. package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/IPhoneDuoDemo.swift +0 -170
  188. package/local.properties +0 -8
  189. package/settings.gradle.kts +0 -64
@@ -41,11 +41,7 @@ public struct ImageView: View {
41
41
  .placeholder {
42
42
  VStack(alignment: .center, content: {
43
43
  if error {
44
- Image("media_fail")
45
- .resizable()
46
- .renderingMode(.template)
47
- .foregroundColor(theme.colors.text.disable)
48
- .frame(width: 24, height: 24)
44
+ ImageErrorIcon(color: theme.colors.text.disable)
49
45
  } else if placeholder != nil {
50
46
  placeholder
51
47
  }
@@ -74,6 +70,21 @@ public struct ImageView: View {
74
70
  var url: String
75
71
  }
76
72
 
73
+ // A bare WebImage on purpose: going through `Icon` nests another `ImageView`, whose own
74
+ // failure would render this placeholder again, without end while offline.
75
+ private struct ImageErrorIcon: View {
76
+ let color: Color
77
+
78
+ var body: some View {
79
+ WebImage(url: URL(string: iconSources["media_fail"] ?? ""))
80
+ .resizable()
81
+ .renderingMode(.template)
82
+ .scaledToFit()
83
+ .foregroundColor(color)
84
+ .frame(width: 24, height: 24)
85
+ }
86
+ }
87
+
77
88
  private struct ColorMultiplyModifier: ViewModifier {
78
89
  let color: Color?
79
90
 
@@ -36,7 +36,8 @@ struct LottieView: UIViewRepresentable {
36
36
  animationView.animation = cachedAnimation
37
37
  setupAnimationView(animationView, view)
38
38
  } else {
39
- LottieAnimation.loadedFrom(url: URL(string: url)!, closure: { animation in
39
+ guard let animationURL = URL(string: url) else { return view }
40
+ LottieAnimation.loadedFrom(url: animationURL, closure: { animation in
40
41
  if let animation = animation {
41
42
  Self.animationCache.setObject(animation, forKey: url as NSString)
42
43
  animationView.animation = animation
@@ -49,7 +50,8 @@ struct LottieView: UIViewRepresentable {
49
50
  if let cachedAnimation = Self.animationCache.object(forKey: name as NSString) {
50
51
  animationView.animation = cachedAnimation
51
52
  setupAnimationView(animationView, view)
52
- } else if let animation = LottieAnimation.named(name) {
53
+ } else if let animation = LottieAnimation.named(name, bundle: MoMoUIKitsResources.bundle)
54
+ ?? LottieAnimation.named(name) {
53
55
  Self.animationCache.setObject(animation, forKey: name as NSString)
54
56
  animationView.animation = animation
55
57
  setupAnimationView(animationView, view)
@@ -55,7 +55,6 @@ extension View {
55
55
 
56
56
  public struct PopupDisplay: View {
57
57
  @Environment(\.localize) private var localize
58
- @Environment(\.screenLayout) private var layout
59
58
 
60
59
  // MARK: Lifecycle
61
60
 
@@ -92,7 +91,6 @@ public struct PopupDisplay: View {
92
91
 
93
92
  @State private var textHeight: CGFloat = .zero
94
93
  @State private var isScrollable = false
95
- @State private var actionsHeight: CGFloat = 0
96
94
 
97
95
  public var body: some View {
98
96
  var shouldUseColumn: Bool {
@@ -116,103 +114,89 @@ public struct PopupDisplay: View {
116
114
  }
117
115
 
118
116
  VStack(spacing: 0) {
119
- // scrolls when iPhone Duo landscape is too short; actions stay visible
120
- PopupScrollBody(maxHeight: layout.popupMaxHeight.map { $0 - actionsHeight }) {
121
- VStack(spacing: 0) {
122
- if(!url.isEmpty) {
123
- WebImage(url: URL(string: url), isAnimating: .constant(true))
124
- .resizable()
125
- .placeholder {
126
- Rectangle()
127
- .fill(Color.gray.opacity(0.3))
128
- .aspectRatio(1.777, contentMode: .fit)
129
- .frame(maxWidth: .infinity, maxHeight: 184)
130
- }
117
+ if(!url.isEmpty) {
118
+ WebImage(url: URL(string: url), isAnimating: .constant(true))
119
+ .resizable()
120
+ .placeholder {
121
+ Rectangle()
122
+ .fill(Color.gray.opacity(0.3))
131
123
  .aspectRatio(1.777, contentMode: .fit)
132
- .frame(maxWidth: .infinity, alignment: .center)
133
- .clipShape(RoundedCorner(radius: 15, corners: [.topLeft, .topRight]))
134
- .clipped()
124
+ .frame(maxWidth: .infinity, maxHeight: 184)
135
125
  }
136
- VStack(alignment: .leading, spacing: 0) {
137
- MomoText(title, typography: .headerDefaultBold)
138
- .padding(.top, 24)
139
- .padding(.bottom, 8)
140
- .lineLimit(2)
141
- .accessibility(identifier: "title_popup_permission")
142
-
143
- Group {
144
- if isScrollable {
145
- ScrollView(showsIndicators: false) {
146
- MomoText(description, typography: .bodyDefaultRegular)
147
- .multilineTextAlignment(.leading)
148
- .background(GeometryReader { geo in
149
- Color.clear.onAppear { textHeight = geo.size.height }
150
- })
151
- .measureLineHeights(font: .body_default_regular,
152
- oneLine: $oneLineH,
153
- twoLines: $twoLineH)
154
- .accessibility(identifier: "description_popup_permission")
155
- }
156
- // Cap the visible height to ~8.5 lines
157
- .frame(height: min(maxHeight8_5, textHeight))
158
- } else {
159
- MomoText(description, typography: .bodyDefaultRegular)
160
- .multilineTextAlignment(.leading)
161
- .background(GeometryReader { geo in
162
- Color.clear.onAppear {
163
- textHeight = geo.size.height
164
- // Trigger scroll at ~8.5 lines
165
- isScrollable = textHeight > maxHeight8_5
166
- }
167
- })
168
- .measureLineHeights(font: .body_default_regular,
169
- oneLine: $oneLineH,
170
- twoLines: $twoLineH)
171
- .accessibility(identifier: "description_popup_permission")
172
- }
173
- }
174
- .padding(.bottom, 8)
126
+ .aspectRatio(1.777, contentMode: .fit)
127
+ .frame(maxWidth: .infinity, alignment: .center)
128
+ .clipShape(RoundedCorner(radius: 15, corners: [.topLeft, .topRight]))
129
+ .clipped()
130
+ }
131
+ VStack(alignment: .leading, spacing: 0) {
132
+ MomoText(title, typography: .headerDefaultBold)
133
+ .padding(.top, 24)
134
+ .padding(.bottom, 8)
135
+ .lineLimit(2)
136
+ .accessibility(identifier: "title_popup_permission")
175
137
 
176
- if(!errorCode.isEmpty) {
177
- MomoText(localize.translate("errorCode") + errorCode, typography: .descriptionXsRegular, color: Colors.black12)
178
- .lineLimit(1)
179
- .padding(.bottom, 8)
138
+ Group {
139
+ if isScrollable {
140
+ ScrollView(showsIndicators: false) {
141
+ MomoText(description, typography: .bodyDefaultRegular)
142
+ .multilineTextAlignment(.leading)
143
+ .background(GeometryReader { geo in
144
+ Color.clear.onAppear { textHeight = geo.size.height }
145
+ })
146
+ .measureLineHeights(font: .body_default_regular,
147
+ oneLine: $oneLineH,
148
+ twoLines: $twoLineH)
149
+ .accessibility(identifier: "description_popup_permission")
180
150
  }
151
+ // Cap the visible height to ~8.5 lines
152
+ .frame(height: min(maxHeight8_5, textHeight))
153
+ } else {
154
+ MomoText(description, typography: .bodyDefaultRegular)
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
+ .accessibility(identifier: "description_popup_permission")
181
167
  }
182
- .frame(maxWidth: .infinity, alignment: .leading)
183
- .padding(.horizontal, 24)
184
- .padding(.bottom, 16)
168
+ }
169
+ .padding(.bottom, 8)
170
+
171
+ if(!errorCode.isEmpty) {
172
+ MomoText(localize.translate("errorCode") + errorCode, typography: .descriptionXsRegular, color: Colors.black12)
173
+ .lineLimit(1)
174
+ .padding(.bottom, 8)
185
175
  }
186
176
  }
187
-
188
- Group {
189
- if shouldUseColumn {
190
- if buttonType == .text {
191
- ColumnTextButtons
192
- } else {
193
- ColumnButtons
194
- }
177
+ .frame(maxWidth: .infinity, alignment: .leading)
178
+ .padding(.horizontal, 24)
179
+ .padding(.bottom, 16)
180
+
181
+ if shouldUseColumn {
182
+ if buttonType == .text {
183
+ ColumnTextButtons
195
184
  } else {
196
- if buttonType == .text {
197
- RowTextButtons
198
- } else {
199
- RowButtons
200
- }
185
+ ColumnButtons
201
186
  }
202
- }
203
- .background(
204
- GeometryReader { proxy in
205
- Color.clear
206
- .onAppear { actionsHeight = proxy.size.height }
207
- .onChange(of: proxy.size.height) { actionsHeight = $0 }
187
+ } else {
188
+ if buttonType == .text {
189
+ RowTextButtons
190
+ } else {
191
+ RowButtons
208
192
  }
209
- )
193
+ }
210
194
  }
211
195
  .fixedSize(horizontal: false, vertical: true)
212
196
  }
213
197
  }
214
198
  .background(Color.white.cornerRadius(15))
215
- .frame(maxWidth: layout.popupMaxWidth)
199
+ .frame(maxWidth: popupMaxWidth - 24)
216
200
  .padding(.horizontal, 12)
217
201
  .accessibilityElement(children: .ignore)
218
202
  .accessibility(identifier: "popup_notify")
@@ -3,6 +3,12 @@ import SwiftUI
3
3
 
4
4
  public typealias PopupActionDirection = PopupButtonDirection
5
5
 
6
+ // Portrait width in landscape too, so aspect-ratio images don't push popups past the screen height.
7
+ var popupMaxWidth: CGFloat {
8
+ let size = UIScreen.main.bounds.size
9
+ return min(size.width, size.height)
10
+ }
11
+
6
12
  public struct PopupNotifyProps {
7
13
  public var image: String
8
14
  public var title: String
@@ -40,12 +46,10 @@ public struct PopupNotifyProps {
40
46
  public struct PopupNotify: View {
41
47
  @Environment(\.localize) private var localize
42
48
  @Environment(\.momoFontScale) private var fontScale
43
- @Environment(\.screenLayout) private var layout
44
49
 
45
50
  public let props: PopupNotifyProps
46
51
 
47
52
  @State private var descriptionHeight: CGFloat = 0
48
- @State private var actionsHeight: CGFloat = 0
49
53
 
50
54
  private var errorCodePrefix: String {
51
55
  localize.translate("errorCode")
@@ -73,26 +77,37 @@ public struct PopupNotify: View {
73
77
  public var body: some View {
74
78
  ZStack(alignment: .topTrailing) {
75
79
  VStack(spacing: 0) {
76
- // scrolls when iPhone Duo landscape is too short; actions stay visible
77
- PopupScrollBody(maxHeight: layout.popupMaxHeight.map { $0 - actionsHeight }) {
78
- VStack(spacing: 0) {
79
- if !props.image.isEmpty {
80
- popupImage
81
- }
82
- textContent
80
+ if !props.image.isEmpty {
81
+ popupImage
82
+ }
83
+
84
+ VStack(alignment: .leading, spacing: 0) {
85
+ MomoText(
86
+ props.title,
87
+ typography: .headerDefaultBold,
88
+ maxLines: 2,
89
+ accessibilityId: "title_popup_permission"
90
+ )
91
+ .padding(.bottom, Spacing.S)
92
+
93
+ descriptionContent
94
+
95
+ if !props.error.isEmpty {
96
+ MomoText(
97
+ errorCodePrefix + props.error,
98
+ typography: .descriptionXsRegular,
99
+ color: Colors.black12,
100
+ maxLines: 1
101
+ )
102
+ .padding(.top, Spacing.S)
83
103
  }
84
104
  }
105
+ .frame(maxWidth: .infinity, alignment: .leading)
106
+ .padding(Spacing.XL)
85
107
 
86
108
  actionButtons
87
109
  .padding(.horizontal, Spacing.XL)
88
110
  .padding(.bottom, Spacing.XL)
89
- .background(
90
- GeometryReader { proxy in
91
- Color.clear
92
- .onAppear { actionsHeight = proxy.size.height }
93
- .onChange(of: proxy.size.height) { actionsHeight = $0 }
94
- }
95
- )
96
111
  }
97
112
  .background(Colors.black01)
98
113
  .clipShape(RoundedRectangle(cornerRadius: Radius.L))
@@ -102,38 +117,12 @@ public struct PopupNotify: View {
102
117
  .offset(x: 11, y: -11)
103
118
  }
104
119
  }
105
- .frame(maxWidth: layout.popupMaxWidth)
120
+ .frame(maxWidth: popupMaxWidth - Spacing.M * 2)
106
121
  .padding(.horizontal, Spacing.M)
107
122
  .accessibilityElement(children: .ignore)
108
123
  .accessibilityIdentifier("popup_notify")
109
124
  }
110
125
 
111
- private var textContent: some View {
112
- VStack(alignment: .leading, spacing: 0) {
113
- MomoText(
114
- props.title,
115
- typography: .headerDefaultBold,
116
- maxLines: 2,
117
- accessibilityId: "title_popup_permission"
118
- )
119
- .padding(.bottom, Spacing.S)
120
-
121
- descriptionContent
122
-
123
- if !props.error.isEmpty {
124
- MomoText(
125
- errorCodePrefix + props.error,
126
- typography: .descriptionXsRegular,
127
- color: Colors.black12,
128
- maxLines: 1
129
- )
130
- .padding(.top, Spacing.S)
131
- }
132
- }
133
- .frame(maxWidth: .infinity, alignment: .leading)
134
- .padding(Spacing.XL)
135
- }
136
-
137
126
  private var popupImage: some View {
138
127
  WebImage(url: URL(string: props.image), isAnimating: .constant(true))
139
128
  .resizable()
@@ -3,7 +3,6 @@ import SDWebImageSwiftUI
3
3
 
4
4
  public struct PopupPromotion: View {
5
5
  @Environment(\.appTheme) private var theme
6
- @Environment(\.screenLayout) private var layout
7
6
 
8
7
  var imageUrl: String
9
8
  var onIconClose: (() -> Void)?
@@ -20,33 +19,22 @@ public struct PopupPromotion: View {
20
19
  self.onAction = onAction
21
20
  }
22
21
 
23
- private static let aspectRatio: CGFloat = 0.72
24
- // close button row under the image: stack spacing + padded 40pt button
25
- private static let closeRowHeight: CGFloat = 8 + 40 + Spacing.S * 2
26
-
27
- // fit the portrait image by height when iPhone Duo leaves too little room
28
- private var imageWidth: CGFloat {
29
- let width = min(layout.width - Spacing.XL * 2, layout.popupMaxWidth)
30
- guard let maxHeight = layout.popupMaxHeight else { return width }
31
- return min(width, (maxHeight - Self.closeRowHeight) * Self.aspectRatio)
32
- }
33
-
34
22
  public var body: some View {
35
23
  VStack(spacing: 8) {
36
24
  if(imageUrl.isEmpty) {
37
- Icon(source: "media_fail", size: imageWidth)
25
+ Icon(source: "media_fail", size: popupMaxWidth - Spacing.XL * 2)
38
26
  }
39
27
  else {
40
- WebImage(url: URL(string: imageUrl)!)
28
+ WebImage(url: URL(string: imageUrl))
41
29
  .resizable()
42
30
  .placeholder {
43
31
  Color.gray
44
- .aspectRatio(Self.aspectRatio, contentMode: .fit)
45
- .frame(maxWidth: imageWidth)
32
+ .aspectRatio(0.72, contentMode: .fit)
33
+ .frame(maxWidth: popupMaxWidth - Spacing.XL * 2)
46
34
  .clipped()
47
35
  }
48
- .aspectRatio(Self.aspectRatio, contentMode: .fit)
49
- .frame(maxWidth: imageWidth, alignment: .center)
36
+ .aspectRatio(0.72, contentMode: .fit)
37
+ .frame(maxWidth: popupMaxWidth - Spacing.XL * 2, alignment: .center)
50
38
  .clipped()
51
39
  .onTapGesture {
52
40
  onAction?()