@momo-kits/native-kits 0.167.1-duo.8-debug → 0.167.1-duo.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +4 -1
- package/ios/Application/ApplicationEnvironment.swift +11 -0
- package/ios/Application/ComposeApi.swift +2 -1
- package/ios/Application/{Components.swift → LegacyHeader.swift} +6 -62
- package/ios/Application/Screen.swift +3 -2
- package/ios/Avatar/Avatar.swift +4 -3
- package/ios/Badge/Badge.swift +6 -4
- package/ios/Badge/BadgeDot.swift +1 -1
- package/ios/Badge/BadgeRibbon.swift +0 -1
- package/ios/Button/Button.swift +15 -12
- package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +12 -20
- package/ios/Carousel/Carousel.swift +29 -12
- package/ios/Checkbox/Checkbox.swift +7 -3
- package/ios/Chip/Chip.swift +5 -4
- package/ios/Collapse/Collapse.swift +70 -19
- package/ios/Colors+Radius+Spacing/Colors.swift +9 -0
- package/ios/DateTimePicker/DateTimePicker.swift +54 -20
- package/ios/DateTimePicker/WheelPicker.swift +103 -105
- package/ios/Divider/Divider.swift +37 -4
- package/ios/Extensions/Color++.swift +18 -0
- package/ios/Icon/Icon.swift +7 -1
- package/ios/IconButton/IconButton.swift +15 -7
- package/ios/Image/Image.swift +7 -34
- package/ios/Information/Information.swift +27 -9
- package/ios/Input/ErrorView.swift +2 -2
- package/ios/Input/Input.swift +160 -147
- package/ios/Input/InputPhoneNumber.swift +12 -9
- package/ios/Input/InputSearch.swift +102 -75
- package/ios/Input/InputTextArea.swift +128 -145
- package/ios/InputDropDown/InputDropDown.swift +10 -7
- package/ios/InputMoney/InputMoney.swift +33 -11
- package/ios/InputOTP/InputOTP.swift +22 -12
- package/ios/Layout/Card.swift +50 -0
- package/ios/Layout/GridContext.swift +123 -3
- package/ios/Layout/Item.swift +5 -4
- package/ios/Layout/Section.swift +4 -100
- package/ios/Loader/Loader.swift +5 -9
- package/ios/Lottie/LottieView.swift +10 -0
- package/ios/{Application/Navigation/Overplay → Navigation}/BottomSheet.swift +61 -9
- package/ios/{Application/Navigation → Navigation}/BottomTab/BottomTab.swift +60 -34
- package/ios/{Application/Navigation → Navigation}/BottomTab/BottomTabBar.swift +11 -6
- package/ios/{Application → Navigation/Component}/FloatingButton.swift +14 -3
- package/ios/Navigation/Component/Header.swift +493 -0
- package/ios/Navigation/Component/HeaderBackground.swift +134 -0
- package/ios/Navigation/Component/HeaderJourney.swift +73 -0
- package/ios/Navigation/Component/HeaderLocation.swift +48 -0
- package/ios/Navigation/Component/HeaderRight.swift +386 -0
- package/ios/Navigation/Component/HeaderTitle.swift +36 -0
- package/ios/{Application/Navigation → Navigation/Component}/HeaderUser.swift +20 -23
- package/ios/{Application/Navigation/component → Navigation/Component}/SideBar.swift +49 -28
- package/ios/{Application/Navigation/Overplay → Navigation/Component}/SnackBar.swift +5 -5
- package/ios/Navigation/HostBackGestureBridge.swift +57 -0
- package/ios/Navigation/Navigation.swift +190 -0
- package/ios/{Application/Navigation → Navigation}/NavigationContainer.swift +46 -41
- package/ios/{Application/Navigation → Navigation}/Navigator.swift +65 -9
- package/ios/{Application → Navigation}/StackScreen.swift +236 -103
- package/ios/{Application/Navigation → Navigation}/Tracking/ScreenTracker.swift +12 -5
- package/ios/OTPKeyboard/OTPKeyboard.swift +8 -11
- package/ios/Pagination/PaginationScroll.swift +2 -2
- package/ios/Popup/PopupDisplay.swift +79 -159
- package/ios/Popup/PopupInput.swift +10 -13
- package/ios/Popup/PopupLayout.swift +97 -2
- package/ios/Popup/PopupNotify.swift +27 -55
- package/ios/Popup/PopupPromotion.swift +22 -50
- package/ios/PopupView/FullscreenPopup.swift +13 -19
- package/ios/PopupView/PopupView.swift +1 -1
- package/ios/PopupView/Utils++.swift +0 -8
- package/ios/ProgressInfo/ProgressInfo.swift +4 -2
- package/ios/Radio/Radio.swift +2 -1
- package/ios/Rating/Rating.swift +9 -1
- package/ios/ScrollIndicator/ScrollIndicator.swift +11 -10
- package/ios/Skeleton/Skeleton.swift +22 -27
- package/ios/Slider/Slider.swift +16 -18
- package/ios/Stepper/Stepper.swift +6 -1
- package/ios/Steps/Steps.swift +8 -6
- package/ios/SuggestAction/SuggestAction.swift +5 -0
- package/ios/Swipeable/SwipeCell.swift +10 -6
- package/ios/Switch/Switch.swift +22 -20
- package/ios/TabView/TabView.swift +102 -21
- package/ios/Tag/Tag.swift +15 -4
- package/ios/Template/Logo/Logo.swift +2 -1
- package/ios/Template/TrustBanner/TrustBanner.swift +41 -27
- package/ios/Title/Title.swift +6 -17
- package/ios/Tooltip/Tooltip.swift +29 -14
- package/ios/Typography/Text.swift +61 -19
- package/ios/Uploader/Uploader.swift +3 -1
- package/ios/native-kits.podspec +1 -0
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/ContentView.swift +1 -1
- package/ios-demo/Sources/MoMoUIKitsDemo/SampleDemos/NavigationDemo.swift +77 -1
- package/package.json +1 -1
- package/build.gradle.kts +0 -11
- package/compose/build.gradle.kts +0 -204
- package/compose/build.gradle.kts.backup +0 -204
- package/compose/compose.podspec +0 -47
- package/compose/src/androidMain/kotlin/vn/momo/kits/const/HostFont.android.kt +0 -19
- package/compose/src/androidMain/kotlin/vn/momo/kits/navigation/ScrollToTop.android.kt +0 -6
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/BackGesture.android.kt +0 -12
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/OsFontScale.android.kt +0 -7
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/Platform.android.kt +0 -153
- package/compose/src/androidMain/kotlin/vn/momo/kits/platform/ReservedRegions.android.kt +0 -6
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/AnimationSearchInput.kt +0 -52
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Context.kt +0 -124
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/FloatingButton.kt +0 -183
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Header.kt +0 -207
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderAnimated.kt +0 -39
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderBackground.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderDefault.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderExtended.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderRight.kt +0 -293
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/HeaderTitle.kt +0 -33
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/LiteScreen.kt +0 -831
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Localize.kt +0 -269
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +0 -110
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +0 -378
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/WidgetContainer.kt +0 -56
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/useHeaderSearchAnimation.kt +0 -69
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Avatar.kt +0 -157
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +0 -82
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +0 -32
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeRibbon.kt +0 -338
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BaselineView.kt +0 -175
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +0 -356
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Carousel.kt +0 -113
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +0 -89
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Chip.kt +0 -128
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Collapse.kt +0 -209
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CupertinoOverscroll.kt +0 -542
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +0 -49
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +0 -76
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +0 -125
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +0 -231
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Information.kt +0 -189
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +0 -475
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputDropDown.kt +0 -114
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +0 -266
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputOTP.kt +0 -240
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputPhoneNumber.kt +0 -223
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +0 -264
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +0 -185
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/LazyColumnWithBouncing.kt +0 -343
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Loader.kt +0 -108
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationDot.kt +0 -56
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationNumber.kt +0 -41
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationScroll.kt +0 -84
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PaginationWhiteDot.kt +0 -40
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +0 -361
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupPromotion.kt +0 -108
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ProgressInfo.kt +0 -310
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +0 -59
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Rating.kt +0 -87
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/ScaleSizeScope.kt +0 -21
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +0 -90
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Slider.kt +0 -323
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Stepper.kt +0 -220
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Steps.kt +0 -473
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/SuggestAction.kt +0 -122
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Swipe.kt +0 -199
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +0 -91
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TabView.kt +0 -552
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +0 -88
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +0 -125
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Title.kt +0 -207
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tooltip.kt +0 -498
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/TrustBanner.kt +0 -176
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Uploader.kt +0 -182
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePicker.kt +0 -193
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerTypes.kt +0 -29
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/DateTimePickerUtils.kt +0 -234
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/datetimepicker/WheelPicker.kt +0 -188
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +0 -325
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/HostFont.kt +0 -16
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitDesignSystem.kt +0 -18
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/KitFontScale.kt +0 -22
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +0 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +0 -16
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +0 -188
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +0 -297
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +0 -54
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +0 -50
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/ScreenLayout.kt +0 -232
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +0 -41
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/AutomationId.kt +0 -52
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Clickable.kt +0 -66
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Conditional.kt +0 -11
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/DeprecatedModifier.kt +0 -104
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +0 -48
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Size.kt +0 -51
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/BottomSheet.kt +0 -338
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/HostBackGestureBridge.kt +0 -58
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ModalScreen.kt +0 -137
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigation.kt +0 -106
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/NavigationContainer.kt +0 -205
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/Navigator.kt +0 -393
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/ScrollToTop.kt +0 -8
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackScreen.kt +0 -708
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/StackTransition.kt +0 -148
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/SwipeBackHaptic.kt +0 -35
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTab.kt +0 -203
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/BottomTabBar.kt +0 -232
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/CurvedContainer.kt +0 -86
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoBarCompression.kt +0 -98
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/bottomtab/DuoTabBar.kt +0 -312
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/FloatingButton.kt +0 -169
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/Header.kt +0 -408
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderBackground.kt +0 -92
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderJourney.kt +0 -105
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderLocation.kt +0 -74
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderRight.kt +0 -366
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderTitle.kt +0 -37
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/HeaderUser.kt +0 -363
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SideBar.kt +0 -185
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/component/SnackBar.kt +0 -132
- package/compose/src/commonMain/kotlin/vn/momo/kits/navigation/tracking/ScreenTracker.kt +0 -127
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/BackGesture.kt +0 -12
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ComposeLottieAnimation.kt +0 -91
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/OsFontScale.kt +0 -9
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/Platform.kt +0 -74
- package/compose/src/commonMain/kotlin/vn/momo/kits/platform/ReservedRegions.kt +0 -13
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +0 -1329
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Resources.kt +0 -55
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Tracking.kt +0 -15
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +0 -118
- package/compose/src/iosMain/kotlin/vn/momo/kits/const/HostFont.ios.kt +0 -40
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/HostBackGesture.ios.kt +0 -45
- package/compose/src/iosMain/kotlin/vn/momo/kits/navigation/ScrollToTop.ios.kt +0 -32
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/BackGesture.ios.kt +0 -38
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/OsFontScale.ios.kt +0 -66
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/Platform.ios.kt +0 -217
- package/compose/src/iosMain/kotlin/vn/momo/kits/platform/ReservedRegions.ios.kt +0 -86
- package/gradle/libs.versions.toml +0 -69
- package/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/gradle/wrapper/gradle-wrapper.properties +0 -8
- package/gradle.properties +0 -26
- package/gradlew +0 -252
- package/gradlew.bat +0 -94
- package/ios/Application/HeaderRight.swift +0 -324
- package/ios/Application/Navigation/HeaderBackProps.swift +0 -66
- package/ios/Application/Navigation/HeaderTitle.swift +0 -57
- package/ios/Application/Navigation/NavigationOptions.swift +0 -109
- package/ios/Application/Navigation/NavigatorManager.swift +0 -29
- package/ios/Application/Navigation/component/DuoScrollGradient.swift +0 -54
- package/ios/Application/Navigation/component/Header.swift +0 -183
- package/ios/Application/Navigation/component/HeaderBackground.swift +0 -84
- package/ios/Application/Navigation/component/HeaderColor.swift +0 -65
- package/ios/Application/Navigation/component/HeaderRightWidthKey.swift +0 -11
- package/ios/Application/Navigation/component/NavigationFooter.swift +0 -90
- package/ios/Application/Navigation/component/NavigationHeaderRight.swift +0 -280
- package/ios-demo/README.md +0 -120
- package/settings.gradle.kts +0 -64
- /package/ios/{Application/Layout → Layout}/ScreenLayout.swift +0 -0
- /package/ios/{Application/Navigation → Navigation}/BottomTab/CurvedContainer.swift +0 -0
- /package/ios/{Application/Navigation → Navigation}/BottomTab/DuoBarCompression.swift +0 -0
- /package/ios/{Application/Navigation → Navigation}/BottomTab/DuoTabBar.swift +0 -0
- /package/ios/{Application/Navigation/Overplay → Navigation}/ModalScreen.swift +0 -0
|
@@ -65,21 +65,18 @@ public struct OTPKeyboard: View {
|
|
|
65
65
|
HStack {
|
|
66
66
|
KeyboardButton("", action: self.onPressKey).disabled(true).opacity(0)
|
|
67
67
|
KeyboardButton("0", action: self.onPressKey)
|
|
68
|
+
// Frame inside the label so the whole key is tappable, not just the glyph.
|
|
68
69
|
SwiftUI.Button(action: onPressBack) {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
}.frame(maxWidth: .infinity, minHeight: 48)
|
|
75
|
-
.clipShape(RoundedRectangle(cornerRadius: 8))
|
|
70
|
+
Image(systemName: "delete.backward")
|
|
71
|
+
.foregroundColor(Colors.text)
|
|
72
|
+
.frame(maxWidth: .infinity, minHeight: 48)
|
|
73
|
+
.contentShape(Rectangle())
|
|
74
|
+
}
|
|
76
75
|
}
|
|
77
76
|
}
|
|
78
77
|
.background(Colors.background)
|
|
79
78
|
.valueChanged(value: value) { otp in
|
|
80
|
-
|
|
81
|
-
self.onChange!(otp)
|
|
82
|
-
}
|
|
79
|
+
onChange?(otp)
|
|
83
80
|
}
|
|
84
81
|
}
|
|
85
82
|
|
|
@@ -128,7 +125,7 @@ private struct ValueView: View {
|
|
|
128
125
|
|
|
129
126
|
public var body: some View {
|
|
130
127
|
return HStack {
|
|
131
|
-
ForEach(0 ..< valueLength, id: \.self) { i in
|
|
128
|
+
ForEach(0 ..< max(valueLength, 0), id: \.self) { i in
|
|
132
129
|
if i < value.count {
|
|
133
130
|
Circle().foregroundColor(Colors.text).frame(width: 8, height: 8)
|
|
134
131
|
} else {
|
|
@@ -14,10 +14,10 @@ import SwiftUI
|
|
|
14
14
|
private let INDICATOR_WIDTH: CGFloat = 24
|
|
15
15
|
private let PROGRESS_WIDTH: CGFloat = 72
|
|
16
16
|
|
|
17
|
-
///
|
|
17
|
+
/// Mirrors Compose's `calculateOffset`; clamped because UIKit bounce overshoots the scroll range.
|
|
18
18
|
private func calculateOffset(currentPosition: CGFloat, maxBound: CGFloat) -> CGFloat {
|
|
19
19
|
guard maxBound > 0 else { return 0 }
|
|
20
|
-
return (PROGRESS_WIDTH - INDICATOR_WIDTH) * (currentPosition / maxBound)
|
|
20
|
+
return (PROGRESS_WIDTH - INDICATOR_WIDTH) * min(max(currentPosition / maxBound, 0), 1)
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
// MARK: - PaginationScroll
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import SDWebImageSwiftUI
|
|
2
1
|
import SwiftUI
|
|
3
2
|
|
|
4
3
|
// MARK: - PopupButtonDirection
|
|
@@ -16,45 +15,12 @@ public enum PopupButtonType {
|
|
|
16
15
|
case button
|
|
17
16
|
}
|
|
18
17
|
|
|
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
|
-
.ignoreBoldTextSetting()
|
|
28
|
-
.lineLimit(1)
|
|
29
|
-
.fixedSize()
|
|
30
|
-
.background(
|
|
31
|
-
GeometryReader { g in
|
|
32
|
-
Color.clear.onAppear { oneLine.wrappedValue = g.size.height }
|
|
33
|
-
}
|
|
34
|
-
)
|
|
35
|
-
.hidden()
|
|
36
|
-
|
|
37
|
-
Text("A\nA")
|
|
38
|
-
.font(font)
|
|
39
|
-
.ignoreBoldTextSetting()
|
|
40
|
-
.lineLimit(2)
|
|
41
|
-
.fixedSize(horizontal: false, vertical: true)
|
|
42
|
-
.background(
|
|
43
|
-
GeometryReader { g in
|
|
44
|
-
Color.clear.onAppear { twoLines.wrappedValue = g.size.height }
|
|
45
|
-
}
|
|
46
|
-
)
|
|
47
|
-
.hidden()
|
|
48
|
-
}
|
|
49
|
-
.frame(width: 0, height: 0)
|
|
50
|
-
)
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
18
|
// MARK: - PopupDisplay
|
|
55
19
|
|
|
56
20
|
public struct PopupDisplay: View {
|
|
21
|
+
@Environment(\.appTheme) private var theme
|
|
57
22
|
@Environment(\.localize) private var localize
|
|
23
|
+
@Environment(\.momoFontScale) private var fontScale
|
|
58
24
|
@Environment(\.screenLayout) private var layout
|
|
59
25
|
|
|
60
26
|
// MARK: Lifecycle
|
|
@@ -76,146 +42,100 @@ public struct PopupDisplay: View {
|
|
|
76
42
|
}
|
|
77
43
|
|
|
78
44
|
// MARK: Public
|
|
79
|
-
|
|
45
|
+
|
|
80
46
|
@State private var oneLineH: CGFloat = 0
|
|
81
47
|
@State private var twoLineH: CGFloat = 0
|
|
48
|
+
@State private var textHeight: CGFloat = .zero
|
|
49
|
+
@State private var actionsHeight: CGFloat = 0
|
|
82
50
|
|
|
83
|
-
|
|
84
|
-
private var
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
guard oneLineH > 0 && twoLineH > 0 else { return ceil(fallbackLH * lines) }
|
|
88
|
-
return ceil(oneLineH + max(0, lines - 1) * (twoLineH - oneLineH))
|
|
51
|
+
// ~8.5 lines as laid out; nominal line height until measured
|
|
52
|
+
private var maxHeight8_5: CGFloat {
|
|
53
|
+
popupLinesHeight(8.5, oneLine: oneLineH, twoLines: twoLineH)
|
|
54
|
+
?? fontScale(TypographyStyle.bodyDefaultRegular.lineHeight) * 8.5
|
|
89
55
|
}
|
|
90
|
-
private var maxHeight8_5: CGFloat { heightForLines(lines: 8.5) }
|
|
91
56
|
|
|
57
|
+
private var shouldUseColumn: Bool {
|
|
58
|
+
// UTF-16 length, as PopupNotify counts it
|
|
59
|
+
buttonDirection == .column || (buttonDirection == .auto && (closeButtonTitle.utf16.count > 12 || actionButtonTitle.utf16.count > 12))
|
|
60
|
+
}
|
|
92
61
|
|
|
93
|
-
@State private var textHeight: CGFloat = .zero
|
|
94
|
-
@State private var isScrollable = false
|
|
95
|
-
@State private var actionsHeight: CGFloat = 0
|
|
96
|
-
|
|
97
62
|
public var body: some View {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
63
|
+
ZStack(alignment: .topTrailing) {
|
|
64
|
+
VStack(spacing: 0) {
|
|
65
|
+
// scrolls when iPhone Duo landscape is too short; actions stay visible
|
|
66
|
+
PopupScrollBody(maxHeight: layout.popupMaxHeight.map { $0 - actionsHeight }) {
|
|
67
|
+
VStack(spacing: 0) {
|
|
68
|
+
if !url.isEmpty {
|
|
69
|
+
PopupHeaderImage(url: url)
|
|
70
|
+
}
|
|
71
|
+
VStack(alignment: .leading, spacing: 0) {
|
|
72
|
+
MomoText(title, typography: .headerDefaultBold, maxLines: 2, accessibilityId: "title_popup_permission")
|
|
73
|
+
.padding(.top, 24)
|
|
74
|
+
.padding(.bottom, 8)
|
|
101
75
|
|
|
102
|
-
|
|
103
|
-
ZStack(alignment: .topTrailing) {
|
|
104
|
-
if(isShowCloseIcon) {
|
|
105
|
-
SwiftUI.Button(action: onClose) {
|
|
106
|
-
Image(systemName: "xmark.circle.fill")
|
|
107
|
-
.resizable()
|
|
108
|
-
.frame(width: 22, height: 22)
|
|
109
|
-
.overlay(RoundedRectangle(cornerRadius: Radius.L).stroke(Colors.black01, lineWidth: 2))
|
|
110
|
-
}.foregroundColor(Colors.black20)
|
|
111
|
-
.background(Colors.black01.cornerRadius(15))
|
|
112
|
-
.padding(.trailing, -11)
|
|
113
|
-
.padding(.top, -11)
|
|
114
|
-
.zIndex(1)
|
|
115
|
-
.accessibility(identifier: "ic_popup_close")
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
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
|
-
}
|
|
131
|
-
.aspectRatio(1.777, contentMode: .fit)
|
|
132
|
-
.frame(maxWidth: .infinity, alignment: .center)
|
|
133
|
-
.clipShape(RoundedCorner(radius: 15, corners: [.topLeft, .topRight]))
|
|
134
|
-
.clipped()
|
|
135
|
-
}
|
|
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
|
-
}
|
|
76
|
+
descriptionContent
|
|
174
77
|
.padding(.bottom, 8)
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
.padding(.bottom, 8)
|
|
180
|
-
}
|
|
78
|
+
|
|
79
|
+
if !errorCode.isEmpty {
|
|
80
|
+
MomoText(localize.translate("errorCode") + errorCode, typography: .descriptionXsRegular, color: theme.colors.text.hint, maxLines: 1)
|
|
81
|
+
.padding(.bottom, 8)
|
|
181
82
|
}
|
|
182
|
-
.frame(maxWidth: .infinity, alignment: .leading)
|
|
183
|
-
.padding(.horizontal, 24)
|
|
184
|
-
.padding(.bottom, 16)
|
|
185
83
|
}
|
|
84
|
+
.frame(maxWidth: .infinity, alignment: .leading)
|
|
85
|
+
.padding(.horizontal, 24)
|
|
86
|
+
.padding(.bottom, 16)
|
|
87
|
+
.measureLineHeights(typography: .bodyDefaultRegular, oneLine: $oneLineH, twoLines: $twoLineH)
|
|
186
88
|
}
|
|
89
|
+
}
|
|
187
90
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
} else {
|
|
193
|
-
ColumnButtons
|
|
194
|
-
}
|
|
91
|
+
Group {
|
|
92
|
+
if shouldUseColumn {
|
|
93
|
+
if buttonType == .text {
|
|
94
|
+
ColumnTextButtons
|
|
195
95
|
} else {
|
|
196
|
-
|
|
197
|
-
RowTextButtons
|
|
198
|
-
} else {
|
|
199
|
-
RowButtons
|
|
200
|
-
}
|
|
96
|
+
ColumnButtons
|
|
201
97
|
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
.onChange(of: proxy.size.height) { actionsHeight = $0 }
|
|
98
|
+
} else {
|
|
99
|
+
if buttonType == .text {
|
|
100
|
+
RowTextButtons
|
|
101
|
+
} else {
|
|
102
|
+
RowButtons
|
|
208
103
|
}
|
|
209
|
-
|
|
104
|
+
}
|
|
210
105
|
}
|
|
211
|
-
.
|
|
106
|
+
.popupReadHeight($actionsHeight)
|
|
212
107
|
}
|
|
108
|
+
.fixedSize(horizontal: false, vertical: true)
|
|
109
|
+
.background(theme.colors.background.surface)
|
|
110
|
+
.clipShape(RoundedRectangle(cornerRadius: Radius.L))
|
|
111
|
+
|
|
112
|
+
if isShowCloseIcon {
|
|
113
|
+
PopupCloseButton(action: onClose)
|
|
114
|
+
.offset(x: 11, y: -11)
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
.frame(maxWidth: layout.popupMaxWidth)
|
|
118
|
+
.padding(.horizontal, 12)
|
|
119
|
+
.accessibilityElement(children: .contain)
|
|
120
|
+
.accessibilityIdentifier("popup_notify")
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@ViewBuilder
|
|
124
|
+
private var descriptionContent: some View {
|
|
125
|
+
if textHeight > maxHeight8_5 {
|
|
126
|
+
ScrollView(showsIndicators: false) {
|
|
127
|
+
descriptionText
|
|
128
|
+
}
|
|
129
|
+
.frame(height: maxHeight8_5)
|
|
130
|
+
} else {
|
|
131
|
+
descriptionText
|
|
213
132
|
}
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
.
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
private var descriptionText: some View {
|
|
136
|
+
MomoText(description, typography: .bodyDefaultRegular, accessibilityId: "description_popup_permission")
|
|
137
|
+
.frame(maxWidth: .infinity, alignment: .leading)
|
|
138
|
+
.popupReadHeight($textHeight)
|
|
219
139
|
}
|
|
220
140
|
|
|
221
141
|
// MARK: Internal
|
|
@@ -265,7 +185,7 @@ public struct PopupDisplay: View {
|
|
|
265
185
|
}
|
|
266
186
|
|
|
267
187
|
var RowButtons: some View {
|
|
268
|
-
HStack {
|
|
188
|
+
HStack(spacing: Spacing.S) {
|
|
269
189
|
if(!closeButtonTitle.isEmpty) {
|
|
270
190
|
Button(title: closeButtonTitle, action: onPressCloseButton, type: .text, size: .medium).accessibility(identifier: "btn_popup_cancel")
|
|
271
191
|
}
|
|
@@ -278,7 +198,7 @@ public struct PopupDisplay: View {
|
|
|
278
198
|
}
|
|
279
199
|
|
|
280
200
|
var ColumnButtons: some View {
|
|
281
|
-
VStack(alignment: .trailing) {
|
|
201
|
+
VStack(alignment: .trailing, spacing: Spacing.S) {
|
|
282
202
|
Button(
|
|
283
203
|
title: actionButtonTitle,
|
|
284
204
|
action: onPressAction,
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
import SDWebImageSwiftUI
|
|
2
1
|
import SwiftUI
|
|
3
2
|
|
|
4
3
|
public struct PopupInput: View {
|
|
4
|
+
@Environment(\.appTheme) private var theme
|
|
5
|
+
@Environment(\.screenLayout) private var layout
|
|
6
|
+
|
|
5
7
|
// MARK: Lifecycle
|
|
6
8
|
|
|
7
9
|
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) {
|
|
@@ -24,22 +26,13 @@ public struct PopupInput: View {
|
|
|
24
26
|
public var body: some View {
|
|
25
27
|
VStack(spacing: 12) {
|
|
26
28
|
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
29
|
VStack {
|
|
37
30
|
VStack(alignment: .leading) {
|
|
38
|
-
MomoText(title, typography: .headerDefaultBold
|
|
31
|
+
MomoText(title, typography: .headerDefaultBold)
|
|
39
32
|
.padding(.top, 12)
|
|
40
33
|
.padding(.bottom, 24)
|
|
41
34
|
|
|
42
|
-
MomoText(description, typography: .bodyDefaultRegular
|
|
35
|
+
MomoText(description, typography: .bodyDefaultRegular)
|
|
43
36
|
.opacity(0.6)
|
|
44
37
|
.multilineTextAlignment(.leading)
|
|
45
38
|
.padding(.bottom, 20)
|
|
@@ -61,11 +54,15 @@ public struct PopupInput: View {
|
|
|
61
54
|
}
|
|
62
55
|
|
|
63
56
|
}.clipped()
|
|
57
|
+
|
|
58
|
+
PopupCloseButton(action: onPressClose)
|
|
59
|
+
.offset(x: 11, y: -11)
|
|
64
60
|
}
|
|
65
61
|
}
|
|
66
|
-
.background(
|
|
62
|
+
.background(theme.colors.background.surface.cornerRadius(8))
|
|
67
63
|
.shadow(color: .black.opacity(0.08), radius: 2, x: 0, y: 0)
|
|
68
64
|
.shadow(color: .black.opacity(0.16), radius: 24, x: 0, y: 0)
|
|
65
|
+
.frame(maxWidth: layout.popupMaxWidth)
|
|
69
66
|
.padding(.horizontal, 40)
|
|
70
67
|
}
|
|
71
68
|
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import SDWebImageSwiftUI
|
|
1
2
|
import SwiftUI
|
|
2
3
|
|
|
3
4
|
// Width of a system alert on the iPhone Duo inner display, in both orientations (RN Popup/utils.ts).
|
|
@@ -6,9 +7,9 @@ private let duoPopupMaxWidth: CGFloat = 440
|
|
|
6
7
|
extension ScreenLayout {
|
|
7
8
|
var isDuoDevice: Bool { isIPhoneDuoDevice(windowSize: CGSize(width: width, height: height)) }
|
|
8
9
|
|
|
9
|
-
/// Card width cap
|
|
10
|
+
/// Card width cap (Compose `popupMaxWidth`); unbounded off iPhone Duo, where the popup's own padding sets the width.
|
|
10
11
|
var popupMaxWidth: CGFloat {
|
|
11
|
-
isDuoDevice ?
|
|
12
|
+
isDuoDevice ? duoPopupMaxWidth : .infinity
|
|
12
13
|
}
|
|
13
14
|
|
|
14
15
|
/// Room left for a popup on iPhone Duo, where landscape is too short for it; nil elsewhere.
|
|
@@ -43,3 +44,97 @@ struct PopupScrollBody<Content: View>: View {
|
|
|
43
44
|
}
|
|
44
45
|
}
|
|
45
46
|
}
|
|
47
|
+
|
|
48
|
+
/// Height of `lines` (may be fractional) lines measured by `measureLineHeights`; nil until measured.
|
|
49
|
+
func popupLinesHeight(_ lines: CGFloat, oneLine: CGFloat, twoLines: CGFloat) -> CGFloat? {
|
|
50
|
+
guard oneLine > 0, twoLines > oneLine else { return nil }
|
|
51
|
+
return oneLine + (lines - 1) * (twoLines - oneLine)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
extension View {
|
|
55
|
+
/// Measures one and two lines of `typography` as MomoText lays them out, its line spacing included.
|
|
56
|
+
func measureLineHeights(typography: TypographyStyle,
|
|
57
|
+
oneLine: Binding<CGFloat>,
|
|
58
|
+
twoLines: Binding<CGFloat>) -> some View {
|
|
59
|
+
overlay(
|
|
60
|
+
VStack(spacing: 0) {
|
|
61
|
+
MomoText("A", typography: typography)
|
|
62
|
+
.fixedSize()
|
|
63
|
+
.popupReadHeight(oneLine)
|
|
64
|
+
MomoText("A\nA", typography: typography)
|
|
65
|
+
.fixedSize()
|
|
66
|
+
.popupReadHeight(twoLines)
|
|
67
|
+
}
|
|
68
|
+
.frame(width: 0, height: 0)
|
|
69
|
+
.hidden()
|
|
70
|
+
.accessibilityHidden(true)
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
func popupReadHeight(_ height: Binding<CGFloat>) -> some View {
|
|
75
|
+
background(
|
|
76
|
+
GeometryReader { proxy in
|
|
77
|
+
Color.clear
|
|
78
|
+
.onAppear { height.wrappedValue = proxy.size.height }
|
|
79
|
+
.onChange(of: proxy.size.height) { height.wrappedValue = $0 }
|
|
80
|
+
}
|
|
81
|
+
)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/// 22pt round close button shared by the popups (Compose `PopupNotify` / `PopupPromotion`).
|
|
86
|
+
struct PopupCloseButton: View {
|
|
87
|
+
@Environment(\.appTheme) private var theme
|
|
88
|
+
var tapSize: CGFloat = 22
|
|
89
|
+
let action: () -> Void
|
|
90
|
+
|
|
91
|
+
var body: some View {
|
|
92
|
+
SwiftUI.Button(action: action) {
|
|
93
|
+
Circle()
|
|
94
|
+
.fill(theme.colors.text.default)
|
|
95
|
+
.overlay(Circle().strokeBorder(theme.colors.background.surface, lineWidth: 2))
|
|
96
|
+
.overlay(Icon(source: "navigation_close", size: 16, color: theme.colors.background.surface))
|
|
97
|
+
.frame(width: 22, height: 22)
|
|
98
|
+
.frame(width: tapSize, height: tapSize)
|
|
99
|
+
.contentShape(Rectangle())
|
|
100
|
+
}
|
|
101
|
+
.accessibilityIdentifier("ic_popup_close")
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/// Compose `Image` states: skeleton while loading, `media_fail` once loading fails.
|
|
106
|
+
struct PopupImagePlaceholder: View {
|
|
107
|
+
@Environment(\.appTheme) private var theme
|
|
108
|
+
let failed: Bool
|
|
109
|
+
|
|
110
|
+
var body: some View {
|
|
111
|
+
if failed {
|
|
112
|
+
Icon(source: "media_fail", color: theme.colors.text.disable)
|
|
113
|
+
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
|
114
|
+
} else {
|
|
115
|
+
Skeleton()
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/// 16:9 header image, cropped like Compose `Image` (ContentScale.Crop).
|
|
121
|
+
struct PopupHeaderImage: View {
|
|
122
|
+
let url: String
|
|
123
|
+
|
|
124
|
+
@State private var failed = false
|
|
125
|
+
|
|
126
|
+
var body: some View {
|
|
127
|
+
Color.clear
|
|
128
|
+
.aspectRatio(1.777, contentMode: .fit)
|
|
129
|
+
.frame(maxWidth: .infinity)
|
|
130
|
+
.overlay(
|
|
131
|
+
WebImage(url: URL(string: url), isAnimating: .constant(true))
|
|
132
|
+
.onSuccess { _, _, _ in failed = false }
|
|
133
|
+
.onFailure { _ in failed = true }
|
|
134
|
+
.resizable()
|
|
135
|
+
.placeholder { PopupImagePlaceholder(failed: failed || URL(string: url) == nil) }
|
|
136
|
+
.scaledToFill()
|
|
137
|
+
)
|
|
138
|
+
.clipped()
|
|
139
|
+
}
|
|
140
|
+
}
|
|
@@ -1,8 +1,17 @@
|
|
|
1
|
-
import SDWebImageSwiftUI
|
|
2
1
|
import SwiftUI
|
|
3
2
|
|
|
4
3
|
public typealias PopupActionDirection = PopupButtonDirection
|
|
5
4
|
|
|
5
|
+
public struct PopupAction {
|
|
6
|
+
public let title: String
|
|
7
|
+
public let onPress: (() -> Void)?
|
|
8
|
+
|
|
9
|
+
public init(title: String, onPress: (() -> Void)? = nil) {
|
|
10
|
+
self.title = title
|
|
11
|
+
self.onPress = onPress
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
6
15
|
public struct PopupNotifyProps {
|
|
7
16
|
public var image: String
|
|
8
17
|
public var title: String
|
|
@@ -38,6 +47,7 @@ public struct PopupNotifyProps {
|
|
|
38
47
|
}
|
|
39
48
|
|
|
40
49
|
public struct PopupNotify: View {
|
|
50
|
+
@Environment(\.appTheme) private var theme
|
|
41
51
|
@Environment(\.localize) private var localize
|
|
42
52
|
@Environment(\.momoFontScale) private var fontScale
|
|
43
53
|
@Environment(\.screenLayout) private var layout
|
|
@@ -46,13 +56,17 @@ public struct PopupNotify: View {
|
|
|
46
56
|
|
|
47
57
|
@State private var descriptionHeight: CGFloat = 0
|
|
48
58
|
@State private var actionsHeight: CGFloat = 0
|
|
59
|
+
@State private var oneLineHeight: CGFloat = 0
|
|
60
|
+
@State private var twoLinesHeight: CGFloat = 0
|
|
49
61
|
|
|
50
62
|
private var errorCodePrefix: String {
|
|
51
63
|
localize.translate("errorCode")
|
|
52
64
|
}
|
|
53
65
|
|
|
66
|
+
// ~8.5 lines as laid out (Compose measures the real lines); nominal line height until measured
|
|
54
67
|
private var maxDescriptionHeight: CGFloat {
|
|
55
|
-
|
|
68
|
+
popupLinesHeight(8.5, oneLine: oneLineHeight, twoLines: twoLinesHeight)
|
|
69
|
+
?? fontScale(TypographyStyle.bodyDefaultRegular.lineHeight) * 8.5
|
|
56
70
|
}
|
|
57
71
|
|
|
58
72
|
private var shouldUseColumnButtons: Bool {
|
|
@@ -62,7 +76,9 @@ public struct PopupNotify: View {
|
|
|
62
76
|
case .row:
|
|
63
77
|
return false
|
|
64
78
|
case .auto:
|
|
65
|
-
|
|
79
|
+
// UTF-16 length, as Kotlin and JS count it
|
|
80
|
+
guard let secondary = props.secondary else { return false }
|
|
81
|
+
return secondary.title.utf16.count > 12 || (props.primary?.title.utf16.count ?? 0) > 12
|
|
66
82
|
}
|
|
67
83
|
}
|
|
68
84
|
|
|
@@ -77,7 +93,7 @@ public struct PopupNotify: View {
|
|
|
77
93
|
PopupScrollBody(maxHeight: layout.popupMaxHeight.map { $0 - actionsHeight }) {
|
|
78
94
|
VStack(spacing: 0) {
|
|
79
95
|
if !props.image.isEmpty {
|
|
80
|
-
|
|
96
|
+
PopupHeaderImage(url: props.image)
|
|
81
97
|
}
|
|
82
98
|
textContent
|
|
83
99
|
}
|
|
@@ -86,25 +102,19 @@ public struct PopupNotify: View {
|
|
|
86
102
|
actionButtons
|
|
87
103
|
.padding(.horizontal, Spacing.XL)
|
|
88
104
|
.padding(.bottom, Spacing.XL)
|
|
89
|
-
.
|
|
90
|
-
GeometryReader { proxy in
|
|
91
|
-
Color.clear
|
|
92
|
-
.onAppear { actionsHeight = proxy.size.height }
|
|
93
|
-
.onChange(of: proxy.size.height) { actionsHeight = $0 }
|
|
94
|
-
}
|
|
95
|
-
)
|
|
105
|
+
.popupReadHeight($actionsHeight)
|
|
96
106
|
}
|
|
97
|
-
.background(
|
|
107
|
+
.background(theme.colors.background.surface)
|
|
98
108
|
.clipShape(RoundedRectangle(cornerRadius: Radius.L))
|
|
99
109
|
|
|
100
110
|
if props.isShowCloseIcon {
|
|
101
|
-
|
|
111
|
+
PopupCloseButton(action: props.onIconClose)
|
|
102
112
|
.offset(x: 11, y: -11)
|
|
103
113
|
}
|
|
104
114
|
}
|
|
105
115
|
.frame(maxWidth: layout.popupMaxWidth)
|
|
106
116
|
.padding(.horizontal, Spacing.M)
|
|
107
|
-
.accessibilityElement(children: .
|
|
117
|
+
.accessibilityElement(children: .contain)
|
|
108
118
|
.accessibilityIdentifier("popup_notify")
|
|
109
119
|
}
|
|
110
120
|
|
|
@@ -124,7 +134,7 @@ public struct PopupNotify: View {
|
|
|
124
134
|
MomoText(
|
|
125
135
|
errorCodePrefix + props.error,
|
|
126
136
|
typography: .descriptionXsRegular,
|
|
127
|
-
color:
|
|
137
|
+
color: theme.colors.text.hint,
|
|
128
138
|
maxLines: 1
|
|
129
139
|
)
|
|
130
140
|
.padding(.top, Spacing.S)
|
|
@@ -132,20 +142,7 @@ public struct PopupNotify: View {
|
|
|
132
142
|
}
|
|
133
143
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
134
144
|
.padding(Spacing.XL)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
private var popupImage: some View {
|
|
138
|
-
WebImage(url: URL(string: props.image), isAnimating: .constant(true))
|
|
139
|
-
.resizable()
|
|
140
|
-
.placeholder {
|
|
141
|
-
Rectangle()
|
|
142
|
-
.fill(Colors.black03)
|
|
143
|
-
.aspectRatio(1.777, contentMode: .fit)
|
|
144
|
-
.frame(maxWidth: .infinity)
|
|
145
|
-
}
|
|
146
|
-
.aspectRatio(1.777, contentMode: .fit)
|
|
147
|
-
.frame(maxWidth: .infinity)
|
|
148
|
-
.clipShape(RoundedCorner(radius: Radius.L, corners: [.topLeft, .topRight]))
|
|
145
|
+
.measureLineHeights(typography: .bodyDefaultRegular, oneLine: $oneLineHeight, twoLines: $twoLinesHeight)
|
|
149
146
|
}
|
|
150
147
|
|
|
151
148
|
@ViewBuilder
|
|
@@ -167,15 +164,7 @@ public struct PopupNotify: View {
|
|
|
167
164
|
accessibilityId: "description_popup_permission"
|
|
168
165
|
)
|
|
169
166
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
170
|
-
.
|
|
171
|
-
GeometryReader { proxy in
|
|
172
|
-
Color.clear
|
|
173
|
-
.onAppear { descriptionHeight = proxy.size.height }
|
|
174
|
-
.onChange(of: props.description) { _ in
|
|
175
|
-
descriptionHeight = proxy.size.height
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
)
|
|
167
|
+
.popupReadHeight($descriptionHeight)
|
|
179
168
|
}
|
|
180
169
|
|
|
181
170
|
@ViewBuilder
|
|
@@ -217,21 +206,4 @@ public struct PopupNotify: View {
|
|
|
217
206
|
)
|
|
218
207
|
.accessibilityIdentifier("btn_popup_cancel")
|
|
219
208
|
}
|
|
220
|
-
|
|
221
|
-
private var closeButton: some View {
|
|
222
|
-
SwiftUI.Button(action: props.onIconClose) {
|
|
223
|
-
ZStack {
|
|
224
|
-
Circle()
|
|
225
|
-
.fill(Colors.black17)
|
|
226
|
-
.overlay(
|
|
227
|
-
Circle()
|
|
228
|
-
.stroke(Colors.black01, lineWidth: 2)
|
|
229
|
-
)
|
|
230
|
-
.frame(width: 22, height: 22)
|
|
231
|
-
|
|
232
|
-
Icon(source: "navigation_close", size: 16, color: Colors.black01)
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
.accessibilityIdentifier("ic_popup_close")
|
|
236
|
-
}
|
|
237
209
|
}
|