@momo-kits/native-kits 0.0.1-beta.4 → 0.89.1-2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/android/.gradle/8.0/checksums/checksums.lock +0 -0
- package/android/.gradle/8.0/dependencies-accessors/dependencies-accessors.lock +0 -0
- package/android/.gradle/8.0/dependencies-accessors/gc.properties +0 -0
- package/android/.gradle/8.0/fileChanges/last-build.bin +0 -0
- package/android/.gradle/8.0/fileHashes/fileHashes.lock +0 -0
- package/android/.gradle/8.0/gc.properties +0 -0
- package/android/.gradle/config.properties +2 -0
- package/android/.gradle/vcs-1/gc.properties +0 -0
- package/android/.idea/gradle.xml +12 -0
- package/android/.idea/migrations.xml +10 -0
- package/android/.idea/misc.xml +10 -0
- package/android/.idea/vcs.xml +6 -0
- package/android/.idea/workspace.xml +50 -0
- package/android/build.gradle +35 -69
- package/android/local.properties +8 -0
- package/android/proguard-rules.pro +21 -0
- package/android/src/main/AndroidManifest.xml +2 -2
- package/android/src/main/java/com/momoplatform/nativekits/foundations/Button.kt +16 -0
- package/android/src/main/java/com/momoplatform/nativekits/libs/Logo.kt +63 -0
- package/android/src/main/java/com/momoplatform/nativekits/libs/TrustBanner.kt +246 -0
- package/android/src/main/res/drawable/ic_launcher_background.xml +170 -0
- package/android/src/main/res/drawable-v24/ic_launcher_foreground.xml +30 -0
- package/android/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +6 -0
- package/android/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +6 -0
- package/android/src/main/res/mipmap-hdpi/ic_launcher.webp +0 -0
- package/android/src/main/res/mipmap-hdpi/ic_launcher_round.webp +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_launcher.webp +0 -0
- package/android/src/main/res/mipmap-mdpi/ic_launcher_round.webp +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_launcher.webp +0 -0
- package/android/src/main/res/mipmap-xhdpi/ic_launcher_round.webp +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_launcher.webp +0 -0
- package/android/src/main/res/mipmap-xxhdpi/ic_launcher_round.webp +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_launcher.webp +0 -0
- package/android/src/main/res/mipmap-xxxhdpi/ic_launcher_round.webp +0 -0
- package/android/src/main/res/values/colors.xml +10 -0
- package/android/src/main/res/values/strings.xml +3 -0
- package/android/src/main/res/values/themes.xml +3 -0
- package/android/src/main/res/values-night/themes.xml +3 -0
- package/android/src/main/res/xml/backup_rules.xml +13 -0
- package/android/src/main/res/xml/data_extraction_rules.xml +19 -0
- package/build.gradle.kts +18 -0
- package/compose/build.gradle.kts +82 -0
- package/compose/src/androidMain/AndroidManifest.xml +2 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/utils/Platform.kt +3 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/utils/SetMaskFilter.kt +8 -0
- package/compose/src/androidMain/kotlin/vn/momo/kits/utils/Utils.android.kt +14 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Components.kt +194 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/NavigationContainer.kt +197 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/application/Screen.kt +133 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Badge.kt +62 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/BadgeDot.kt +27 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Button.kt +288 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/CheckBox.kt +80 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Divider.kt +23 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Icon.kt +42 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/IconButton.kt +126 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Image.kt +51 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Input.kt +299 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputMoney.kt +246 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputSearch.kt +223 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/InputTextArea.kt +244 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PopupNotify.kt +281 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/PromotionPopup.kt +72 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Radio.kt +65 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Skeleton.kt +64 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Switch.kt +63 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Tag.kt +73 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/components/Text.kt +42 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Colors.kt +150 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Radius.kt +12 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Spacing.kt +13 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Theme.kt +173 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/const/Typography.kt +242 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Card.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Item.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/layout/Section.kt +2 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/modifier/Shadow.kt +50 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Icons.kt +1321 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Platform.kt +3 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/SetMaskFilter.kt +5 -0
- package/compose/src/commonMain/kotlin/vn/momo/kits/utils/Utils.kt +97 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/utils/Platform.kt +3 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/utils/SetMaskFilter.kt +9 -0
- package/compose/src/iosMain/kotlin/vn/momo/kits/utils/Utils.ios.kt +18 -0
- package/gradle.properties +19 -0
- package/gradlew +240 -0
- package/gradlew.bat +91 -0
- package/ios/Button/Button.swift +9 -2
- package/ios/CalculatorKeyboard/CalculatorKeyboard.swift +126 -0
- package/ios/Checkbox/Checkbox.swift +38 -0
- package/ios/{Colors+Spacing → Colors+Radius+Spacing}/Colors.swift +21 -19
- package/ios/Colors+Radius+Spacing/Radius.swift +22 -0
- package/ios/Image/Image.swift +60 -0
- package/ios/Input/Input.swift +88 -37
- package/ios/OTPKeyboard/KeyboardButton.swift +12 -4
- package/ios/OTPKeyboard/OTPKeyboard.swift +1 -1
- package/ios/Popup/PopupDisplay.swift +169 -0
- package/ios/Popup/PopupInput.swift +96 -0
- package/ios/Popup/PopupPromotion.swift +52 -0
- package/ios/PopupView/FullscreenPopup.swift +251 -0
- package/ios/{Popup → PopupView}/Modifiers.swift +6 -20
- package/ios/{Popup → PopupView}/PopupView.swift +38 -146
- package/ios/PopupView/Utils++.swift +281 -0
- package/ios/ScrollIndicator/ScrollIndicator.swift +79 -0
- package/ios/Switch/Switch.swift +44 -0
- package/ios/Template/Logo/Logo.swift +75 -0
- package/ios/Template/TrustBanner/TrustBanner.swift +189 -0
- package/ios/native-kits.podspec +2 -0
- package/local.properties +8 -0
- package/package.json +6 -6
- package/publish.sh +1 -10
- package/settings.gradle.kts +41 -0
- package/android/gradle.properties +0 -5
- package/android/src/main/java/com/momoplatform/nativekits/NativeKitsPackage.kt +0 -17
- package/android/src/main/java/com/momoplatform/nativekits/NativeKitsViewManager.kt +0 -20
- package/example/ios/Example/Assets.xcassets/AppIcon.appiconset/Contents.json +0 -63
- package/example/ios/Example/Assets.xcassets/Background.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Border.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Card.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Contents.json +0 -6
- package/example/ios/Example/Assets.xcassets/Error.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Primary.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/PrimaryDark.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/PrimaryLight.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Secondary.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Success.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Text.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/TextSecondary.colorset/Contents.json +0 -38
- package/example/ios/Example/Assets.xcassets/Warning.colorset/Contents.json +0 -38
- package/example/ios/Example/ComponentDetail.swift +0 -35
- package/example/ios/Example/ComponentItem.swift +0 -24
- package/example/ios/Example/ComponentModel.swift +0 -33
- package/example/ios/Example/ContentView.swift +0 -53
- package/example/ios/Example/Example.entitlements +0 -10
- package/example/ios/Example/Foundation/ButtonDemo.swift +0 -80
- package/example/ios/Example/Foundation/Popup/ActionSheets.swift +0 -136
- package/example/ios/Example/Foundation/Popup/Floats.swift +0 -127
- package/example/ios/Example/Foundation/Popup/Popups.swift +0 -101
- package/example/ios/Example/Foundation/PopupDemo.swift +0 -366
- package/example/ios/Example/Foundation/TextInputDemo.swift +0 -31
- package/example/ios/Example/Foundation/TypographyDemo.swift +0 -53
- package/example/ios/Example/Foundation.swift +0 -26
- package/example/ios/Example/Info.plist +0 -18
- package/example/ios/Example/Library/SwipeableDemo.swift +0 -105
- package/example/ios/Example/Library.swift +0 -26
- package/example/ios/Example/Main.swift +0 -11
- package/example/ios/Example/Overview.swift +0 -20
- package/example/ios/Example/Preview Content/Preview Assets.xcassets/Contents.json +0 -6
- package/example/ios/Example/Resource/SFProText-Black.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Bold.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Heavy.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Light.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Medium.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Regular.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Semibold.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Thin.ttf +0 -0
- package/example/ios/Example/Resource/SFProText-Ultralight.ttf +0 -0
- package/example/ios/Example/Resource/foundation.json +0 -33
- package/example/ios/Example/Resource/library.json +0 -8
- package/example/ios/Example/Utils.swift +0 -30
- package/example/ios/Example/ViewModifier/DarkViewModifier.swift +0 -22
- package/example/ios/Example.xcodeproj/project.pbxproj +0 -570
- package/example/ios/Example.xcodeproj/project.xcworkspace/contents.xcworkspacedata +0 -7
- package/example/ios/Example.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/example/ios/Example.xcodeproj/project.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -14
- package/example/ios/Example.xcworkspace/contents.xcworkspacedata +0 -10
- package/example/ios/Example.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +0 -8
- package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/UserInterfaceState.xcuserstate +0 -0
- package/example/ios/Example.xcworkspace/xcuserdata/wem.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist +0 -6
- package/example/ios/Podfile +0 -6
- package/example/ios/Podfile.lock +0 -16
- package/example/ios/Pods/Local Podspecs/MoMoUIKits.podspec.json +0 -29
- package/example/ios/Pods/Manifest.lock +0 -16
- package/example/ios/Pods/Pods.xcodeproj/project.pbxproj +0 -661
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/MoMoUIKits.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/Pods-Example.xcscheme +0 -58
- package/example/ios/Pods/Pods.xcodeproj/xcuserdata/wem.xcuserdatad/xcschemes/xcschememanagement.plist +0 -25
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-dummy.m +0 -5
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-prefix.pch +0 -12
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits-umbrella.h +0 -16
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.debug.xcconfig +0 -12
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.modulemap +0 -6
- package/example/ios/Pods/Target Support Files/MoMoUIKits/MoMoUIKits.release.xcconfig +0 -12
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.markdown +0 -3
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-acknowledgements.plist +0 -29
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-dummy.m +0 -5
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example-umbrella.h +0 -16
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig +0 -14
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.modulemap +0 -6
- package/example/ios/Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig +0 -14
- package/ios/Colors+Spacing/Radius.swift +0 -11
- package/ios/Popup/Utils++.swift +0 -163
- /package/ios/{Colors+Spacing → Colors+Radius+Spacing}/Spacing.swift +0 -0
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
|
|
2
|
+
import Foundation
|
|
3
|
+
import SwiftUI
|
|
4
|
+
|
|
5
|
+
public struct FullscreenPopup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
6
|
+
|
|
7
|
+
// MARK: - Presentaion
|
|
8
|
+
@Binding var isPresented: Bool
|
|
9
|
+
@Binding var item: Item?
|
|
10
|
+
|
|
11
|
+
var isBoolMode: Bool
|
|
12
|
+
|
|
13
|
+
var sheetPresented: Bool {
|
|
14
|
+
item != nil || isPresented
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
// MARK: - Parameters
|
|
18
|
+
var type: Popup<Item, PopupContent>.PopupType
|
|
19
|
+
var position: Popup<Item, PopupContent>.Position
|
|
20
|
+
|
|
21
|
+
var animation: Animation
|
|
22
|
+
|
|
23
|
+
/// If nil - never hides on its own
|
|
24
|
+
var autohideIn: Double?
|
|
25
|
+
|
|
26
|
+
/// Should allow dismiss by dragging
|
|
27
|
+
var dragToDismiss: Bool
|
|
28
|
+
|
|
29
|
+
/// Should close on tap outside - default is `true`
|
|
30
|
+
var closeOnTapOutside: Bool
|
|
31
|
+
|
|
32
|
+
/// Background color for outside area - default is `Color.clear`
|
|
33
|
+
var backgroundColor: Color
|
|
34
|
+
|
|
35
|
+
/// is called on any close action
|
|
36
|
+
var dismissCallback: (DismissSource) -> ()
|
|
37
|
+
|
|
38
|
+
var view: () -> PopupContent
|
|
39
|
+
|
|
40
|
+
// MARK: - Presentation animation
|
|
41
|
+
/// Trigger popup showing/hiding animations and...
|
|
42
|
+
@State private var shouldShowContent = false
|
|
43
|
+
|
|
44
|
+
/// ... once hiding animation is finished remove popup from the memory using this flag
|
|
45
|
+
@State private var showContent = false
|
|
46
|
+
|
|
47
|
+
/// show transparentNonAnimatingFullScreenCover
|
|
48
|
+
@State private var showSheet = false
|
|
49
|
+
|
|
50
|
+
/// opacity of background color
|
|
51
|
+
@State private var opacity = 0.0
|
|
52
|
+
|
|
53
|
+
// MARK: - Autohide
|
|
54
|
+
/// Class reference for capturing a weak reference later in dispatch work holder.
|
|
55
|
+
private var isPresentedRef: ClassReference<Binding<Bool>>?
|
|
56
|
+
private var itemRef: ClassReference<Binding<Item?>>?
|
|
57
|
+
|
|
58
|
+
/// holder for autohiding dispatch work (to be able to cancel it when needed)
|
|
59
|
+
private var dispatchWorkHolder = DispatchWorkHolder()
|
|
60
|
+
|
|
61
|
+
// MARK: - Internal
|
|
62
|
+
/// Set dismiss souce to pass to dismiss callback
|
|
63
|
+
@State private var dismissSource: DismissSource?
|
|
64
|
+
|
|
65
|
+
init(isPresented: Binding<Bool>,
|
|
66
|
+
type: Popup<Item, PopupContent>.PopupType = .`default`,
|
|
67
|
+
position: Popup<Item, PopupContent>.Position = .bottom,
|
|
68
|
+
animation: Animation,
|
|
69
|
+
autohideIn: Double?,
|
|
70
|
+
dragToDismiss: Bool,
|
|
71
|
+
closeOnTapOutside: Bool,
|
|
72
|
+
backgroundColor: Color,
|
|
73
|
+
dismissCallback: @escaping (DismissSource) -> (),
|
|
74
|
+
view: @escaping () -> PopupContent) {
|
|
75
|
+
self._isPresented = isPresented
|
|
76
|
+
self._item = .constant(nil)
|
|
77
|
+
self.isBoolMode = true
|
|
78
|
+
|
|
79
|
+
self.type = type
|
|
80
|
+
self.position = position
|
|
81
|
+
self.animation = animation
|
|
82
|
+
self.autohideIn = autohideIn
|
|
83
|
+
self.dragToDismiss = dragToDismiss
|
|
84
|
+
self.closeOnTapOutside = closeOnTapOutside
|
|
85
|
+
self.backgroundColor = backgroundColor
|
|
86
|
+
self.dismissCallback = dismissCallback
|
|
87
|
+
self.view = view
|
|
88
|
+
|
|
89
|
+
self.isPresentedRef = ClassReference(self.$isPresented)
|
|
90
|
+
self.itemRef = ClassReference(self.$item)
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
init(item: Binding<Item?>,
|
|
94
|
+
type: Popup<Item, PopupContent>.PopupType = .`default`,
|
|
95
|
+
position: Popup<Item, PopupContent>.Position = .bottom,
|
|
96
|
+
animation: Animation,
|
|
97
|
+
autohideIn: Double?,
|
|
98
|
+
dragToDismiss: Bool,
|
|
99
|
+
closeOnTapOutside: Bool,
|
|
100
|
+
backgroundColor: Color,
|
|
101
|
+
dismissCallback: @escaping (DismissSource) -> (),
|
|
102
|
+
view: @escaping () -> PopupContent) {
|
|
103
|
+
self._isPresented = .constant(false)
|
|
104
|
+
self._item = item
|
|
105
|
+
self.isBoolMode = false
|
|
106
|
+
|
|
107
|
+
self.type = type
|
|
108
|
+
self.position = position
|
|
109
|
+
self.animation = animation
|
|
110
|
+
self.autohideIn = autohideIn
|
|
111
|
+
self.dragToDismiss = dragToDismiss
|
|
112
|
+
self.closeOnTapOutside = closeOnTapOutside
|
|
113
|
+
self.backgroundColor = backgroundColor
|
|
114
|
+
self.dismissCallback = dismissCallback
|
|
115
|
+
self.view = view
|
|
116
|
+
|
|
117
|
+
self.isPresentedRef = ClassReference(self.$isPresented)
|
|
118
|
+
self.itemRef = ClassReference(self.$item)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
public func body(content: Content) -> some View {
|
|
122
|
+
if isBoolMode {
|
|
123
|
+
boolBody(content: content)
|
|
124
|
+
} else {
|
|
125
|
+
itemBody(content: content)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
func backgroundColorView() -> some View {
|
|
130
|
+
backgroundColor.opacity(opacity)
|
|
131
|
+
.applyIf(closeOnTapOutside) { view in
|
|
132
|
+
view.contentShape(Rectangle())
|
|
133
|
+
}
|
|
134
|
+
.addTapIf(if: closeOnTapOutside) {
|
|
135
|
+
dismissSource = .tapOutside
|
|
136
|
+
isPresented = false
|
|
137
|
+
item = nil
|
|
138
|
+
}
|
|
139
|
+
.edgesIgnoringSafeArea(.all)
|
|
140
|
+
.animation(.linear(duration: 0.2), value: opacity)
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
public func boolBody(content: Content) -> some View {
|
|
144
|
+
content
|
|
145
|
+
.transparentNonAnimatingFullScreenCover(isPresented: $showSheet) {
|
|
146
|
+
backgroundColorView()
|
|
147
|
+
.modifier(
|
|
148
|
+
Popup(
|
|
149
|
+
isPresented: $isPresented,
|
|
150
|
+
type: type,
|
|
151
|
+
position: position,
|
|
152
|
+
animation: animation,
|
|
153
|
+
autohideIn: autohideIn,
|
|
154
|
+
dragToDismiss: dragToDismiss,
|
|
155
|
+
closeOnTapOutside: closeOnTapOutside,
|
|
156
|
+
shouldShowContent: shouldShowContent,
|
|
157
|
+
showContent: showContent,
|
|
158
|
+
dismissCallback: { _ in },
|
|
159
|
+
dismissSource: $dismissSource,
|
|
160
|
+
animationCompletedCallback: onAnimationCompleted,
|
|
161
|
+
view: view)
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
.valueChanged(value: isPresented, onChange: { newValue in
|
|
165
|
+
appearAction(sheetPresented: newValue)
|
|
166
|
+
})
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
public func itemBody(content: Content) -> some View {
|
|
170
|
+
content
|
|
171
|
+
.transparentNonAnimatingFullScreenCover(isPresented: $showSheet) {
|
|
172
|
+
backgroundColorView()
|
|
173
|
+
.modifier(
|
|
174
|
+
Popup(
|
|
175
|
+
item: $item,
|
|
176
|
+
type: type,
|
|
177
|
+
position: position,
|
|
178
|
+
animation: animation,
|
|
179
|
+
autohideIn: autohideIn,
|
|
180
|
+
dragToDismiss: dragToDismiss,
|
|
181
|
+
closeOnTapOutside: closeOnTapOutside,
|
|
182
|
+
shouldShowContent: shouldShowContent,
|
|
183
|
+
showContent: showContent,
|
|
184
|
+
dismissCallback: { _ in },
|
|
185
|
+
dismissSource: $dismissSource,
|
|
186
|
+
animationCompletedCallback: onAnimationCompleted,
|
|
187
|
+
view: view)
|
|
188
|
+
)
|
|
189
|
+
}
|
|
190
|
+
.valueChanged(value: item, onChange: { newValue in
|
|
191
|
+
appearAction(sheetPresented: newValue != nil)
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
func appearAction(sheetPresented: Bool) {
|
|
196
|
+
if sheetPresented {
|
|
197
|
+
dismissSource = nil
|
|
198
|
+
showSheet = true // show transparent fullscreen sheet
|
|
199
|
+
showContent = true // immediately load popup body
|
|
200
|
+
performWithDelay(0.01) {
|
|
201
|
+
shouldShowContent = true // this will cause currentOffset change thus triggering the sliding showing animation
|
|
202
|
+
opacity = 1 // this will cause cross disolving animation for background color
|
|
203
|
+
setupAutohide()
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
dispatchWorkHolder.work?.cancel()
|
|
207
|
+
shouldShowContent = false // this will cause currentOffset change thus triggering the sliding hiding animation
|
|
208
|
+
opacity = 0
|
|
209
|
+
// do the rest once the animation is finished (see onAnimationCompleted())
|
|
210
|
+
performWithDelay(0.3) { // TEMP: imitate onAnimationCompleted for now
|
|
211
|
+
onAnimationCompleted()
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
func onAnimationCompleted() -> () {
|
|
217
|
+
if shouldShowContent { // return if this was called on showing animation, only proceed if called on hiding
|
|
218
|
+
return
|
|
219
|
+
}
|
|
220
|
+
showContent = false // unload popup body after hiding animation is done
|
|
221
|
+
performWithDelay(0.01) {
|
|
222
|
+
showSheet = false
|
|
223
|
+
}
|
|
224
|
+
dismissCallback(dismissSource ?? .binding)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
func setupAutohide() {
|
|
228
|
+
// if needed, dispatch autohide and cancel previous one
|
|
229
|
+
if let autohideIn = autohideIn {
|
|
230
|
+
dispatchWorkHolder.work?.cancel()
|
|
231
|
+
|
|
232
|
+
// Weak reference to avoid the work item capturing the struct,
|
|
233
|
+
// which would create a retain cycle with the work holder itself.
|
|
234
|
+
dispatchWorkHolder.work = DispatchWorkItem(block: { [weak isPresentedRef, weak itemRef] in
|
|
235
|
+
isPresentedRef?.value.wrappedValue = false
|
|
236
|
+
itemRef?.value.wrappedValue = nil
|
|
237
|
+
dismissSource = .autohide
|
|
238
|
+
})
|
|
239
|
+
if sheetPresented, let work = dispatchWorkHolder.work {
|
|
240
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + autohideIn, execute: work)
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
func performWithDelay(_ delay: Double, block: @escaping ()->()) {
|
|
246
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
|
|
247
|
+
block()
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
1
|
import SwiftUI
|
|
4
2
|
|
|
5
3
|
extension View {
|
|
@@ -11,19 +9,17 @@ extension View {
|
|
|
11
9
|
animation: Animation = Animation.easeOut(duration: 0.3),
|
|
12
10
|
autohideIn: Double? = nil,
|
|
13
11
|
dragToDismiss: Bool = true,
|
|
14
|
-
closeOnTap: Bool = true,
|
|
15
12
|
closeOnTapOutside: Bool = false,
|
|
16
13
|
backgroundColor: Color = Color.clear,
|
|
17
14
|
@ViewBuilder view: @escaping () -> PopupContent) -> some View {
|
|
18
15
|
self.modifier(
|
|
19
|
-
|
|
16
|
+
FullscreenPopup(
|
|
20
17
|
item: item,
|
|
21
18
|
type: type,
|
|
22
19
|
position: position,
|
|
23
20
|
animation: animation,
|
|
24
21
|
autohideIn: autohideIn,
|
|
25
22
|
dragToDismiss: dragToDismiss,
|
|
26
|
-
closeOnTap: closeOnTap,
|
|
27
23
|
closeOnTapOutside: closeOnTapOutside,
|
|
28
24
|
backgroundColor: backgroundColor,
|
|
29
25
|
dismissCallback: { _ in },
|
|
@@ -38,19 +34,17 @@ extension View {
|
|
|
38
34
|
animation: Animation = Animation.easeOut(duration: 0.3),
|
|
39
35
|
autohideIn: Double? = nil,
|
|
40
36
|
dragToDismiss: Bool = true,
|
|
41
|
-
closeOnTap: Bool = true,
|
|
42
37
|
closeOnTapOutside: Bool = false,
|
|
43
38
|
backgroundColor: Color = Color.clear,
|
|
44
39
|
@ViewBuilder view: @escaping () -> PopupContent) -> some View {
|
|
45
40
|
self.modifier(
|
|
46
|
-
|
|
41
|
+
FullscreenPopup<Int, PopupContent>(
|
|
47
42
|
isPresented: isPresented,
|
|
48
43
|
type: type,
|
|
49
44
|
position: position,
|
|
50
45
|
animation: animation,
|
|
51
46
|
autohideIn: autohideIn,
|
|
52
47
|
dragToDismiss: dragToDismiss,
|
|
53
|
-
closeOnTap: closeOnTap,
|
|
54
48
|
closeOnTapOutside: closeOnTapOutside,
|
|
55
49
|
backgroundColor: backgroundColor,
|
|
56
50
|
dismissCallback: { _ in },
|
|
@@ -65,20 +59,18 @@ extension View {
|
|
|
65
59
|
animation: Animation = Animation.easeOut(duration: 0.3),
|
|
66
60
|
autohideIn: Double? = nil,
|
|
67
61
|
dragToDismiss: Bool = true,
|
|
68
|
-
closeOnTap: Bool = true,
|
|
69
62
|
closeOnTapOutside: Bool = false,
|
|
70
63
|
backgroundColor: Color = Color.clear,
|
|
71
64
|
dismissCallback: @escaping () -> (),
|
|
72
65
|
@ViewBuilder view: @escaping () -> PopupContent) -> some View {
|
|
73
66
|
self.modifier(
|
|
74
|
-
|
|
67
|
+
FullscreenPopup(
|
|
75
68
|
item: item,
|
|
76
69
|
type: type,
|
|
77
70
|
position: position,
|
|
78
71
|
animation: animation,
|
|
79
72
|
autohideIn: autohideIn,
|
|
80
73
|
dragToDismiss: dragToDismiss,
|
|
81
|
-
closeOnTap: closeOnTap,
|
|
82
74
|
closeOnTapOutside: closeOnTapOutside,
|
|
83
75
|
backgroundColor: backgroundColor,
|
|
84
76
|
dismissCallback: { _ in dismissCallback() },
|
|
@@ -93,20 +85,18 @@ extension View {
|
|
|
93
85
|
animation: Animation = Animation.easeOut(duration: 0.3),
|
|
94
86
|
autohideIn: Double? = nil,
|
|
95
87
|
dragToDismiss: Bool = true,
|
|
96
|
-
closeOnTap: Bool = true,
|
|
97
88
|
closeOnTapOutside: Bool = false,
|
|
98
89
|
backgroundColor: Color = Color.clear,
|
|
99
90
|
dismissCallback: @escaping () -> (),
|
|
100
91
|
@ViewBuilder view: @escaping () -> PopupContent) -> some View {
|
|
101
92
|
self.modifier(
|
|
102
|
-
|
|
93
|
+
FullscreenPopup<Int, PopupContent>(
|
|
103
94
|
isPresented: isPresented,
|
|
104
95
|
type: type,
|
|
105
96
|
position: position,
|
|
106
97
|
animation: animation,
|
|
107
98
|
autohideIn: autohideIn,
|
|
108
99
|
dragToDismiss: dragToDismiss,
|
|
109
|
-
closeOnTap: closeOnTap,
|
|
110
100
|
closeOnTapOutside: closeOnTapOutside,
|
|
111
101
|
backgroundColor: backgroundColor,
|
|
112
102
|
dismissCallback: { _ in dismissCallback() },
|
|
@@ -121,20 +111,18 @@ extension View {
|
|
|
121
111
|
animation: Animation = Animation.easeOut(duration: 0.3),
|
|
122
112
|
autohideIn: Double? = nil,
|
|
123
113
|
dragToDismiss: Bool = true,
|
|
124
|
-
closeOnTap: Bool = true,
|
|
125
114
|
closeOnTapOutside: Bool = false,
|
|
126
115
|
backgroundColor: Color = Color.clear,
|
|
127
116
|
dismissSourceCallback: @escaping (DismissSource) -> (),
|
|
128
117
|
@ViewBuilder view: @escaping () -> PopupContent) -> some View {
|
|
129
118
|
self.modifier(
|
|
130
|
-
|
|
119
|
+
FullscreenPopup(
|
|
131
120
|
item: item,
|
|
132
121
|
type: type,
|
|
133
122
|
position: position,
|
|
134
123
|
animation: animation,
|
|
135
124
|
autohideIn: autohideIn,
|
|
136
125
|
dragToDismiss: dragToDismiss,
|
|
137
|
-
closeOnTap: closeOnTap,
|
|
138
126
|
closeOnTapOutside: closeOnTapOutside,
|
|
139
127
|
backgroundColor: backgroundColor,
|
|
140
128
|
dismissCallback: dismissSourceCallback,
|
|
@@ -149,20 +137,18 @@ extension View {
|
|
|
149
137
|
animation: Animation = Animation.easeOut(duration: 0.3),
|
|
150
138
|
autohideIn: Double? = nil,
|
|
151
139
|
dragToDismiss: Bool = true,
|
|
152
|
-
closeOnTap: Bool = true,
|
|
153
140
|
closeOnTapOutside: Bool = false,
|
|
154
141
|
backgroundColor: Color = Color.clear,
|
|
155
142
|
dismissSourceCallback: @escaping (DismissSource) -> (),
|
|
156
143
|
@ViewBuilder view: @escaping () -> PopupContent) -> some View {
|
|
157
144
|
self.modifier(
|
|
158
|
-
|
|
145
|
+
FullscreenPopup<Int, PopupContent>(
|
|
159
146
|
isPresented: isPresented,
|
|
160
147
|
type: type,
|
|
161
148
|
position: position,
|
|
162
149
|
animation: animation,
|
|
163
150
|
autohideIn: autohideIn,
|
|
164
151
|
dragToDismiss: dragToDismiss,
|
|
165
|
-
closeOnTap: closeOnTap,
|
|
166
152
|
closeOnTapOutside: closeOnTapOutside,
|
|
167
153
|
backgroundColor: backgroundColor,
|
|
168
154
|
dismissCallback: dismissSourceCallback,
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
1
|
import SwiftUI
|
|
4
2
|
|
|
5
3
|
public enum DismissSource {
|
|
@@ -18,10 +16,12 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
18
16
|
animation: Animation,
|
|
19
17
|
autohideIn: Double?,
|
|
20
18
|
dragToDismiss: Bool,
|
|
21
|
-
closeOnTap: Bool,
|
|
22
19
|
closeOnTapOutside: Bool,
|
|
23
|
-
|
|
20
|
+
shouldShowContent: Bool = true,
|
|
21
|
+
showContent: Bool = true,
|
|
24
22
|
dismissCallback: @escaping (DismissSource) -> (),
|
|
23
|
+
dismissSource: Binding<DismissSource?>,
|
|
24
|
+
animationCompletedCallback: @escaping () -> (),
|
|
25
25
|
view: @escaping () -> PopupContent) {
|
|
26
26
|
self._isPresented = isPresented
|
|
27
27
|
self._item = .constant(nil)
|
|
@@ -30,13 +30,13 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
30
30
|
self.animation = animation
|
|
31
31
|
self.autohideIn = autohideIn
|
|
32
32
|
self.dragToDismiss = dragToDismiss
|
|
33
|
-
self.closeOnTap = closeOnTap
|
|
34
33
|
self.closeOnTapOutside = closeOnTapOutside
|
|
35
|
-
self.
|
|
34
|
+
self.shouldShowContent = shouldShowContent
|
|
35
|
+
self.showContent = showContent
|
|
36
36
|
self.dismissCallback = dismissCallback
|
|
37
|
+
self._dismissSource = dismissSource
|
|
38
|
+
self.animationCompletedCallback = animationCompletedCallback
|
|
37
39
|
self.view = view
|
|
38
|
-
self.isPresentedRef = ClassReference(self.$isPresented)
|
|
39
|
-
self.itemRef = ClassReference(self.$item)
|
|
40
40
|
}
|
|
41
41
|
|
|
42
42
|
init(item: Binding<Item?>,
|
|
@@ -45,10 +45,12 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
45
45
|
animation: Animation,
|
|
46
46
|
autohideIn: Double?,
|
|
47
47
|
dragToDismiss: Bool,
|
|
48
|
-
closeOnTap: Bool,
|
|
49
48
|
closeOnTapOutside: Bool,
|
|
50
|
-
|
|
49
|
+
shouldShowContent: Bool = true,
|
|
50
|
+
showContent: Bool = true,
|
|
51
51
|
dismissCallback: @escaping (DismissSource) -> (),
|
|
52
|
+
dismissSource: Binding<DismissSource?>,
|
|
53
|
+
animationCompletedCallback: @escaping () -> (),
|
|
52
54
|
view: @escaping () -> PopupContent) {
|
|
53
55
|
self._isPresented = .constant(false)
|
|
54
56
|
self._item = item
|
|
@@ -57,13 +59,13 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
57
59
|
self.animation = animation
|
|
58
60
|
self.autohideIn = autohideIn
|
|
59
61
|
self.dragToDismiss = dragToDismiss
|
|
60
|
-
self.closeOnTap = closeOnTap
|
|
61
62
|
self.closeOnTapOutside = closeOnTapOutside
|
|
62
|
-
self.
|
|
63
|
+
self.shouldShowContent = shouldShowContent
|
|
64
|
+
self.showContent = showContent
|
|
63
65
|
self.dismissCallback = dismissCallback
|
|
66
|
+
self._dismissSource = dismissSource
|
|
67
|
+
self.animationCompletedCallback = animationCompletedCallback
|
|
64
68
|
self.view = view
|
|
65
|
-
self.isPresentedRef = ClassReference(self.$isPresented)
|
|
66
|
-
self.itemRef = ClassReference(self.$item)
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
public enum PopupType {
|
|
@@ -85,7 +87,6 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
85
87
|
public enum Position {
|
|
86
88
|
case top
|
|
87
89
|
case bottom
|
|
88
|
-
case center
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
private enum DragState {
|
|
@@ -112,15 +113,10 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
112
113
|
}
|
|
113
114
|
|
|
114
115
|
// MARK: - Public Properties
|
|
115
|
-
|
|
116
116
|
/// Tells if the sheet should be presented or not
|
|
117
117
|
@Binding var isPresented: Bool
|
|
118
118
|
@Binding var item: Item?
|
|
119
119
|
|
|
120
|
-
var sheetPresented: Bool {
|
|
121
|
-
item != nil || isPresented
|
|
122
|
-
}
|
|
123
|
-
|
|
124
120
|
var type: PopupType
|
|
125
121
|
var position: Position
|
|
126
122
|
|
|
@@ -129,33 +125,31 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
129
125
|
/// If nil - never hides on its own
|
|
130
126
|
var autohideIn: Double?
|
|
131
127
|
|
|
132
|
-
/// Should close on tap - default is `true`
|
|
133
|
-
var closeOnTap: Bool
|
|
134
|
-
|
|
135
128
|
/// Should allow dismiss by dragging
|
|
136
129
|
var dragToDismiss: Bool
|
|
137
130
|
|
|
138
131
|
/// Should close on tap outside - default is `true`
|
|
139
132
|
var closeOnTapOutside: Bool
|
|
140
|
-
|
|
141
|
-
///
|
|
142
|
-
var
|
|
133
|
+
|
|
134
|
+
/// Trigger popup showing/hiding animations and...
|
|
135
|
+
var shouldShowContent: Bool
|
|
136
|
+
|
|
137
|
+
/// ... once hiding animation is finished remove popup from the memory using this flag
|
|
138
|
+
var showContent: Bool
|
|
143
139
|
|
|
144
140
|
/// is called on any close action
|
|
145
141
|
var dismissCallback: (DismissSource) -> ()
|
|
146
142
|
|
|
147
|
-
|
|
143
|
+
/// Set dismiss souce to pass to dismiss callback
|
|
144
|
+
@Binding private var dismissSource: DismissSource?
|
|
148
145
|
|
|
149
|
-
///
|
|
150
|
-
var
|
|
146
|
+
/// called on showing/hiding sliding animation completed
|
|
147
|
+
var animationCompletedCallback: () -> ()
|
|
151
148
|
|
|
152
|
-
|
|
149
|
+
var view: () -> PopupContent
|
|
153
150
|
|
|
151
|
+
// MARK: - Private Properties
|
|
154
152
|
@Environment(\.safeAreaInsets) private var safeAreaInsets
|
|
155
|
-
|
|
156
|
-
/// Class reference for capturing a weak reference later in dispatch work holder.
|
|
157
|
-
private var isPresentedRef: ClassReference<Binding<Bool>>?
|
|
158
|
-
private var itemRef: ClassReference<Binding<Item?>>?
|
|
159
153
|
|
|
160
154
|
/// The rect and safe area of the hosting controller
|
|
161
155
|
@State private var presenterContentRect: CGRect = .zero
|
|
@@ -168,15 +162,6 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
168
162
|
|
|
169
163
|
/// Last position for drag gesture
|
|
170
164
|
@State private var lastDragPosition: CGFloat = 0
|
|
171
|
-
|
|
172
|
-
/// Trigger popup showing/hiding animations and...
|
|
173
|
-
@State private var shouldShowContent: Bool = false
|
|
174
|
-
|
|
175
|
-
/// ... once hiding animation is finished remove popup from the memory using this flag
|
|
176
|
-
@State private var showContent: Bool = false
|
|
177
|
-
|
|
178
|
-
/// Set dismiss souce to pass to dismiss callback
|
|
179
|
-
@State private var dismissSource: DismissSource?
|
|
180
165
|
|
|
181
166
|
/// The offset when the popup is displayed
|
|
182
167
|
private var displayedOffset: CGFloat {
|
|
@@ -200,9 +185,7 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
200
185
|
|
|
201
186
|
/// The offset when the popup is hidden
|
|
202
187
|
private var hiddenOffset: CGFloat {
|
|
203
|
-
if position == .
|
|
204
|
-
return displayedOffset
|
|
205
|
-
} else if position == .top {
|
|
188
|
+
if position == .top {
|
|
206
189
|
if presenterContentRect.isEmpty {
|
|
207
190
|
return -1000
|
|
208
191
|
}
|
|
@@ -219,11 +202,6 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
219
202
|
private var currentOffset: CGFloat {
|
|
220
203
|
return shouldShowContent ? displayedOffset : hiddenOffset
|
|
221
204
|
}
|
|
222
|
-
|
|
223
|
-
/// The current background opacity, based on the **presented** property
|
|
224
|
-
private var currentBackgroundOpacity: Double {
|
|
225
|
-
return shouldShowContent ? 1.0 : 0.0
|
|
226
|
-
}
|
|
227
205
|
|
|
228
206
|
private var screenSize: CGSize {
|
|
229
207
|
#if os(iOS) || os(tvOS)
|
|
@@ -240,94 +218,26 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
240
218
|
}
|
|
241
219
|
|
|
242
220
|
// MARK: - Content Builders
|
|
243
|
-
|
|
244
221
|
public func body(content: Content) -> some View {
|
|
245
|
-
|
|
246
|
-
.
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
dismissSource = .binding
|
|
253
|
-
}
|
|
254
|
-
if !isPresented {
|
|
255
|
-
dismissCallback(dismissSource ?? .autohide)
|
|
222
|
+
content
|
|
223
|
+
.frameGetter($presenterContentRect)
|
|
224
|
+
.overlay(
|
|
225
|
+
Group {
|
|
226
|
+
if showContent {
|
|
227
|
+
sheet()
|
|
228
|
+
}
|
|
256
229
|
}
|
|
257
|
-
|
|
258
|
-
.valueChanged(value: item) { item in
|
|
259
|
-
appearAction(sheetPresented: item != nil)
|
|
260
|
-
if item != nil {
|
|
261
|
-
dismissSource = .binding
|
|
262
|
-
}
|
|
263
|
-
if item == nil {
|
|
264
|
-
dismissCallback(dismissSource ?? .autohide)
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
private func main(content: Content) -> some View {
|
|
270
|
-
ZStack {
|
|
271
|
-
content
|
|
272
|
-
.frameGetter($presenterContentRect)
|
|
273
|
-
|
|
274
|
-
if showContent {
|
|
275
|
-
popupBackground()
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
.overlay(
|
|
279
|
-
Group {
|
|
280
|
-
if showContent {
|
|
281
|
-
sheet()
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
)
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
private func popupBackground() -> some View {
|
|
288
|
-
backgroundColor
|
|
289
|
-
.applyIf(closeOnTapOutside) { view in
|
|
290
|
-
view.contentShape(Rectangle())
|
|
291
|
-
}
|
|
292
|
-
.addTapIf(if: closeOnTapOutside) {
|
|
293
|
-
dismissSource = .tapOutside
|
|
294
|
-
dismiss()
|
|
295
|
-
}
|
|
296
|
-
.edgesIgnoringSafeArea(.all)
|
|
297
|
-
.opacity(currentBackgroundOpacity)
|
|
298
|
-
.animation(.linear)
|
|
230
|
+
)
|
|
299
231
|
}
|
|
300
232
|
|
|
301
233
|
/// This is the builder for the sheet content
|
|
302
234
|
func sheet() -> some View {
|
|
303
|
-
|
|
304
|
-
// if needed, dispatch autohide and cancel previous one
|
|
305
|
-
if let autohideIn = autohideIn {
|
|
306
|
-
dispatchWorkHolder.work?.cancel()
|
|
307
|
-
|
|
308
|
-
// Weak reference to avoid the work item capturing the struct,
|
|
309
|
-
// which would create a retain cycle with the work holder itself.
|
|
310
|
-
|
|
311
|
-
dispatchWorkHolder.work = DispatchWorkItem(block: { [weak isPresentedRef, weak itemRef] in
|
|
312
|
-
isPresentedRef?.value.wrappedValue = false
|
|
313
|
-
itemRef?.value.wrappedValue = nil
|
|
314
|
-
dismissSource = .autohide
|
|
315
|
-
})
|
|
316
|
-
if sheetPresented, let work = dispatchWorkHolder.work {
|
|
317
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + autohideIn, execute: work)
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
|
|
321
235
|
let sheet = ZStack {
|
|
322
236
|
self.view()
|
|
323
|
-
.addTapIf(if: closeOnTap) {
|
|
324
|
-
dismissSource = .tapInside
|
|
325
|
-
dismiss()
|
|
326
|
-
}
|
|
327
237
|
.frameGetter($sheetContentRect)
|
|
328
238
|
.offset(y: currentOffset)
|
|
329
239
|
.onAnimationCompleted(for: currentOffset) {
|
|
330
|
-
|
|
240
|
+
animationCompletedCallback()
|
|
331
241
|
}
|
|
332
242
|
.animation(animation)
|
|
333
243
|
}
|
|
@@ -372,26 +282,8 @@ public struct Popup<Item: Equatable, PopupContent: View>: ViewModifier {
|
|
|
372
282
|
}
|
|
373
283
|
#endif
|
|
374
284
|
|
|
375
|
-
private func appearAction(sheetPresented: Bool) {
|
|
376
|
-
if sheetPresented {
|
|
377
|
-
showContent = true // immediately load popup body
|
|
378
|
-
DispatchQueue.main.async {
|
|
379
|
-
shouldShowContent = true // this will cause currentOffset change thus triggering the showing animation
|
|
380
|
-
}
|
|
381
|
-
} else {
|
|
382
|
-
shouldShowContent = false // this will cause currentOffset change thus triggering the hiding animation
|
|
383
|
-
// unload popup body after hiding animation is done (see sheet())
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
|
|
387
285
|
private func dismiss() {
|
|
388
|
-
dispatchWorkHolder.work?.cancel()
|
|
389
286
|
isPresented = false
|
|
390
287
|
item = nil
|
|
391
|
-
if position == .center {
|
|
392
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
|
393
|
-
showContent = false
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
288
|
}
|
|
397
289
|
}
|