├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ └── contents.xcworkspacedata
├── LICENSE
├── Package.resolved
├── Package.swift
├── PopupExample
├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Color
│ │ ├── Contents.json
│ │ ├── dark.colorset
│ │ │ └── Contents.json
│ │ ├── darkBlue.colorset
│ │ │ └── Contents.json
│ │ ├── darkText.colorset
│ │ │ └── Contents.json
│ │ ├── light.colorset
│ │ │ └── Contents.json
│ │ ├── lightBlue.colorset
│ │ │ └── Contents.json
│ │ ├── purple.colorset
│ │ │ └── Contents.json
│ │ ├── semiLight.colorset
│ │ │ └── Contents.json
│ │ ├── semidark.colorset
│ │ │ └── Contents.json
│ │ └── yellow.colorset
│ │ │ └── Contents.json
│ ├── Contents.json
│ ├── avatar1.imageset
│ │ ├── Contents.json
│ │ ├── avatar1.png
│ │ ├── avatar1@2x.png
│ │ └── avatar1@3x.png
│ ├── avatar2.imageset
│ │ ├── Contents.json
│ │ ├── avatar2.png
│ │ ├── avatar2@2x.png
│ │ └── avatar2@3x.png
│ ├── avatar3.imageset
│ │ ├── Contents.json
│ │ ├── avatar3.png
│ │ ├── avatar3@2x.png
│ │ └── avatar3@3x.png
│ ├── avatar4.imageset
│ │ ├── Contents.json
│ │ └── avatar4.pdf
│ ├── avatar5.imageset
│ │ ├── Contents.json
│ │ └── avatar5.pdf
│ ├── avatar6.imageset
│ │ ├── Contents.json
│ │ └── avatar6.pdf
│ ├── check_circle.imageset
│ │ ├── Check Circle.pdf
│ │ └── Contents.json
│ ├── checkmark.imageset
│ │ ├── Contents.json
│ │ ├── checkmark.png
│ │ ├── checkmark@2x.png
│ │ └── checkmark@3x.png
│ ├── chest.imageset
│ │ ├── Contents.json
│ │ └── chest.pdf
│ ├── cross.imageset
│ │ ├── Contents.json
│ │ └── Vector.pdf
│ ├── file.imageset
│ │ ├── Contents.json
│ │ └── file.pdf
│ ├── fitness.imageset
│ │ ├── Contents.json
│ │ ├── fitness.png
│ │ ├── fitness@2x.png
│ │ └── fitness@3x.png
│ ├── gift.imageset
│ │ ├── Contents.json
│ │ └── gift.pdf
│ ├── gift2.imageset
│ │ ├── Contents.json
│ │ └── Gift.pdf
│ ├── grapes.imageset
│ │ ├── Contents.json
│ │ └── grapes (7).png
│ ├── okay.imageset
│ │ ├── Contents.json
│ │ └── okay-svg (1).png
│ ├── phone_call.imageset
│ │ ├── Contents.json
│ │ └── phone_call.pdf
│ ├── phone_call2.imageset
│ │ ├── Contents.json
│ │ └── phone_call2.pdf
│ ├── shop_NA.imageset
│ │ ├── Contents.json
│ │ └── shop_NA.png
│ ├── shop_coffee.imageset
│ │ ├── Contents.json
│ │ └── shop_coffee.png
│ ├── transaction_coffee.imageset
│ │ ├── Contents.json
│ │ └── transaction_coffee.png
│ └── winner.imageset
│ │ ├── Contents.json
│ │ └── winner.pdf
├── Font
│ ├── NunitoSans_7pt-Bold.ttf
│ ├── NunitoSans_7pt-Light.ttf
│ ├── NunitoSans_7pt-Medium.ttf
│ └── NunitoSans_7pt-Regular.ttf
├── PopupExample.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── swiftpm
│ │ │ └── Package.resolved
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── PopupExample.xcscheme
├── PopupExample
│ ├── Components
│ │ ├── Images.swift
│ │ └── PopupButton.swift
│ ├── ContentView.swift
│ ├── Examples
│ │ ├── ActionSheets.swift
│ │ ├── FloatsBig.swift
│ │ ├── FloatsSmall.swift
│ │ ├── InputSheets.swift
│ │ ├── Popups.swift
│ │ └── Toasts.swift
│ ├── Info.plist
│ ├── PopupExample.entitlements
│ ├── PopupExampleApp.swift
│ ├── PopupsList.swift
│ ├── Preview Content
│ │ └── Preview Assets.xcassets
│ │ │ └── Contents.json
│ └── Utils.swift
└── PopupWatchExample Watch App
│ ├── ContentView.swift
│ ├── PopupWatchExampleApp.swift
│ └── Preview Content
│ └── Preview Assets.xcassets
│ └── Contents.json
├── README.md
└── Sources
└── PopupView
├── FullscreenPopup.swift
├── Info.plist
├── Modifiers.swift
├── PopupBackgroundView.swift
├── PopupScrollViewDelegate.swift
├── PopupView.h
├── PopupView.swift
├── PublicAPI.swift
└── Utils.swift
/.gitignore:
--------------------------------------------------------------------------------
1 |
2 | # Created by https://www.gitignore.io/api/swift,macos,carthage,cocoapods
3 | # Edit at https://www.gitignore.io/?templates=swift,macos,carthage,cocoapods
4 |
5 | ### Carthage ###
6 | # Carthage
7 | #
8 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
9 | # Carthage/Checkouts
10 |
11 | Carthage/Build
12 |
13 | ### CocoaPods ###
14 | ## CocoaPods GitIgnore Template
15 |
16 | # CocoaPods - Only use to conserve bandwidth / Save time on Pushing
17 | # - Also handy if you have a large number of dependant pods
18 | # - AS PER https://guides.cocoapods.org/using/using-cocoapods.html NEVER IGNORE THE LOCK FILE
19 | Pods/
20 | Podfile.lock
21 | Example.xcworkspace
22 |
23 | ### macOS ###
24 | # General
25 | .DS_Store
26 | .AppleDouble
27 | .LSOverride
28 |
29 | # Icon must end with two \r
30 | Icon
31 |
32 | # Thumbnails
33 | ._*
34 |
35 | # Files that might appear in the root of a volume
36 | .DocumentRevisions-V100
37 | .fseventsd
38 | .Spotlight-V100
39 | .TemporaryItems
40 | .Trashes
41 | .VolumeIcon.icns
42 | .com.apple.timemachine.donotpresent
43 |
44 | # Directories potentially created on remote AFP share
45 | .AppleDB
46 | .AppleDesktop
47 | Network Trash Folder
48 | Temporary Items
49 | .apdisk
50 |
51 | ### Swift ###
52 | # Xcode
53 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
54 |
55 | ## Build generated
56 | build/
57 | DerivedData/
58 |
59 | ## Various settings
60 | *.pbxuser
61 | !default.pbxuser
62 | *.mode1v3
63 | !default.mode1v3
64 | *.mode2v3
65 | !default.mode2v3
66 | *.perspectivev3
67 | !default.perspectivev3
68 | xcuserdata/
69 |
70 | ## Other
71 | *.moved-aside
72 | *.xccheckout
73 | *.xcscmblueprint
74 |
75 | ## Obj-C/Swift specific
76 | *.hmap
77 | *.ipa
78 | *.dSYM.zip
79 | *.dSYM
80 |
81 | ## Playgrounds
82 | timeline.xctimeline
83 | playground.xcworkspace
84 |
85 | # Swift Package Manager
86 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
87 | # Packages/
88 | # Package.pins
89 | # Package.resolved
90 | .build/
91 | # Add this line if you want to avoid checking in Xcode SPM integration.
92 | # .swiftpm/xcode
93 |
94 | # CocoaPods
95 | # We recommend against adding the Pods directory to your .gitignore. However
96 | # you should judge for yourself, the pros and cons are mentioned at:
97 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
98 | # Pods/
99 | # Add this line if you want to avoid checking in source code from the Xcode workspace
100 | # *.xcworkspace
101 |
102 | # Carthage
103 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
104 | # Carthage/Checkouts
105 |
106 |
107 | # Accio dependency management
108 | Dependencies/
109 | .accio/
110 |
111 | # fastlane
112 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
113 | # screenshots whenever they are needed.
114 | # For more information about the recommended setup visit:
115 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
116 |
117 | fastlane/report.xml
118 | fastlane/Preview.html
119 | fastlane/screenshots/**/*.png
120 | fastlane/test_output
121 |
122 | # Code Injection
123 | # After new code Injection tools there's a generated folder /iOSInjectionProject
124 | # https://github.com/johnno1962/injectionforxcode
125 |
126 | iOSInjectionProject/
127 |
128 | # End of https://www.gitignore.io/api/swift,macos,carthage,cocoapods
129 | .idea/
130 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2019 exyte
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is
8 | furnished to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in
11 | all copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
20 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "pins" : [
3 | {
4 | "identity" : "swiftui-introspect",
5 | "kind" : "remoteSourceControl",
6 | "location" : "https://github.com/siteline/swiftui-introspect",
7 | "state" : {
8 | "revision" : "807f73ce09a9b9723f12385e592b4e0aaebd3336",
9 | "version" : "1.3.0"
10 | }
11 | }
12 | ],
13 | "version" : 2
14 | }
15 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version: 5.9
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "PopupView",
7 | platforms: [
8 | .iOS(.v15),
9 | .macOS(.v11),
10 | .tvOS(.v14),
11 | .watchOS(.v7)
12 | ],
13 | products: [
14 | .library(name: "PopupView", targets: ["PopupView"]),
15 | ],
16 | dependencies: [
17 | .package(
18 | url: "https://github.com/siteline/swiftui-introspect",
19 | from: "1.0.0"
20 | )
21 | ],
22 | targets: [
23 | .target(
24 | name: "PopupView",
25 | dependencies: [
26 | .product(name: "SwiftUIIntrospect", package: "swiftui-introspect"),
27 | ],
28 | swiftSettings: [
29 | .enableExperimentalFeature("StrictConcurrency")
30 | ]
31 | )
32 | ]
33 | )
34 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0xEE",
9 | "green" : "0x6C",
10 | "red" : "0xAC"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "0xFF",
27 | "green" : "0xFF",
28 | "red" : "0xFE"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "scale" : "2x",
6 | "size" : "20x20"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "scale" : "3x",
11 | "size" : "20x20"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "scale" : "2x",
16 | "size" : "29x29"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "scale" : "3x",
21 | "size" : "29x29"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "scale" : "2x",
26 | "size" : "40x40"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "scale" : "3x",
31 | "size" : "40x40"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "scale" : "2x",
36 | "size" : "60x60"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "scale" : "3x",
41 | "size" : "60x60"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "scale" : "1x",
46 | "size" : "20x20"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "scale" : "2x",
51 | "size" : "20x20"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "scale" : "1x",
56 | "size" : "29x29"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "scale" : "2x",
61 | "size" : "29x29"
62 | },
63 | {
64 | "idiom" : "ipad",
65 | "scale" : "1x",
66 | "size" : "40x40"
67 | },
68 | {
69 | "idiom" : "ipad",
70 | "scale" : "2x",
71 | "size" : "40x40"
72 | },
73 | {
74 | "idiom" : "ipad",
75 | "scale" : "1x",
76 | "size" : "76x76"
77 | },
78 | {
79 | "idiom" : "ipad",
80 | "scale" : "2x",
81 | "size" : "76x76"
82 | },
83 | {
84 | "idiom" : "ipad",
85 | "scale" : "2x",
86 | "size" : "83.5x83.5"
87 | },
88 | {
89 | "idiom" : "ios-marketing",
90 | "scale" : "1x",
91 | "size" : "1024x1024"
92 | }
93 | ],
94 | "info" : {
95 | "author" : "xcode",
96 | "version" : 1
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/Color/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/Color/dark.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.169",
9 | "green" : "0.114",
10 | "red" : "0.122"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "1.000",
28 | "red" : "1.000"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/Color/darkBlue.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "1.000",
9 | "green" : "0.384",
10 | "red" : "0.286"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "1.000",
28 | "red" : "1.000"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/Color/darkText.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.263",
9 | "green" : "0.235",
10 | "red" : "0.235"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "1.000",
28 | "red" : "1.000"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/Color/light.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.918",
9 | "green" : "0.906",
10 | "red" : "0.906"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "1.000",
28 | "red" : "1.000"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/Color/lightBlue.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.922",
9 | "green" : "0.533",
10 | "red" : "0.149"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "1.000",
28 | "red" : "1.000"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/Color/purple.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.973",
9 | "green" : "0.396",
10 | "red" : "0.573"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "1.000",
28 | "red" : "1.000"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/Color/semiLight.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "0.520",
8 | "blue" : "0.855",
9 | "green" : "0.855",
10 | "red" : "0.855"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "1.000",
28 | "red" : "1.000"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/Color/semidark.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "0.700",
8 | "blue" : "0.118",
9 | "green" : "0.118",
10 | "red" : "0.118"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "1.000",
28 | "red" : "1.000"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/Color/yellow.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "color" : {
5 | "color-space" : "srgb",
6 | "components" : {
7 | "alpha" : "1.000",
8 | "blue" : "0.239",
9 | "green" : "0.725",
10 | "red" : "1.000"
11 | }
12 | },
13 | "idiom" : "universal"
14 | },
15 | {
16 | "appearances" : [
17 | {
18 | "appearance" : "luminosity",
19 | "value" : "dark"
20 | }
21 | ],
22 | "color" : {
23 | "color-space" : "srgb",
24 | "components" : {
25 | "alpha" : "1.000",
26 | "blue" : "1.000",
27 | "green" : "1.000",
28 | "red" : "1.000"
29 | }
30 | },
31 | "idiom" : "universal"
32 | }
33 | ],
34 | "info" : {
35 | "author" : "xcode",
36 | "version" : 1
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "avatar1.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "avatar1@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "avatar1@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar1.imageset/avatar1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar1.imageset/avatar1.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar1.imageset/avatar1@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar1.imageset/avatar1@2x.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar1.imageset/avatar1@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar1.imageset/avatar1@3x.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "avatar2.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "avatar2@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "avatar2@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar2.imageset/avatar2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar2.imageset/avatar2.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar2.imageset/avatar2@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar2.imageset/avatar2@2x.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar2.imageset/avatar2@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar2.imageset/avatar2@3x.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar3.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "avatar3.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "avatar3@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "avatar3@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar3.imageset/avatar3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar3.imageset/avatar3.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar3.imageset/avatar3@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar3.imageset/avatar3@2x.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar3.imageset/avatar3@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar3.imageset/avatar3@3x.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar4.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "avatar4.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar4.imageset/avatar4.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar4.imageset/avatar4.pdf
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar5.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "avatar5.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar5.imageset/avatar5.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar5.imageset/avatar5.pdf
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar6.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "avatar6.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/avatar6.imageset/avatar6.pdf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/avatar6.imageset/avatar6.pdf
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/check_circle.imageset/Check Circle.pdf:
--------------------------------------------------------------------------------
1 | %PDF-1.7
2 |
3 | 1 0 obj
4 | << >>
5 | endobj
6 |
7 | 2 0 obj
8 | << /Length 3 0 R >>
9 | stream
10 | /DeviceRGB CS
11 | /DeviceRGB cs
12 | q
13 | 1.000000 0.000000 -0.000000 1.000000 2.666626 1.166666 cm
14 | 0.002986 0.716667 0.304318 scn
15 | 25.916666 14.833333 m
16 | 25.916666 7.883751 20.282915 2.250000 13.333333 2.250000 c
17 | 13.333333 0.750000 l
18 | 21.111343 0.750000 27.416666 7.055323 27.416666 14.833333 c
19 | 25.916666 14.833333 l
20 | h
21 | 13.333333 2.250000 m
22 | 6.383750 2.250000 0.750000 7.883751 0.750000 14.833333 c
23 | -0.750000 14.833333 l
24 | -0.750000 7.055323 5.555323 0.750000 13.333333 0.750000 c
25 | 13.333333 2.250000 l
26 | h
27 | 0.750000 14.833333 m
28 | 0.750000 21.782917 6.383750 27.416666 13.333333 27.416666 c
29 | 13.333333 28.916666 l
30 | 5.555323 28.916666 -0.750000 22.611343 -0.750000 14.833333 c
31 | 0.750000 14.833333 l
32 | h
33 | 13.333333 27.416666 m
34 | 20.282915 27.416666 25.916666 21.782917 25.916666 14.833333 c
35 | 27.416666 14.833333 l
36 | 27.416666 22.611343 21.111343 28.916666 13.333333 28.916666 c
37 | 13.333333 27.416666 l
38 | h
39 | f
40 | n
41 | Q
42 | q
43 | 1.000000 0.000000 -0.000000 1.000000 11.333374 11.020220 cm
44 | 0.002986 0.716667 0.304318 scn
45 | 0.530330 4.843443 m
46 | 0.237437 5.136336 -0.237437 5.136336 -0.530330 4.843443 c
47 | -0.823223 4.550550 -0.823223 4.075675 -0.530330 3.782783 c
48 | 0.530330 4.843443 l
49 | h
50 | 2.666667 1.646446 m
51 | 2.136336 1.116116 l
52 | 2.429230 0.823223 2.904103 0.823223 3.196997 1.116116 c
53 | 2.666667 1.646446 l
54 | h
55 | 9.863663 7.782782 m
56 | 10.156556 8.075675 10.156556 8.550550 9.863663 8.843442 c
57 | 9.570769 9.136335 9.095896 9.136335 8.803002 8.843442 c
58 | 9.863663 7.782782 l
59 | h
60 | -0.530330 3.782783 m
61 | 2.136336 1.116116 l
62 | 3.196997 2.176776 l
63 | 0.530330 4.843443 l
64 | -0.530330 3.782783 l
65 | h
66 | 3.196997 1.116116 m
67 | 9.863663 7.782782 l
68 | 8.803002 8.843442 l
69 | 2.136336 2.176776 l
70 | 3.196997 1.116116 l
71 | h
72 | f
73 | n
74 | Q
75 |
76 | endstream
77 | endobj
78 |
79 | 3 0 obj
80 | 1609
81 | endobj
82 |
83 | 4 0 obj
84 | << /Annots []
85 | /Type /Page
86 | /MediaBox [ 0.000000 0.000000 32.000000 32.000000 ]
87 | /Resources 1 0 R
88 | /Contents 2 0 R
89 | /Parent 5 0 R
90 | >>
91 | endobj
92 |
93 | 5 0 obj
94 | << /Kids [ 4 0 R ]
95 | /Count 1
96 | /Type /Pages
97 | >>
98 | endobj
99 |
100 | 6 0 obj
101 | << /Pages 5 0 R
102 | /Type /Catalog
103 | >>
104 | endobj
105 |
106 | xref
107 | 0 7
108 | 0000000000 65535 f
109 | 0000000010 00000 n
110 | 0000000034 00000 n
111 | 0000001699 00000 n
112 | 0000001722 00000 n
113 | 0000001895 00000 n
114 | 0000001969 00000 n
115 | trailer
116 | << /ID [ (some) (id) ]
117 | /Root 6 0 R
118 | /Size 7
119 | >>
120 | startxref
121 | 2028
122 | %%EOF
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/check_circle.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Check Circle.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/checkmark.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "checkmark.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "checkmark@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "checkmark@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/checkmark.imageset/checkmark.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/checkmark.imageset/checkmark.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/checkmark.imageset/checkmark@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/checkmark.imageset/checkmark@2x.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/checkmark.imageset/checkmark@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/checkmark.imageset/checkmark@3x.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/chest.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "chest.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/cross.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Vector.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/cross.imageset/Vector.pdf:
--------------------------------------------------------------------------------
1 | %PDF-1.7
2 |
3 | 1 0 obj
4 | << /ExtGState << /E1 << /ca 0.400000 >> >> >>
5 | endobj
6 |
7 | 2 0 obj
8 | << /Length 3 0 R >>
9 | stream
10 | /DeviceRGB CS
11 | /DeviceRGB cs
12 | q
13 | /E1 gs
14 | 1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
15 | 1.000000 1.000000 1.000000 scn
16 | 6.179832 5.004830 m
17 | 9.763165 8.579830 l
18 | 9.920085 8.736750 10.008242 8.949578 10.008242 9.171496 c
19 | 10.008242 9.393414 9.920085 9.606243 9.763165 9.763164 c
20 | 9.606245 9.920083 9.393417 10.008240 9.171499 10.008240 c
21 | 8.949581 10.008240 8.736753 9.920083 8.579833 9.763164 c
22 | 5.004832 6.179831 l
23 | 1.429832 9.763164 l
24 | 1.272912 9.920083 1.060083 10.008240 0.838165 10.008240 c
25 | 0.616247 10.008240 0.403418 9.920083 0.246499 9.763164 c
26 | 0.089579 9.606243 0.001422 9.393414 0.001422 9.171496 c
27 | 0.001422 8.949578 0.089579 8.736750 0.246499 8.579830 c
28 | 3.829832 5.004830 l
29 | 0.246499 1.429831 l
30 | 0.168392 1.352362 0.106397 1.260195 0.064089 1.158646 c
31 | 0.021782 1.057096 0.000000 0.948174 0.000000 0.838164 c
32 | 0.000000 0.728155 0.021782 0.619233 0.064089 0.517684 c
33 | 0.106397 0.416135 0.168392 0.323968 0.246499 0.246499 c
34 | 0.323968 0.168391 0.416135 0.106395 0.517685 0.064088 c
35 | 0.619234 0.021781 0.728155 -0.000001 0.838165 -0.000001 c
36 | 0.948175 -0.000001 1.057097 0.021781 1.158646 0.064088 c
37 | 1.260195 0.106395 1.352363 0.168391 1.429832 0.246499 c
38 | 5.004832 3.829831 l
39 | 8.579833 0.246499 l
40 | 8.657302 0.168391 8.749469 0.106395 8.851018 0.064088 c
41 | 8.952568 0.021781 9.061489 -0.000001 9.171499 -0.000001 c
42 | 9.281509 -0.000001 9.390430 0.021781 9.491980 0.064088 c
43 | 9.593529 0.106395 9.685696 0.168391 9.763165 0.246499 c
44 | 9.841272 0.323968 9.903269 0.416135 9.945576 0.517684 c
45 | 9.987884 0.619233 10.009665 0.728155 10.009665 0.838164 c
46 | 10.009665 0.948174 9.987884 1.057096 9.945576 1.158646 c
47 | 9.903269 1.260195 9.841272 1.352362 9.763165 1.429831 c
48 | 6.179832 5.004830 l
49 | h
50 | f
51 | n
52 | Q
53 |
54 | endstream
55 | endobj
56 |
57 | 3 0 obj
58 | 1676
59 | endobj
60 |
61 | 4 0 obj
62 | << /Annots []
63 | /Type /Page
64 | /MediaBox [ 0.000000 0.000000 10.009644 10.008240 ]
65 | /Resources 1 0 R
66 | /Contents 2 0 R
67 | /Parent 5 0 R
68 | >>
69 | endobj
70 |
71 | 5 0 obj
72 | << /Kids [ 4 0 R ]
73 | /Count 1
74 | /Type /Pages
75 | >>
76 | endobj
77 |
78 | 6 0 obj
79 | << /Pages 5 0 R
80 | /Type /Catalog
81 | >>
82 | endobj
83 |
84 | xref
85 | 0 7
86 | 0000000000 65535 f
87 | 0000000010 00000 n
88 | 0000000074 00000 n
89 | 0000001806 00000 n
90 | 0000001829 00000 n
91 | 0000002002 00000 n
92 | 0000002076 00000 n
93 | trailer
94 | << /ID [ (some) (id) ]
95 | /Root 6 0 R
96 | /Size 7
97 | >>
98 | startxref
99 | 2135
100 | %%EOF
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/file.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "file.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/file.imageset/file.pdf:
--------------------------------------------------------------------------------
1 | %PDF-1.7
2 |
3 | 1 0 obj
4 | << >>
5 | endobj
6 |
7 | 2 0 obj
8 | << /Length 3 0 R >>
9 | stream
10 | /DeviceRGB CS
11 | /DeviceRGB cs
12 | q
13 | 1.000000 0.000000 -0.000000 1.000000 13.000000 13.248413 cm
14 | 1.000000 1.000000 1.000000 scn
15 | -0.750000 8.251587 m
16 | -0.750000 5.751587 l
17 | 0.750000 5.751587 l
18 | 0.750000 8.251587 l
19 | -0.750000 8.251587 l
20 | h
21 | 5.000000 0.001587 m
22 | 9.000000 0.001587 l
23 | 9.000000 1.501587 l
24 | 5.000000 1.501587 l
25 | 5.000000 0.001587 l
26 | h
27 | -0.750000 5.751587 m
28 | -0.750000 4.594278 -0.751593 3.650847 -0.651783 2.908472 c
29 | -0.549072 2.144520 -0.326790 1.482183 0.201903 0.953490 c
30 | 1.262563 2.014150 l
31 | 1.059023 2.217690 0.915189 2.510725 0.834841 3.108343 c
32 | 0.751593 3.727537 0.750000 4.551873 0.750000 5.751587 c
33 | -0.750000 5.751587 l
34 | h
35 | 5.000000 1.501587 m
36 | 3.800286 1.501587 2.975950 1.503180 2.356756 1.586428 c
37 | 1.759138 1.666776 1.466103 1.810610 1.262563 2.014150 c
38 | 0.201903 0.953490 l
39 | 0.730596 0.424797 1.392934 0.202515 2.156885 0.099804 c
40 | 2.899261 -0.000006 3.842691 0.001587 5.000000 0.001587 c
41 | 5.000000 1.501587 l
42 | h
43 | f
44 | n
45 | Q
46 | q
47 | 1.000000 0.000000 -0.000000 1.000000 2.000000 0.486816 cm
48 | 1.000000 1.000000 1.000000 scn
49 | 13.397319 19.459538 m
50 | 12.895686 18.901985 l
51 | 12.895686 18.901985 l
52 | 13.397319 19.459538 l
53 | h
54 | 17.357389 15.896639 m
55 | 16.855757 15.339087 l
56 | 16.855757 15.339087 l
57 | 17.357389 15.896639 l
58 | h
59 | 19.660423 13.359088 m
60 | 18.975336 13.053877 l
61 | 18.975336 13.053874 l
62 | 19.660423 13.359088 l
63 | h
64 | 1.171956 2.684757 m
65 | 1.702199 3.215174 l
66 | 1.702198 3.215176 l
67 | 1.171956 2.684757 l
68 | h
69 | 18.834581 2.684757 m
70 | 18.304338 3.215174 l
71 | 18.304337 3.215174 l
72 | 18.834581 2.684757 l
73 | h
74 | 16.291039 10.656041 m
75 | 16.706970 11.280142 l
76 | 16.706968 11.280142 l
77 | 16.291039 10.656041 l
78 | h
79 | 19.720732 10.656041 m
80 | 19.304802 11.280143 l
81 | 19.304800 11.280142 l
82 | 19.720732 10.656041 l
83 | h
84 | 7.716807 10.656041 m
85 | 7.300877 11.280142 l
86 | 7.300877 11.280142 l
87 | 7.716807 10.656041 l
88 | h
89 | 10.289076 10.656041 m
90 | 10.705008 11.280142 l
91 | 10.705008 11.280142 l
92 | 10.289076 10.656041 l
93 | h
94 | 4.287115 10.656041 m
95 | 3.871184 10.031940 l
96 | 3.871184 10.031940 l
97 | 4.287115 10.656041 l
98 | h
99 | 1.714846 10.656041 m
100 | 1.298915 11.280142 l
101 | 1.298915 11.280141 l
102 | 1.714846 10.656041 l
103 | h
104 | 16.291039 6.656040 m
105 | 16.706970 7.280141 l
106 | 16.706968 7.280141 l
107 | 16.291039 6.656040 l
108 | h
109 | 19.720732 6.656041 m
110 | 20.136662 6.031940 l
111 | 20.136663 6.031941 l
112 | 19.720732 6.656041 l
113 | h
114 | 13.718769 6.656040 m
115 | 13.302837 7.280141 l
116 | 13.302837 7.280141 l
117 | 13.718769 6.656040 l
118 | h
119 | 10.289076 6.656040 m
120 | 10.705008 7.280141 l
121 | 10.705008 7.280141 l
122 | 10.289076 6.656040 l
123 | h
124 | 7.716807 6.656040 m
125 | 7.300877 7.280141 l
126 | 7.300877 7.280141 l
127 | 7.716807 6.656040 l
128 | h
129 | 13.718769 10.656041 m
130 | 13.302837 11.280142 l
131 | 13.302837 11.280142 l
132 | 13.718769 10.656041 l
133 | h
134 | 4.287115 6.656040 m
135 | 3.871184 6.031940 l
136 | 3.871184 6.031940 l
137 | 4.287115 6.656040 l
138 | h
139 | 1.714846 6.656041 m
140 | 1.298915 7.280142 l
141 | 1.298915 7.280142 l
142 | 1.714846 6.656041 l
143 | h
144 | 1.088646 6.238710 m
145 | 1.504576 5.614610 l
146 | 1.504577 5.614610 l
147 | 1.088646 6.238710 l
148 | h
149 | 0.278273 4.398304 m
150 | 1.007832 4.572212 l
151 | 1.007832 4.572212 l
152 | 0.278273 4.398304 l
153 | h
154 | 19.971657 6.515432 m
155 | 20.721012 6.484366 l
156 | 20.721012 6.484366 l
157 | 19.971657 6.515432 l
158 | h
159 | 19.999893 11.185890 m
160 | 20.749765 11.199770 l
161 | 20.749765 11.199771 l
162 | 19.999893 11.185890 l
163 | h
164 | 0.214360 5.440413 m
165 | 0.912367 5.166027 l
166 | 0.912367 5.166029 l
167 | 0.214360 5.440413 l
168 | h
169 | 0.006134 11.271131 m
170 | 0.751532 11.354085 l
171 | 0.751532 11.354086 l
172 | 0.006134 11.271131 l
173 | h
174 | 1.459776 10.493419 m
175 | 1.804160 9.827161 l
176 | 1.804163 9.827162 l
177 | 1.459776 10.493419 l
178 | h
179 | 12.003922 2.263184 m
180 | 8.002614 2.263184 l
181 | 8.002614 0.763184 l
182 | 12.003922 0.763184 l
183 | 12.003922 2.263184 l
184 | h
185 | 0.750000 11.573499 m
186 | 0.750000 13.513184 l
187 | -0.750000 13.513184 l
188 | -0.750000 11.573499 l
189 | 0.750000 11.573499 l
190 | h
191 | 12.895686 18.901985 m
192 | 16.855757 15.339087 l
193 | 17.859022 16.454191 l
194 | 13.898952 20.017090 l
195 | 12.895686 18.901985 l
196 | h
197 | 16.855757 15.339087 m
198 | 18.209637 14.120993 18.709270 13.651097 18.975336 13.053877 c
199 | 20.345512 13.664299 l
200 | 19.919353 14.620869 19.114374 15.324743 17.859022 16.454191 c
201 | 16.855757 15.339087 l
202 | h
203 | 8.032416 20.763184 m
204 | 9.614695 20.763184 10.211914 20.751612 10.744201 20.547421 c
205 | 11.281443 21.947910 l
206 | 10.429418 22.274755 9.501137 22.263184 8.032416 22.263184 c
207 | 8.032416 20.763184 l
208 | h
209 | 13.898952 20.017090 m
210 | 12.812582 20.994503 12.133384 21.621096 11.281443 21.947910 c
211 | 10.744201 20.547421 l
212 | 11.276571 20.343197 11.725601 19.954718 12.895686 18.901985 c
213 | 13.898952 20.017090 l
214 | h
215 | 8.002614 2.263184 m
216 | 6.095184 2.263184 4.740036 2.264776 3.711997 2.402946 c
217 | 2.705507 2.538221 2.125591 2.791920 1.702199 3.215174 c
218 | 0.641712 2.154341 l
219 | 1.390277 1.406021 2.339456 1.073933 3.512189 0.916313 c
220 | 4.663373 0.761591 6.137576 0.763184 8.002614 0.763184 c
221 | 8.002614 2.263184 l
222 | h
223 | 12.003922 0.763184 m
224 | 13.868961 0.763184 15.343165 0.761591 16.494349 0.916313 c
225 | 17.667082 1.073933 18.616261 1.406021 19.364824 2.154341 c
226 | 18.304337 3.215174 l
227 | 17.880945 2.791920 17.301031 2.538221 16.294540 2.402946 c
228 | 15.266500 2.264776 13.911353 2.263184 12.003922 2.263184 c
229 | 12.003922 0.763184 l
230 | h
231 | 0.750000 13.513184 m
232 | 0.750000 15.420012 0.751594 16.774658 0.889802 17.802303 c
233 | 1.025106 18.808348 1.278841 19.387974 1.702199 19.811193 c
234 | 0.641712 20.872028 l
235 | -0.106886 20.123674 -0.439128 19.174706 -0.596813 18.002239 c
236 | -0.751594 16.851372 -0.750000 15.377593 -0.750000 13.513184 c
237 | 0.750000 13.513184 l
238 | h
239 | 8.032416 22.263184 m
240 | 6.157373 22.263184 4.675969 22.264763 3.520085 22.110113 c
241 | 2.343219 21.952658 1.390861 21.620932 0.641712 20.872028 c
242 | 1.702199 19.811193 l
243 | 2.125006 20.233862 2.706711 20.487925 3.719002 20.623362 c
244 | 4.752275 20.761604 6.115123 20.763184 8.032416 20.763184 c
245 | 8.032416 22.263184 l
246 | h
247 | 15.875108 10.031940 m
248 | 17.165417 9.172016 18.846352 9.172016 20.136662 10.031940 c
249 | 19.304800 11.280142 l
250 | 18.518251 10.755949 17.493515 10.755949 16.706970 11.280142 c
251 | 15.875108 10.031940 l
252 | h
253 | 8.132738 10.031940 m
254 | 8.659678 10.383119 9.346206 10.383119 9.873145 10.031940 c
255 | 10.705008 11.280142 l
256 | 9.674305 11.967052 8.331579 11.967052 7.300877 11.280142 c
257 | 8.132738 10.031940 l
258 | h
259 | 3.871184 10.031940 m
260 | 5.161493 9.172016 6.842429 9.172016 8.132738 10.031940 c
261 | 7.300877 11.280142 l
262 | 6.514330 10.755949 5.489592 10.755949 4.703046 11.280142 c
263 | 3.871184 10.031940 l
264 | h
265 | 2.130777 10.031940 m
266 | 2.657717 10.383119 3.344245 10.383119 3.871184 10.031940 c
267 | 4.703046 11.280142 l
268 | 3.672344 11.967052 2.329617 11.967052 1.298915 11.280142 c
269 | 2.130777 10.031940 l
270 | h
271 | 15.875108 6.031940 m
272 | 17.165417 5.172014 18.846352 5.172016 20.136662 6.031940 c
273 | 19.304800 7.280142 l
274 | 18.518251 6.755948 17.493515 6.755948 16.706970 7.280141 c
275 | 15.875108 6.031940 l
276 | h
277 | 14.134700 6.031940 m
278 | 14.661639 6.383118 15.348167 6.383118 15.875108 6.031940 c
279 | 16.706968 7.280141 l
280 | 15.676266 7.967051 14.333540 7.967051 13.302837 7.280141 c
281 | 14.134700 6.031940 l
282 | h
283 | 9.873145 6.031940 m
284 | 11.163454 5.172014 12.844391 5.172014 14.134700 6.031940 c
285 | 13.302837 7.280141 l
286 | 12.516292 6.755948 11.491553 6.755948 10.705008 7.280141 c
287 | 9.873145 6.031940 l
288 | h
289 | 8.132738 6.031940 m
290 | 8.659678 6.383118 9.346206 6.383118 9.873145 6.031940 c
291 | 10.705008 7.280141 l
292 | 9.674305 7.967051 8.331579 7.967051 7.300877 7.280141 c
293 | 8.132738 6.031940 l
294 | h
295 | 14.134700 10.031940 m
296 | 14.661639 10.383119 15.348167 10.383119 15.875108 10.031940 c
297 | 16.706968 11.280142 l
298 | 15.676266 11.967052 14.333540 11.967052 13.302837 11.280142 c
299 | 14.134700 10.031940 l
300 | h
301 | 3.871184 6.031940 m
302 | 5.161493 5.172014 6.842429 5.172014 8.132738 6.031940 c
303 | 7.300877 7.280141 l
304 | 6.514330 6.755948 5.489592 6.755948 4.703046 7.280141 c
305 | 3.871184 6.031940 l
306 | h
307 | 9.873145 10.031940 m
308 | 11.163454 9.172016 12.844391 9.172016 14.134700 10.031940 c
309 | 13.302837 11.280142 l
310 | 12.516292 10.755949 11.491553 10.755949 10.705008 11.280142 c
311 | 9.873145 10.031940 l
312 | h
313 | 2.130777 6.031940 m
314 | 2.657716 6.383119 3.344244 6.383118 3.871184 6.031940 c
315 | 4.703046 7.280141 l
316 | 3.672345 7.967051 2.329618 7.967052 1.298915 7.280142 c
317 | 2.130777 6.031940 l
318 | h
319 | 1.504577 5.614610 m
320 | 2.130777 6.031940 l
321 | 1.298915 7.280142 l
322 | 0.672715 6.862811 l
323 | 1.504577 5.614610 l
324 | h
325 | -0.451286 4.224396 m
326 | -0.256317 3.406483 0.074721 2.721144 0.641713 2.154339 c
327 | 1.702198 3.215176 l
328 | 1.376703 3.540564 1.155085 3.954472 1.007832 4.572212 c
329 | -0.451286 4.224396 l
330 | h
331 | 19.222300 6.546498 m
332 | 19.144999 4.681908 18.892281 3.802925 18.304338 3.215174 c
333 | 19.364824 2.154341 l
334 | 20.394405 3.183582 20.642962 4.601696 20.721012 6.484366 c
335 | 19.222300 6.546498 l
336 | h
337 | 20.749765 11.199771 m
338 | 20.731390 12.192454 20.664989 12.947197 20.345510 13.664302 c
339 | 18.975336 13.053874 l
340 | 19.162746 12.633213 19.232058 12.142510 19.250023 11.172009 c
341 | 20.749765 11.199771 l
342 | h
343 | 20.136660 10.031940 m
344 | 20.522711 10.289222 20.758514 10.727117 20.749765 11.199770 c
345 | 19.250023 11.172010 l
346 | 19.249142 11.219550 19.272644 11.258712 19.304802 11.280143 c
347 | 20.136660 10.031940 l
348 | h
349 | 0.672715 6.862811 m
350 | 0.434373 6.703969 0.199842 6.549189 0.016436 6.391880 c
351 | -0.186187 6.218088 -0.368468 6.007800 -0.483647 5.714796 c
352 | 0.912367 5.166029 l
353 | 0.914552 5.171587 0.916551 5.175688 0.922846 5.183876 c
354 | 0.930993 5.194475 0.950079 5.216505 0.992994 5.253313 c
355 | 1.091445 5.337755 1.236630 5.436037 1.504576 5.614610 c
356 | 0.672715 6.862811 l
357 | h
358 | 1.007832 4.572212 m
359 | 0.943789 4.840878 0.914517 4.970667 0.905153 5.068638 c
360 | 0.898916 5.133884 0.905281 5.148003 0.912367 5.166027 c
361 | -0.483646 5.714798 l
362 | -0.701090 5.161642 -0.555377 4.661068 -0.451286 4.224396 c
363 | 1.007832 4.572212 l
364 | h
365 | 20.136663 6.031941 m
366 | 19.739531 5.767271 19.202213 6.061961 19.222300 6.546498 c
367 | 20.721012 6.484366 l
368 | 20.752035 7.232711 19.921692 7.691271 19.304798 7.280141 c
369 | 20.136663 6.031941 l
370 | h
371 | -0.750000 11.573499 m
372 | -0.750000 11.434543 -0.751280 11.296141 -0.739264 11.188175 c
373 | 0.751532 11.354086 l
374 | 0.752536 11.345060 0.751351 11.350513 0.750671 11.393123 c
375 | 0.750023 11.433824 0.750000 11.488574 0.750000 11.573499 c
376 | -0.750000 11.573499 l
377 | h
378 | 1.298915 11.280141 m
379 | 1.228231 11.233034 1.182645 11.202681 1.148405 11.180640 c
380 | 1.112560 11.157568 1.107345 11.155518 1.115389 11.159676 c
381 | 1.804163 9.827162 l
382 | 1.900654 9.877038 2.015105 9.954851 2.130778 10.031941 c
383 | 1.298915 11.280141 l
384 | h
385 | -0.739264 11.188176 m
386 | -0.603460 9.967891 0.713858 9.263590 1.804160 9.827161 c
387 | 1.115391 11.159677 l
388 | 0.959110 11.078896 0.770898 11.180066 0.751532 11.354085 c
389 | -0.739264 11.188176 l
390 | h
391 | f
392 | n
393 | Q
394 |
395 | endstream
396 | endobj
397 |
398 | 3 0 obj
399 | 9806
400 | endobj
401 |
402 | 4 0 obj
403 | << /Annots []
404 | /Type /Page
405 | /MediaBox [ 0.000000 0.000000 24.000000 24.000000 ]
406 | /Resources 1 0 R
407 | /Contents 2 0 R
408 | /Parent 5 0 R
409 | >>
410 | endobj
411 |
412 | 5 0 obj
413 | << /Kids [ 4 0 R ]
414 | /Count 1
415 | /Type /Pages
416 | >>
417 | endobj
418 |
419 | 6 0 obj
420 | << /Pages 5 0 R
421 | /Type /Catalog
422 | >>
423 | endobj
424 |
425 | xref
426 | 0 7
427 | 0000000000 65535 f
428 | 0000000010 00000 n
429 | 0000000034 00000 n
430 | 0000009896 00000 n
431 | 0000009919 00000 n
432 | 0000010092 00000 n
433 | 0000010166 00000 n
434 | trailer
435 | << /ID [ (some) (id) ]
436 | /Root 6 0 R
437 | /Size 7
438 | >>
439 | startxref
440 | 10225
441 | %%EOF
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/fitness.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "fitness.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "filename" : "fitness@2x.png",
10 | "idiom" : "universal",
11 | "scale" : "2x"
12 | },
13 | {
14 | "filename" : "fitness@3x.png",
15 | "idiom" : "universal",
16 | "scale" : "3x"
17 | }
18 | ],
19 | "info" : {
20 | "author" : "xcode",
21 | "version" : 1
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/fitness.imageset/fitness.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/fitness.imageset/fitness.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/fitness.imageset/fitness@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/fitness.imageset/fitness@2x.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/fitness.imageset/fitness@3x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/fitness.imageset/fitness@3x.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/gift.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "gift.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/gift.imageset/gift.pdf:
--------------------------------------------------------------------------------
1 | %PDF-1.7
2 |
3 | 1 0 obj
4 | << >>
5 | endobj
6 |
7 | 2 0 obj
8 | << /Length 3 0 R >>
9 | stream
10 | /DeviceRGB CS
11 | /DeviceRGB cs
12 | q
13 | 1.000000 0.000000 -0.000000 1.000000 11.548218 3.000000 cm
14 | 0.827451 0.756863 0.988235 scn
15 | 0.800000 34.465820 m
16 | 40.102154 34.465820 l
17 | 40.102154 36.465820 l
18 | 0.800000 36.465820 l
19 | 0.800000 34.465820 l
20 | h
21 | 39.902157 34.665821 m
22 | 39.902157 2.800419 l
23 | 41.902157 2.800419 l
24 | 41.902157 34.665821 l
25 | 39.902157 34.665821 l
26 | h
27 | 40.102158 3.000420 m
28 | 0.800001 3.000420 l
29 | 0.800001 1.000420 l
30 | 40.102158 1.000420 l
31 | 40.102158 3.000420 l
32 | h
33 | 1.000000 2.800419 m
34 | 1.000000 34.665821 l
35 | -1.000000 34.665821 l
36 | -1.000000 2.800419 l
37 | 1.000000 2.800419 l
38 | h
39 | 0.800001 3.000420 m
40 | 0.910456 3.000420 1.000000 2.910877 1.000000 2.800419 c
41 | -1.000000 2.800419 l
42 | -1.000000 1.806305 -0.194109 1.000420 0.800001 1.000420 c
43 | 0.800001 3.000420 l
44 | h
45 | 39.902157 2.800419 m
46 | 39.902157 2.910877 39.991703 3.000420 40.102158 3.000420 c
47 | 40.102158 1.000420 l
48 | 41.096264 1.000420 41.902157 1.806301 41.902157 2.800419 c
49 | 39.902157 2.800419 l
50 | h
51 | 40.102154 34.465820 m
52 | 39.991699 34.465820 39.902157 34.555363 39.902157 34.665821 c
53 | 41.902157 34.665821 l
54 | 41.902157 35.659935 41.096264 36.465820 40.102154 36.465820 c
55 | 40.102154 34.465820 l
56 | h
57 | 0.800000 36.465820 m
58 | -0.194109 36.465820 -1.000000 35.659939 -1.000000 34.665821 c
59 | 1.000000 34.665821 l
60 | 1.000000 34.555363 0.910453 34.465820 0.800000 34.465820 c
61 | 0.800000 36.465820 l
62 | h
63 | f
64 | n
65 | Q
66 | q
67 | 1.000000 0.000000 -0.000000 1.000000 7.829956 36.465820 cm
68 | 0.827451 0.756863 0.988235 scn
69 | 0.800000 10.295898 m
70 | 47.538914 10.295898 l
71 | 47.538914 12.295898 l
72 | 0.800000 12.295898 l
73 | 0.800000 10.295898 l
74 | h
75 | 47.338913 10.495898 m
76 | 47.338913 2.799953 l
77 | 49.338913 2.799953 l
78 | 49.338913 10.495898 l
79 | 47.338913 10.495898 l
80 | h
81 | 47.538914 2.999954 m
82 | 0.800001 2.999954 l
83 | 0.800001 0.999954 l
84 | 47.538914 0.999954 l
85 | 47.538914 2.999954 l
86 | h
87 | 1.000000 2.799954 m
88 | 1.000000 10.495899 l
89 | -1.000000 10.495899 l
90 | -1.000000 2.799954 l
91 | 1.000000 2.799954 l
92 | h
93 | 0.800001 2.999954 m
94 | 0.910457 2.999954 1.000000 2.910412 1.000000 2.799954 c
95 | -1.000000 2.799954 l
96 | -1.000000 1.805840 -0.194111 0.999954 0.800001 0.999954 c
97 | 0.800001 2.999954 l
98 | h
99 | 47.338913 2.799953 m
100 | 47.338913 2.910412 47.428459 2.999954 47.538914 2.999954 c
101 | 47.538914 0.999954 l
102 | 48.533024 0.999954 49.338913 1.805839 49.338913 2.799953 c
103 | 47.338913 2.799953 l
104 | h
105 | 47.538914 10.295898 m
106 | 47.428455 10.295898 47.338913 10.385441 47.338913 10.495898 c
107 | 49.338913 10.495898 l
108 | 49.338913 11.490012 48.533024 12.295898 47.538914 12.295898 c
109 | 47.538914 10.295898 l
110 | h
111 | 0.800000 12.295898 m
112 | -0.194111 12.295898 -1.000000 11.490014 -1.000000 10.495899 c
113 | 1.000000 10.495899 l
114 | 1.000000 10.385441 0.910455 10.295898 0.800000 10.295898 c
115 | 0.800000 12.295898 l
116 | h
117 | f
118 | n
119 | Q
120 | q
121 | -0.000000 1.000000 -1.000000 -0.000000 72.113159 5.000002 cm
122 | 0.827451 0.756863 0.988235 scn
123 | 0.000000 44.761719 m
124 | 0.000000 45.761719 l
125 | -1.000000 45.761719 l
126 | -1.000000 44.761719 l
127 | 0.000000 44.761719 l
128 | h
129 | 42.761345 44.761719 m
130 | 43.761345 44.761719 l
131 | 43.761345 45.761719 l
132 | 42.761345 45.761719 l
133 | 42.761345 44.761719 l
134 | h
135 | 42.761345 35.465775 m
136 | 42.761345 34.465775 l
137 | 43.761345 34.465775 l
138 | 43.761345 35.465775 l
139 | 42.761345 35.465775 l
140 | h
141 | 0.000000 35.465775 m
142 | -1.000000 35.465775 l
143 | -1.000000 34.465775 l
144 | 0.000000 34.465775 l
145 | 0.000000 35.465775 l
146 | h
147 | 0.000000 43.761719 m
148 | 42.761345 43.761719 l
149 | 42.761345 45.761719 l
150 | 0.000000 45.761719 l
151 | 0.000000 43.761719 l
152 | h
153 | 41.761345 44.761719 m
154 | 41.761345 35.465775 l
155 | 43.761345 35.465775 l
156 | 43.761345 44.761719 l
157 | 41.761345 44.761719 l
158 | h
159 | 42.761345 36.465775 m
160 | 0.000000 36.465775 l
161 | 0.000000 34.465775 l
162 | 42.761345 34.465775 l
163 | 42.761345 36.465775 l
164 | h
165 | 1.000000 35.465775 m
166 | 1.000000 44.761719 l
167 | -1.000000 44.761719 l
168 | -1.000000 35.465775 l
169 | 1.000000 35.465775 l
170 | h
171 | f
172 | n
173 | Q
174 | q
175 | 0.707107 -0.707107 -0.707107 -0.707107 41.293781 62.373005 cm
176 | 0.827451 0.756863 0.988235 scn
177 | 4.647972 4.769764 m
178 | 4.647972 3.769764 l
179 | 4.647972 4.769764 l
180 | h
181 | 3.718378 16.854492 m
182 | 4.318378 17.654491 l
183 | 3.631667 18.169525 l
184 | 3.018528 17.568783 l
185 | 3.718378 16.854492 l
186 | h
187 | 6.436756 10.207891 m
188 | 6.436756 8.018752 6.091123 6.897692 5.729475 6.347184 c
189 | 5.427681 5.887786 5.080161 5.769764 4.647972 5.769764 c
190 | 4.647972 3.769764 l
191 | 5.610176 3.769764 6.657047 4.116540 7.401046 5.249072 c
192 | 8.085193 6.290494 8.436756 7.888498 8.436756 10.207891 c
193 | 6.436756 10.207891 l
194 | h
195 | 4.647972 5.769764 m
196 | 3.986962 5.769764 3.073215 6.188008 2.289848 7.039577 c
197 | 1.525780 7.870164 1.000000 8.996224 1.000000 10.207891 c
198 | -1.000000 10.207891 l
199 | -1.000000 8.416162 -0.228596 6.823160 0.817922 5.685533 c
200 | 1.845139 4.568886 3.255379 3.769764 4.647972 3.769764 c
201 | 4.647972 5.769764 l
202 | h
203 | 1.000000 10.207891 m
204 | 1.000000 11.366888 1.752103 12.802116 2.669673 14.071704 c
205 | 3.108615 14.679043 3.549703 15.200510 3.881659 15.570442 c
206 | 4.047126 15.754840 4.184189 15.900154 4.278595 15.998099 c
207 | 4.325767 16.047039 4.362194 16.084053 4.386085 16.108105 c
208 | 4.398027 16.120127 4.406828 16.128901 4.412262 16.134296 c
209 | 4.414979 16.136993 4.416854 16.138845 4.417858 16.139835 c
210 | 4.418359 16.140331 4.418643 16.140610 4.418706 16.140671 c
211 | 4.418738 16.140703 4.418714 16.140678 4.418634 16.140600 c
212 | 4.418594 16.140562 4.418493 16.140461 4.418473 16.140442 c
213 | 4.418357 16.140329 4.418228 16.140202 3.718378 16.854492 c
214 | 3.018528 17.568783 3.018370 17.568626 3.018198 17.568459 c
215 | 3.018121 17.568384 3.017935 17.568201 3.017782 17.568050 c
216 | 3.017476 17.567751 3.017113 17.567394 3.016695 17.566982 c
217 | 3.015857 17.566158 3.014793 17.565113 3.013508 17.563845 c
218 | 3.010937 17.561310 3.007478 17.557890 3.003160 17.553602 c
219 | 2.994523 17.545029 2.982444 17.532978 2.967152 17.517584 c
220 | 2.936575 17.486801 2.893115 17.442610 2.838612 17.386065 c
221 | 2.729670 17.273041 2.576234 17.110266 2.393104 16.906183 c
222 | 2.027864 16.499159 1.539357 15.922112 1.048705 15.243226 c
223 | 0.107086 13.940362 -1.000000 12.052290 -1.000000 10.207891 c
224 | 1.000000 10.207891 l
225 | h
226 | 3.718378 16.854492 m
227 | 3.118378 16.054493 3.118132 16.054676 3.117901 16.054850 c
228 | 3.117842 16.054893 3.117625 16.055058 3.117507 16.055145 c
229 | 3.117273 16.055323 3.117094 16.055456 3.116970 16.055550 c
230 | 3.116722 16.055738 3.116694 16.055759 3.116882 16.055616 c
231 | 3.117259 16.055330 3.118500 16.054388 3.120579 16.052794 c
232 | 3.124738 16.049604 3.132241 16.043816 3.142866 16.035480 c
233 | 3.164123 16.018803 3.197818 15.991974 3.242179 15.955416 c
234 | 3.330987 15.882228 3.462000 15.770494 3.621158 15.623604 c
235 | 3.940624 15.328764 4.367190 14.898074 4.792189 14.358856 c
236 | 5.655714 13.263259 6.436756 11.817486 6.436756 10.207891 c
237 | 8.436756 10.207891 l
238 | 8.436755 12.456114 7.358608 14.333641 6.362945 15.596890 c
239 | 5.858349 16.237095 5.355320 16.744715 4.977591 17.093328 c
240 | 4.788151 17.268166 4.628665 17.404446 4.514125 17.498838 c
241 | 4.456811 17.546070 4.410620 17.582924 4.377408 17.608982 c
242 | 4.360798 17.622013 4.347422 17.632355 4.337510 17.639956 c
243 | 4.332553 17.643755 4.328462 17.646872 4.325264 17.649296 c
244 | 4.323665 17.650509 4.322289 17.651548 4.321140 17.652414 c
245 | 4.320566 17.652847 4.320048 17.653236 4.319588 17.653584 c
246 | 4.319357 17.653757 4.319055 17.653984 4.318940 17.654070 c
247 | 4.318652 17.654287 4.318378 17.654491 3.718378 16.854492 c
248 | h
249 | f
250 | n
251 | Q
252 | q
253 | -0.707107 -0.707107 0.707107 -0.707107 22.720867 62.367146 cm
254 | 0.827451 0.756863 0.988235 scn
255 | 4.647972 4.769764 m
256 | 4.647972 3.769764 l
257 | 4.647972 4.769764 l
258 | h
259 | 3.718378 16.854492 m
260 | 4.318378 17.654491 l
261 | 3.631667 18.169525 l
262 | 3.018528 17.568783 l
263 | 3.718378 16.854492 l
264 | h
265 | 6.436756 10.207891 m
266 | 6.436756 8.018752 6.091123 6.897692 5.729475 6.347184 c
267 | 5.427681 5.887786 5.080161 5.769764 4.647972 5.769764 c
268 | 4.647972 3.769764 l
269 | 5.610176 3.769764 6.657047 4.116540 7.401046 5.249072 c
270 | 8.085193 6.290494 8.436756 7.888498 8.436756 10.207891 c
271 | 6.436756 10.207891 l
272 | h
273 | 4.647972 5.769764 m
274 | 3.986962 5.769764 3.073215 6.188008 2.289848 7.039577 c
275 | 1.525780 7.870164 1.000000 8.996224 1.000000 10.207891 c
276 | -1.000000 10.207891 l
277 | -1.000000 8.416162 -0.228596 6.823160 0.817922 5.685533 c
278 | 1.845139 4.568886 3.255379 3.769764 4.647972 3.769764 c
279 | 4.647972 5.769764 l
280 | h
281 | 1.000000 10.207891 m
282 | 1.000000 11.366888 1.752103 12.802116 2.669673 14.071704 c
283 | 3.108615 14.679043 3.549703 15.200510 3.881659 15.570442 c
284 | 4.047126 15.754840 4.184189 15.900154 4.278595 15.998099 c
285 | 4.325767 16.047039 4.362194 16.084053 4.386085 16.108105 c
286 | 4.398027 16.120127 4.406828 16.128901 4.412262 16.134296 c
287 | 4.414979 16.136993 4.416854 16.138845 4.417858 16.139835 c
288 | 4.418359 16.140331 4.418643 16.140610 4.418706 16.140671 c
289 | 4.418738 16.140703 4.418714 16.140678 4.418634 16.140600 c
290 | 4.418594 16.140562 4.418493 16.140461 4.418473 16.140442 c
291 | 4.418357 16.140329 4.418228 16.140202 3.718378 16.854492 c
292 | 3.018528 17.568783 3.018370 17.568626 3.018198 17.568459 c
293 | 3.018121 17.568384 3.017935 17.568201 3.017782 17.568050 c
294 | 3.017476 17.567751 3.017113 17.567394 3.016695 17.566982 c
295 | 3.015857 17.566158 3.014793 17.565113 3.013508 17.563845 c
296 | 3.010937 17.561310 3.007478 17.557890 3.003160 17.553602 c
297 | 2.994523 17.545029 2.982444 17.532978 2.967152 17.517584 c
298 | 2.936575 17.486801 2.893115 17.442610 2.838612 17.386065 c
299 | 2.729670 17.273041 2.576234 17.110266 2.393104 16.906183 c
300 | 2.027864 16.499159 1.539357 15.922112 1.048705 15.243226 c
301 | 0.107086 13.940362 -1.000000 12.052290 -1.000000 10.207891 c
302 | 1.000000 10.207891 l
303 | h
304 | 3.718378 16.854492 m
305 | 3.118378 16.054493 3.118132 16.054676 3.117901 16.054850 c
306 | 3.117842 16.054893 3.117625 16.055058 3.117507 16.055145 c
307 | 3.117273 16.055323 3.117094 16.055456 3.116970 16.055550 c
308 | 3.116722 16.055738 3.116694 16.055759 3.116882 16.055616 c
309 | 3.117259 16.055330 3.118500 16.054388 3.120579 16.052794 c
310 | 3.124738 16.049604 3.132241 16.043816 3.142866 16.035480 c
311 | 3.164123 16.018803 3.197818 15.991974 3.242179 15.955416 c
312 | 3.330987 15.882228 3.462000 15.770494 3.621158 15.623604 c
313 | 3.940624 15.328764 4.367190 14.898074 4.792189 14.358856 c
314 | 5.655714 13.263259 6.436756 11.817486 6.436756 10.207891 c
315 | 8.436756 10.207891 l
316 | 8.436755 12.456114 7.358608 14.333641 6.362945 15.596890 c
317 | 5.858349 16.237095 5.355320 16.744715 4.977591 17.093328 c
318 | 4.788151 17.268166 4.628665 17.404446 4.514125 17.498838 c
319 | 4.456811 17.546070 4.410620 17.582924 4.377408 17.608982 c
320 | 4.360798 17.622013 4.347422 17.632355 4.337510 17.639956 c
321 | 4.332553 17.643755 4.328462 17.646872 4.325264 17.649296 c
322 | 4.323665 17.650509 4.322289 17.651548 4.321140 17.652414 c
323 | 4.320566 17.652847 4.320048 17.653236 4.319588 17.653584 c
324 | 4.319357 17.653757 4.319055 17.653984 4.318940 17.654070 c
325 | 4.318652 17.654287 4.318378 17.654491 3.718378 16.854492 c
326 | h
327 | f
328 | n
329 | Q
330 |
331 | endstream
332 | endobj
333 |
334 | 3 0 obj
335 | 10142
336 | endobj
337 |
338 | 4 0 obj
339 | << /Annots []
340 | /Type /Page
341 | /MediaBox [ 0.000000 0.000000 64.000000 64.000000 ]
342 | /Resources 1 0 R
343 | /Contents 2 0 R
344 | /Parent 5 0 R
345 | >>
346 | endobj
347 |
348 | 5 0 obj
349 | << /Kids [ 4 0 R ]
350 | /Count 1
351 | /Type /Pages
352 | >>
353 | endobj
354 |
355 | 6 0 obj
356 | << /Pages 5 0 R
357 | /Type /Catalog
358 | >>
359 | endobj
360 |
361 | xref
362 | 0 7
363 | 0000000000 65535 f
364 | 0000000010 00000 n
365 | 0000000034 00000 n
366 | 0000010232 00000 n
367 | 0000010256 00000 n
368 | 0000010429 00000 n
369 | 0000010503 00000 n
370 | trailer
371 | << /ID [ (some) (id) ]
372 | /Root 6 0 R
373 | /Size 7
374 | >>
375 | startxref
376 | 10562
377 | %%EOF
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/gift2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "Gift.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/gift2.imageset/Gift.pdf:
--------------------------------------------------------------------------------
1 | %PDF-1.7
2 |
3 | 1 0 obj
4 | << >>
5 | endobj
6 |
7 | 2 0 obj
8 | << /Length 3 0 R >>
9 | stream
10 | /DeviceRGB CS
11 | /DeviceRGB cs
12 | q
13 | 1.000000 0.000000 -0.000000 1.000000 3.333313 21.250389 cm
14 | 1.000000 1.000000 1.000000 scn
15 | 15.416273 15.416275 m
16 | 8.385745 15.409420 4.748133 15.283645 2.440382 12.975893 c
17 | 0.132631 10.668142 0.006855 7.030530 0.000000 0.000002 c
18 | 8.189196 0.000002 l
19 | 7.604244 0.730662 7.167176 1.592505 6.928849 2.545813 c
20 | 6.031759 6.134171 9.282106 9.384516 12.870464 8.487427 c
21 | 13.823773 8.249100 14.685613 7.812031 15.416273 7.227080 c
22 | 15.416273 15.416275 l
23 | h
24 | f
25 | n
26 | Q
27 | q
28 | 1.000000 0.000000 -0.000000 1.000000 3.333313 21.250393 cm
29 | 1.000000 1.000000 1.000000 scn
30 | 0.000000 -2.500002 m
31 | 0.006855 -9.530529 0.132631 -13.168140 2.440382 -15.475893 c
32 | 4.748133 -17.783646 8.385745 -17.909420 15.416273 -17.916275 c
33 | 15.416273 -4.789415 l
34 | 14.116873 -7.384815 11.432992 -9.166670 8.332939 -9.166670 c
35 | 7.642582 -9.166670 7.082939 -8.607025 7.082939 -7.916670 c
36 | 7.082939 -7.226315 7.642582 -6.666670 8.332939 -6.666670 c
37 | 10.894257 -6.666670 13.040359 -4.888918 13.604664 -2.500002 c
38 | 0.000000 -2.500002 l
39 | h
40 | f
41 | n
42 | Q
43 | q
44 | 1.000000 0.000000 -0.000000 1.000000 3.333313 21.250393 cm
45 | 1.000000 1.000000 1.000000 scn
46 | 17.916273 -17.916275 m
47 | 24.946800 -17.909420 28.584412 -17.783646 30.892164 -15.475893 c
48 | 33.199917 -13.168140 33.325691 -9.530529 33.332546 -2.500002 c
49 | 19.727882 -2.500002 l
50 | 20.292185 -4.888918 22.438290 -6.666670 24.999607 -6.666670 c
51 | 25.689962 -6.666670 26.249607 -7.226315 26.249607 -7.916670 c
52 | 26.249607 -8.607025 25.689962 -9.166670 24.999607 -9.166670 c
53 | 21.899551 -9.166670 19.215673 -7.384815 17.916273 -4.789415 c
54 | 17.916273 -17.916275 l
55 | h
56 | f
57 | n
58 | Q
59 | q
60 | 1.000000 0.000000 -0.000000 1.000000 3.333313 21.250389 cm
61 | 1.000000 1.000000 1.000000 scn
62 | 33.332546 0.000002 m
63 | 33.325691 7.030530 33.199917 10.668142 30.892164 12.975893 c
64 | 28.584412 15.283645 24.946800 15.409420 17.916273 15.416275 c
65 | 17.916273 7.227080 l
66 | 18.646935 7.812031 19.508772 8.249100 20.462082 8.487427 c
67 | 24.050438 9.384516 27.300785 6.134171 26.403696 2.545813 c
68 | 26.165365 1.592505 25.728300 0.730662 25.143349 0.000002 c
69 | 33.332546 0.000002 l
70 | h
71 | f
72 | n
73 | Q
74 | q
75 | 1.000000 0.000000 -0.000000 1.000000 3.333313 30.165241 cm
76 | 1.000000 1.000000 1.000000 scn
77 | 12.264124 -2.852782 m
78 | 14.116663 -3.315917 15.416273 -4.980426 15.416273 -6.889980 c
79 | 15.416273 -8.914850 l
80 | 13.391403 -8.914850 l
81 | 11.481850 -8.914850 9.817340 -7.615240 9.354205 -5.762700 c
82 | 8.914853 -4.005294 10.506717 -2.413430 12.264124 -2.852782 c
83 | h
84 | f
85 | n
86 | Q
87 | q
88 | 1.000000 0.000000 -0.000000 1.000000 3.333313 30.165241 cm
89 | 1.000000 1.000000 1.000000 scn
90 | 17.916273 -6.889980 m
91 | 17.916273 -8.914850 l
92 | 19.941139 -8.914850 l
93 | 21.850695 -8.914850 23.515207 -7.615240 23.978340 -5.762700 c
94 | 24.417690 -4.005294 22.825827 -2.413430 21.068422 -2.852782 c
95 | 19.215879 -3.315917 17.916273 -4.980426 17.916273 -6.889980 c
96 | h
97 | f
98 | n
99 | Q
100 |
101 | endstream
102 | endobj
103 |
104 | 3 0 obj
105 | 2717
106 | endobj
107 |
108 | 4 0 obj
109 | << /Annots []
110 | /Type /Page
111 | /MediaBox [ 0.000000 0.000000 40.000000 40.000000 ]
112 | /Resources 1 0 R
113 | /Contents 2 0 R
114 | /Parent 5 0 R
115 | >>
116 | endobj
117 |
118 | 5 0 obj
119 | << /Kids [ 4 0 R ]
120 | /Count 1
121 | /Type /Pages
122 | >>
123 | endobj
124 |
125 | 6 0 obj
126 | << /Pages 5 0 R
127 | /Type /Catalog
128 | >>
129 | endobj
130 |
131 | xref
132 | 0 7
133 | 0000000000 65535 f
134 | 0000000010 00000 n
135 | 0000000034 00000 n
136 | 0000002807 00000 n
137 | 0000002830 00000 n
138 | 0000003003 00000 n
139 | 0000003077 00000 n
140 | trailer
141 | << /ID [ (some) (id) ]
142 | /Root 6 0 R
143 | /Size 7
144 | >>
145 | startxref
146 | 3136
147 | %%EOF
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/grapes.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "grapes (7).png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/grapes.imageset/grapes (7).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/grapes.imageset/grapes (7).png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/okay.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "okay-svg (1).png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/okay.imageset/okay-svg (1).png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/okay.imageset/okay-svg (1).png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/phone_call.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "phone_call.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/phone_call.imageset/phone_call.pdf:
--------------------------------------------------------------------------------
1 | %PDF-1.7
2 |
3 | 1 0 obj
4 | << >>
5 | endobj
6 |
7 | 2 0 obj
8 | << /Length 3 0 R >>
9 | stream
10 | /DeviceRGB CS
11 | /DeviceRGB cs
12 | q
13 | 1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
14 | 1.000000 0.270588 0.227451 scn
15 | 36.000000 18.000000 m
16 | 36.000000 8.058874 27.941126 0.000000 18.000000 0.000000 c
17 | 8.058874 0.000000 0.000000 8.058874 0.000000 18.000000 c
18 | 0.000000 27.941126 8.058874 36.000000 18.000000 36.000000 c
19 | 27.941126 36.000000 36.000000 27.941126 36.000000 18.000000 c
20 | h
21 | f
22 | n
23 | Q
24 | q
25 | 1.000000 0.000000 -0.000000 1.000000 8.000000 14.673157 cm
26 | 1.000000 1.000000 1.000000 scn
27 | 9.758739 7.326843 m
28 | 8.557892 7.326843 7.401317 7.238302 6.289012 7.061218 c
29 | 5.182241 6.889669 4.180614 6.624044 3.284130 6.264343 c
30 | 2.387645 5.904643 1.659943 5.445333 1.101024 4.886414 c
31 | 0.719188 4.504578 0.434195 4.081238 0.246044 3.616394 c
32 | 0.057893 3.157084 -0.022348 2.647970 0.005321 2.089050 c
33 | 0.021923 1.751485 0.080028 1.438822 0.179637 1.151062 c
34 | 0.284781 0.863302 0.436962 0.622579 0.636180 0.428894 c
35 | 0.785594 0.279480 0.957144 0.166036 1.150829 0.088562 c
36 | 1.350048 0.016622 1.568635 0.000021 1.806591 0.038757 c
37 | 4.886180 0.561707 l
38 | 5.339956 0.639181 5.671988 0.783061 5.882274 0.993347 c
39 | 6.020620 1.126160 6.114696 1.292175 6.164501 1.491394 c
40 | 6.214305 1.690613 6.239208 1.920268 6.239208 2.180359 c
41 | 6.239208 3.018738 l
42 | 6.239208 3.129415 6.286245 3.234558 6.380321 3.334167 c
43 | 6.419058 3.383972 6.466096 3.419942 6.521434 3.442078 c
44 | 6.582307 3.469747 6.634878 3.489115 6.679149 3.500183 c
45 | 6.961376 3.566589 7.373648 3.624695 7.915966 3.674500 c
46 | 8.463818 3.729838 9.078074 3.757507 9.758739 3.757507 c
47 | 10.439403 3.757507 11.050894 3.732605 11.593211 3.682800 c
48 | 12.135529 3.638530 12.550568 3.574890 12.838328 3.491882 c
49 | 12.882599 3.480815 12.929637 3.461446 12.979442 3.433777 c
50 | 13.034781 3.411641 13.084585 3.378438 13.128856 3.334167 c
51 | 13.211864 3.245626 13.256134 3.143250 13.261668 3.027039 c
52 | 13.269969 2.180359 l
53 | 13.275503 1.920268 13.303172 1.690613 13.352977 1.491394 c
54 | 13.402781 1.292175 13.494090 1.126160 13.626903 0.993347 c
55 | 13.732046 0.888204 13.867625 0.799662 14.033641 0.727722 c
56 | 14.199656 0.655782 14.398875 0.600443 14.631297 0.561707 c
57 | 17.669384 0.047058 l
58 | 17.912874 0.002787 18.136995 0.019389 18.341747 0.096863 c
59 | 18.552034 0.179871 18.737417 0.298849 18.897900 0.453796 c
60 | 19.296337 0.841166 19.503857 1.389018 19.520458 2.097351 c
61 | 19.531527 2.656271 19.434683 3.165385 19.229931 3.624695 c
62 | 19.030712 4.089539 18.742952 4.510112 18.366650 4.886414 c
63 | 17.807730 5.450867 17.082796 5.912943 16.191845 6.272644 c
64 | 15.300895 6.632345 14.304800 6.897970 13.203563 7.069519 c
65 | 12.102325 7.241068 10.954051 7.326843 9.758739 7.326843 c
66 | h
67 | f
68 | n
69 | Q
70 |
71 | endstream
72 | endobj
73 |
74 | 3 0 obj
75 | 2544
76 | endobj
77 |
78 | 4 0 obj
79 | << /Annots []
80 | /Type /Page
81 | /MediaBox [ 0.000000 0.000000 36.000000 36.000000 ]
82 | /Resources 1 0 R
83 | /Contents 2 0 R
84 | /Parent 5 0 R
85 | >>
86 | endobj
87 |
88 | 5 0 obj
89 | << /Kids [ 4 0 R ]
90 | /Count 1
91 | /Type /Pages
92 | >>
93 | endobj
94 |
95 | 6 0 obj
96 | << /Pages 5 0 R
97 | /Type /Catalog
98 | >>
99 | endobj
100 |
101 | xref
102 | 0 7
103 | 0000000000 65535 f
104 | 0000000010 00000 n
105 | 0000000034 00000 n
106 | 0000002634 00000 n
107 | 0000002657 00000 n
108 | 0000002830 00000 n
109 | 0000002904 00000 n
110 | trailer
111 | << /ID [ (some) (id) ]
112 | /Root 6 0 R
113 | /Size 7
114 | >>
115 | startxref
116 | 2963
117 | %%EOF
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/phone_call2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "phone_call2.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/phone_call2.imageset/phone_call2.pdf:
--------------------------------------------------------------------------------
1 | %PDF-1.7
2 |
3 | 1 0 obj
4 | << >>
5 | endobj
6 |
7 | 2 0 obj
8 | << /Length 3 0 R >>
9 | stream
10 | /DeviceRGB CS
11 | /DeviceRGB cs
12 | q
13 | 1.000000 0.000000 -0.000000 1.000000 0.000000 0.000000 cm
14 | 0.203922 0.780392 0.349020 scn
15 | 36.000000 18.000000 m
16 | 36.000000 8.058874 27.941126 0.000000 18.000000 0.000000 c
17 | 8.058874 0.000000 0.000000 8.058874 0.000000 18.000000 c
18 | 0.000000 27.941126 8.058874 36.000000 18.000000 36.000000 c
19 | 27.941126 36.000000 36.000000 27.941126 36.000000 18.000000 c
20 | h
21 | f
22 | n
23 | Q
24 | q
25 | 1.000000 0.000000 -0.000000 1.000000 10.000000 9.975708 cm
26 | 1.000000 1.000000 1.000000 scn
27 | 4.110033 4.142415 m
28 | 4.886732 3.365716 5.706580 2.664529 6.569579 2.038855 c
29 | 7.432578 1.413181 8.295577 0.916957 9.158576 0.550182 c
30 | 10.021575 0.183408 10.838727 0.000020 11.610032 0.000020 c
31 | 12.133225 0.000020 12.621359 0.094411 13.074433 0.283192 c
32 | 13.527508 0.471972 13.937432 0.768628 14.304207 1.173160 c
33 | 14.519957 1.410484 14.689859 1.666687 14.813916 1.941768 c
34 | 14.937972 2.211454 15.000000 2.483839 15.000000 2.758920 c
35 | 15.000000 2.963882 14.959547 3.158057 14.878641 3.341444 c
36 | 14.797734 3.530225 14.660194 3.692038 14.466020 3.826881 c
37 | 11.982201 5.590635 l
38 | 11.793420 5.720085 11.618123 5.817172 11.456310 5.881897 c
39 | 11.294498 5.946622 11.140777 5.978985 10.995146 5.978985 c
40 | 10.811758 5.978985 10.633765 5.927744 10.461165 5.825263 c
41 | 10.288566 5.728175 10.110572 5.587938 9.927184 5.404551 c
42 | 9.352751 4.838208 l
43 | 9.271845 4.751908 9.169364 4.708758 9.045307 4.708758 c
44 | 8.980582 4.708758 8.918554 4.719545 8.859223 4.741120 c
45 | 8.805285 4.762695 8.759439 4.781573 8.721683 4.797754 c
46 | 8.468177 4.932598 8.144552 5.164529 7.750809 5.493547 c
47 | 7.357066 5.827960 6.960626 6.194735 6.561489 6.593871 c
48 | 6.167746 6.993009 5.803668 7.389448 5.469256 7.783192 c
49 | 5.134844 8.176935 4.902913 8.497863 4.773463 8.745975 c
50 | 4.751888 8.789125 4.730313 8.837668 4.708738 8.891605 c
51 | 4.692557 8.950937 4.684466 9.010268 4.684466 9.069599 c
52 | 4.684466 9.188262 4.724919 9.288046 4.805825 9.368952 c
53 | 5.380259 9.959567 l
54 | 5.558252 10.142954 5.698490 10.320948 5.800971 10.493547 c
55 | 5.903452 10.666147 5.954692 10.844141 5.954692 11.027529 c
56 | 5.954692 11.173160 5.919633 11.326881 5.849514 11.488693 c
57 | 5.784790 11.650505 5.685005 11.825802 5.550162 12.014584 c
58 | 3.810680 14.466040 l
59 | 3.670442 14.660214 3.503236 14.800451 3.309062 14.886751 c
60 | 3.114887 14.978445 2.909925 15.024292 2.694175 15.024292 c
61 | 2.138619 15.024292 1.618123 14.789664 1.132686 14.320409 c
62 | 0.738943 13.942846 0.450378 13.524832 0.266990 13.066363 c
63 | 0.088997 12.613289 0.000000 12.127851 0.000000 11.610052 c
64 | 0.000000 10.833353 0.180690 10.016201 0.542071 9.158596 c
65 | 0.903452 8.306385 1.394283 7.451477 2.014563 6.593871 c
66 | 2.634844 5.736266 3.333333 4.919114 4.110033 4.142415 c
67 | h
68 | f
69 | n
70 | Q
71 |
72 | endstream
73 | endobj
74 |
75 | 3 0 obj
76 | 2610
77 | endobj
78 |
79 | 4 0 obj
80 | << /Annots []
81 | /Type /Page
82 | /MediaBox [ 0.000000 0.000000 36.000000 36.000000 ]
83 | /Resources 1 0 R
84 | /Contents 2 0 R
85 | /Parent 5 0 R
86 | >>
87 | endobj
88 |
89 | 5 0 obj
90 | << /Kids [ 4 0 R ]
91 | /Count 1
92 | /Type /Pages
93 | >>
94 | endobj
95 |
96 | 6 0 obj
97 | << /Pages 5 0 R
98 | /Type /Catalog
99 | >>
100 | endobj
101 |
102 | xref
103 | 0 7
104 | 0000000000 65535 f
105 | 0000000010 00000 n
106 | 0000000034 00000 n
107 | 0000002700 00000 n
108 | 0000002723 00000 n
109 | 0000002896 00000 n
110 | 0000002970 00000 n
111 | trailer
112 | << /ID [ (some) (id) ]
113 | /Root 6 0 R
114 | /Size 7
115 | >>
116 | startxref
117 | 3029
118 | %%EOF
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/shop_NA.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "shop_NA.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/shop_NA.imageset/shop_NA.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/shop_NA.imageset/shop_NA.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/shop_coffee.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "shop_coffee.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/shop_coffee.imageset/shop_coffee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/shop_coffee.imageset/shop_coffee.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/transaction_coffee.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "transaction_coffee.png",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/transaction_coffee.imageset/transaction_coffee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Assets.xcassets/transaction_coffee.imageset/transaction_coffee.png
--------------------------------------------------------------------------------
/PopupExample/Assets.xcassets/winner.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "filename" : "winner.pdf",
5 | "idiom" : "universal",
6 | "scale" : "1x"
7 | },
8 | {
9 | "idiom" : "universal",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "scale" : "3x"
15 | }
16 | ],
17 | "info" : {
18 | "author" : "xcode",
19 | "version" : 1
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/PopupExample/Font/NunitoSans_7pt-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Font/NunitoSans_7pt-Bold.ttf
--------------------------------------------------------------------------------
/PopupExample/Font/NunitoSans_7pt-Light.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Font/NunitoSans_7pt-Light.ttf
--------------------------------------------------------------------------------
/PopupExample/Font/NunitoSans_7pt-Medium.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Font/NunitoSans_7pt-Medium.ttf
--------------------------------------------------------------------------------
/PopupExample/Font/NunitoSans_7pt-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/exyte/PopupView/676d4609495f144b48a583af40b936eedfb49f3e/PopupExample/Font/NunitoSans_7pt-Regular.ttf
--------------------------------------------------------------------------------
/PopupExample/PopupExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "pins" : [
3 | {
4 | "identity" : "swiftui-introspect",
5 | "kind" : "remoteSourceControl",
6 | "location" : "https://github.com/siteline/swiftui-introspect",
7 | "state" : {
8 | "revision" : "807f73ce09a9b9723f12385e592b4e0aaebd3336",
9 | "version" : "1.3.0"
10 | }
11 | }
12 | ],
13 | "version" : 2
14 | }
15 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample.xcodeproj/xcshareddata/xcschemes/PopupExample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
29 |
35 |
36 |
37 |
38 |
39 |
45 |
46 |
56 |
58 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/Components/Images.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImageViews.swift
3 | // Example
4 | //
5 | // Created by Alex.M on 19.05.2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | private struct AlertImageView : View where Content : View {
11 | let hex: String
12 | let alignment: Alignment
13 |
14 | @ViewBuilder let content: (Color) -> Content
15 |
16 | var body: some View {
17 | let color = Color(hex: hex)
18 | return ZStack(alignment: alignment) {
19 | Rectangle()
20 | .fill(color)
21 | .opacity(0.24)
22 | .frame(width: 40, height: 40)
23 | content(color)
24 | }
25 | .cornerRadius(10)
26 | }
27 | }
28 |
29 | struct SmallFloatsImage: View {
30 | let alignment: Alignment
31 |
32 | var body: some View {
33 | AlertImageView(hex: "9265F8", alignment: alignment) { color in
34 | Rectangle()
35 | .fill(color)
36 | .frame(width: 24, height: 4)
37 | .cornerRadius(12)
38 | .padding(.all, 8)
39 | }
40 | }
41 | }
42 |
43 | struct BigFloatsImage: View {
44 | let alignment: Alignment
45 |
46 | var body: some View {
47 | AlertImageView(hex: "9265F8", alignment: alignment) { color in
48 | Rectangle()
49 | .fill(color)
50 | .frame(width: 12, height: 4)
51 | .cornerRadius(12)
52 | .padding(.all, 8)
53 | }
54 | }
55 | }
56 |
57 | struct ToastImage: View {
58 | let position: Position
59 |
60 | var body: some View {
61 | AlertImageView(hex: "87B9FF", alignment: position.toAligment()) { color in
62 | RoundedRectangle(cornerRadius: 4)
63 | .fill(color)
64 | .frame(width: 40, height: 24)
65 | .padding(
66 | EdgeInsets(
67 | top: position == .top ? -16 : 0,
68 | leading: 0,
69 | bottom: position == .bottom ? -16 : 0,
70 | trailing: 0
71 | )
72 | )
73 | }
74 | }
75 |
76 | enum Position {
77 | case top, bottom
78 |
79 | func toAligment() -> Alignment {
80 | switch self {
81 | case .top:
82 | return .top
83 | case .bottom:
84 | return .bottom
85 | }
86 | }
87 | }
88 | }
89 |
90 | struct PopupImage: View {
91 | let style: Style
92 |
93 | var body: some View {
94 | AlertImageView(hex: "CCE7A2", alignment: style.toAligment()) { color in
95 | switch style {
96 | case .default:
97 | RoundedRectangle(cornerRadius: 4)
98 | .fill(color)
99 | .frame(width: 24, height: 20)
100 |
101 | case .bottomFirst:
102 | RoundedRectangle(cornerRadius: 4)
103 | .fill(color)
104 | .frame(width: 24, height: 20)
105 | .padding(.bottom, 4)
106 |
107 | case .bottomSecond:
108 | RoundedRectangle(cornerRadius: 4)
109 | .fill(color)
110 | .frame(width: 40, height: 20)
111 | .padding(0)
112 | }
113 | }
114 | }
115 |
116 | enum Style {
117 | case `default`
118 | case bottomFirst
119 | case bottomSecond
120 |
121 | func toAligment() -> Alignment {
122 | switch self {
123 | case .default:
124 | return .center
125 | case .bottomFirst, .bottomSecond:
126 | return .bottom
127 | }
128 | }
129 | }
130 | }
131 |
132 | struct ActionSheetImage: View {
133 | var body: some View {
134 | AlertImageView(hex: "FFB93D", alignment: .bottom) { color in
135 | RoundedRectangle(cornerRadius: 4)
136 | .fill(color)
137 | .frame(width: 40, height: 20)
138 | .padding(0)
139 | }
140 | }
141 | }
142 |
143 | struct InputSheetImage: View {
144 | var body: some View {
145 | AlertImageView(hex: "B03A31", alignment: .bottom) { color in
146 | RoundedRectangle(cornerRadius: 4)
147 | .fill(color)
148 | .frame(width: 24, height: 20)
149 | .padding(.bottom, 4)
150 | }
151 | }
152 | }
153 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/Components/PopupButton.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PopupButton.swift
3 | // Example
4 | //
5 | // Created by Alex.M on 19.05.2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct PopupButton : View where Content : View {
11 | @Binding var isShowing: Bool
12 |
13 | var hideAll: () -> ()
14 |
15 | @ViewBuilder let content: () -> Content
16 |
17 | var body: some View {
18 | Button {
19 | hideAll()
20 | isShowing.toggle()
21 | } label: {
22 | content()
23 | }
24 | .customButtonStyle(foreground: .black, background: .clear)
25 | }
26 | }
27 |
28 | struct ItemPopupButton : View where Content : View {
29 | @Binding var item: SomeItem?
30 |
31 | let text = "In two weeks, you did 12 workouts and burned 2671 calories. That's 566 calories more than last month. Continue at the same pace and the result will please you."
32 |
33 | var hideAll: () -> ()
34 |
35 | @ViewBuilder let content: () -> Content
36 |
37 | var body: some View {
38 | Button {
39 | hideAll()
40 | item = SomeItem(value: text)
41 | } label: {
42 | content()
43 | }
44 | .customButtonStyle(foreground: .black, background: .clear)
45 | }
46 | }
47 |
48 | class SomeItem: Equatable {
49 |
50 | let value: String
51 |
52 | init(value: String) {
53 | self.value = value
54 | }
55 |
56 | static func == (lhs: SomeItem, rhs: SomeItem) -> Bool {
57 | lhs.value == rhs.value
58 | }
59 | }
60 |
61 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // Example
4 | //
5 | // Created by Alisa Mylnikova on 23/04/2020.
6 | // Copyright © 2020 Exyte. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 | import PopupView
11 |
12 | struct ContentView : View {
13 | @State var floatsSmall = FloatsStateSmall()
14 | @State var floatsBig = FloatsStateBig()
15 | @State var toasts = ToastsState()
16 | @State var popups = PopupsState()
17 | @State var actionSheets = ActionSheetsState()
18 | @State var inputSheets = InputSheetsState()
19 |
20 | var body: some View {
21 | createPopupsList()
22 |
23 | // MARK: - Designed floats big screen
24 |
25 | .popup(isPresented: $floatsBig.showingTopLeading) {
26 | FloatTopLeading()
27 | } customize: {
28 | $0
29 | .type(.floater())
30 | .position(.topLeading)
31 | .animation(.spring())
32 | }
33 |
34 | .popup(isPresented: $floatsBig.showingTop) {
35 | FloatTop()
36 | } customize: {
37 | $0
38 | .type(.floater())
39 | .position(.top)
40 | .animation(.spring())
41 | }
42 |
43 | .popup(isPresented: $floatsBig.showingTopTrailing) {
44 | FloatTopTrailing()
45 | } customize: {
46 | $0
47 | .type(.floater())
48 | .position(.topTrailing)
49 | .animation(.spring())
50 | }
51 |
52 | .popup(isPresented: $floatsBig.showingLeading) {
53 | FloatLeading()
54 | } customize: {
55 | $0
56 | .type(.floater())
57 | .position(.leading)
58 | .animation(.spring())
59 | }
60 |
61 | .popup(isPresented: $floatsBig.showingTrailing) {
62 | FloatTrailing()
63 | } customize: {
64 | $0
65 | .type(.floater())
66 | .position(.trailing)
67 | .animation(.spring())
68 | }
69 |
70 | .popup(isPresented: $floatsBig.showingBottomLeading) {
71 | FloatBottomLeading()
72 | } customize: {
73 | $0
74 | .type(.floater())
75 | .position(.bottomLeading)
76 | .appearFrom(.bottomSlide)
77 | .animation(.spring())
78 | }
79 |
80 | .popup(isPresented: $floatsBig.showingBottom) {
81 | FloatBottom()
82 | } customize: {
83 | $0
84 | .type(.floater())
85 | .position(.bottom)
86 | .animation(.spring())
87 | }
88 |
89 | .popup(isPresented: $floatsBig.showingBottomTrailing) {
90 | FloatBottomTrailing()
91 | } customize: {
92 | $0
93 | .type(.floater())
94 | .position(.bottomTrailing)
95 | .animation(.spring())
96 | }
97 |
98 | // MARK: - Designed floats small screen
99 |
100 | .popup(isPresented: $floatsSmall.showingTopFirst) {
101 | FloatTopFirst()
102 | } customize: {
103 | $0
104 | .type(.floater())
105 | .position(.top)
106 | .displayMode(.window)
107 | .animation(.spring())
108 | .closeOnTapOutside(true)
109 | .autohideIn(3)
110 | .dismissCallback {
111 | print("did", $0)
112 | }
113 | .willDismissCallback {
114 | print("will", $0)
115 | }
116 | }
117 |
118 | .popup(isPresented: $floatsSmall.showingTopSecond) {
119 | FloatTopSecond()
120 | } customize: {
121 | $0
122 | .type(.floater())
123 | .position(.top)
124 | .animation(.spring())
125 | }
126 |
127 | .popup(isPresented: $floatsSmall.showingBottomFirst) {
128 | FloatBottomFirst()
129 | } customize: {
130 | $0
131 | .type(.floater())
132 | .position(.bottom)
133 | .animation(.spring())
134 | }
135 |
136 | .popup(isPresented: $floatsSmall.showingBottomSecond) {
137 | FloatBottomSecond()
138 | } customize: {
139 | $0
140 | .type(.floater())
141 | .position(.bottom)
142 | .animation(.spring())
143 | }
144 |
145 | // MARK: - Designed toasts
146 |
147 | .popup(isPresented: $toasts.showingTopFirst) {
148 | ToastTopFirst()
149 | } customize: {
150 | $0
151 | .type(.toast)
152 | .position(.top)
153 | }
154 |
155 | .popup(isPresented: $toasts.showingTopSecond) {
156 | ToastTopSecond()
157 | } customize: {
158 | $0
159 | .type(.toast)
160 | .position(.top)
161 | }
162 |
163 | .popup(isPresented: $toasts.showingBottomFirst) {
164 | ToastBottomFirst(isShowing: $toasts.showingBottomFirst)
165 | } customize: {
166 | $0
167 | .type(.toast)
168 | .position(.bottom)
169 | .closeOnTap(false)
170 | .backgroundColor(.black.opacity(0.4))
171 | }
172 |
173 | .popup(isPresented: $toasts.showingBottomSecond) {
174 | ToastBottomSecond()
175 | } customize: {
176 | $0
177 | .type(.toast)
178 | .position(.bottom)
179 | .autohideIn(10)
180 | }
181 |
182 | // MARK: - Designed popups
183 |
184 | .popup(item: $popups.middleItem) { item in
185 | PopupMiddle(item: item)
186 | } customize: {
187 | $0
188 | .appearFrom(.centerScale)
189 | .closeOnTap(false)
190 | .backgroundColor(.black.opacity(0.4))
191 | }
192 |
193 | .popup(isPresented: $popups.showingBottomFirst) {
194 | PopupBottomFirst(isPresented: $popups.showingBottomFirst)
195 | } customize: {
196 | $0
197 | .type(.floater())
198 | .disappearTo(.centerScale)
199 | .position(.bottom)
200 | .closeOnTap(false)
201 | .backgroundColor(.black.opacity(0.4))
202 | }
203 |
204 | .popup(isPresented: $popups.showingBottomSecond) {
205 | PopupBottomSecond()
206 | } customize: {
207 | $0
208 | .type(.floater(verticalPadding: 0, useSafeAreaInset: false))
209 | .position(.bottom)
210 | .closeOnTap(true)
211 | .closeOnTapOutside(true)
212 | .backgroundColor(.black.opacity(0.4))
213 | }
214 |
215 | #if os(iOS)
216 | // MARK: - Designed action sheets
217 | .popup(isPresented: $actionSheets.showingFirst) {
218 | ActionSheetFirst()
219 | } customize: {
220 | $0
221 | .type(.toast)
222 | .position(.bottom)
223 | .closeOnTap(false)
224 | .backgroundColor(.black.opacity(0.4))
225 | }
226 | .popup(isPresented: $actionSheets.showingSecond) {
227 | ActionSheetSecond()
228 | } customize: {
229 | $0
230 | .type(.scroll(headerView: AnyView(scrollViewHeader())))
231 | .position(.bottom)
232 | .closeOnTap(false)
233 | .closeOnTapOutside(true)
234 | .backgroundColor(.black.opacity(0.4))
235 | }
236 |
237 | #endif
238 |
239 | .popup(isPresented: $inputSheets.showingFirst) {
240 | InputSheetBottom(isShowing: $inputSheets.showingFirst)
241 | } customize: {
242 | $0
243 | .position(.bottom)
244 | .closeOnTap(false)
245 | .backgroundColor(.black.opacity(0.4))
246 | .useKeyboardSafeArea(true)
247 | }
248 | }
249 |
250 | func createPopupsList() -> PopupsList {
251 | PopupsList(
252 | floatsBig: $floatsBig,
253 | floatsSmall: $floatsSmall,
254 | toasts: $toasts,
255 | popups: $popups,
256 | actionSheets: $actionSheets,
257 | inputSheets: $inputSheets,
258 | hideAll: {
259 | floatsBig = FloatsStateBig()
260 | floatsSmall = FloatsStateSmall()
261 | toasts = ToastsState()
262 | popups = PopupsState()
263 | actionSheets = ActionSheetsState()
264 | inputSheets = InputSheetsState()
265 | }
266 | )
267 | }
268 |
269 | #if os(iOS)
270 | func scrollViewHeader() -> some View {
271 | ZStack {
272 | Color(.white).cornerRadius(40, corners: [.topLeft, .topRight])
273 |
274 | Color.black
275 | .opacity(0.2)
276 | .frame(width: 30, height: 6)
277 | .clipShape(Capsule())
278 | .padding(.vertical, 20)
279 | }
280 | }
281 | #endif
282 | }
283 |
284 | struct ContentView_Previews: PreviewProvider {
285 | static var previews: some View {
286 | ContentView()
287 | }
288 | }
289 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/Examples/ActionSheets.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ActionSheets.swift
3 | // Example
4 | //
5 | // Created by Alex.M on 20.05.2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | #if os(iOS)
11 | struct ActionSheetView: View {
12 |
13 | let content: Content
14 | let topPadding: CGFloat
15 | let fixedHeight: Bool
16 | let bgColor: Color
17 |
18 | init(topPadding: CGFloat = 100, fixedHeight: Bool = false, bgColor: Color = .white, @ViewBuilder content: () -> Content) {
19 | self.content = content()
20 | self.topPadding = topPadding
21 | self.fixedHeight = fixedHeight
22 | self.bgColor = bgColor
23 | }
24 |
25 | var body: some View {
26 | ZStack {
27 | bgColor.cornerRadius(40, corners: [.topLeft, .topRight])
28 | VStack {
29 | Color.black
30 | .opacity(0.2)
31 | .frame(width: 30, height: 6)
32 | .clipShape(Capsule())
33 | .padding(.top, 15)
34 | .padding(.bottom, 10)
35 |
36 | content
37 | .padding(.bottom, 30)
38 | .applyIf(fixedHeight) {
39 | $0.frame(height: UIScreen.main.bounds.height - topPadding)
40 | }
41 | .applyIf(!fixedHeight) {
42 | $0.frame(maxHeight: UIScreen.main.bounds.height - topPadding)
43 | }
44 | }
45 | }
46 | .fixedSize(horizontal: false, vertical: true)
47 | }
48 | }
49 |
50 | private struct ActivityView: View {
51 | let emoji: String
52 | let name: String
53 | let isSelected: Bool
54 |
55 | var body: some View {
56 | HStack(spacing: 12) {
57 | Text(emoji)
58 | .font(.system(size: 24))
59 |
60 | Text(name.uppercased())
61 | .font(.system(size: 13, weight: isSelected ? .regular : .light))
62 |
63 | Spacer()
64 |
65 | if isSelected {
66 | Image(systemName: "checkmark")
67 | .foregroundColor(Color(hex: "9265F8"))
68 | }
69 | }
70 | .opacity(isSelected ? 1.0 : 0.8)
71 | }
72 | }
73 |
74 | struct ActionSheetFirst: View {
75 | var body: some View {
76 | ActionSheetView(bgColor: .white) {
77 | ScrollView {
78 | VStack(alignment: .leading, spacing: 24) {
79 | ActivityView(emoji: "🤼♂️", name: "Sparring", isSelected: true)
80 | ActivityView(emoji: "🧘", name: "Yoga", isSelected: false)
81 | ActivityView(emoji: "🚴", name: "cycling", isSelected: false)
82 | ActivityView(emoji: "🏊", name: "Swimming", isSelected: false)
83 | ActivityView(emoji: "🏄", name: "Surfing", isSelected: false)
84 | ActivityView(emoji: "🤸", name: "Fitness", isSelected: false)
85 | ActivityView(emoji: "⛹️", name: "Basketball", isSelected: true)
86 | ActivityView(emoji: "🏋️", name: "Lifting Weights", isSelected: false)
87 | ActivityView(emoji: "⚽️", name: "Football", isSelected: false)
88 | }
89 | .padding(.horizontal, 20)
90 | }
91 | }
92 | }
93 | }
94 |
95 | struct ActionSheetSecond: View {
96 |
97 | var body: some View {
98 | VStack(alignment: .leading, spacing: 16) {
99 | Text("Privacy Policy")
100 | .font(.system(size: 24))
101 |
102 | Text(Constants.privacyPolicy)
103 | .font(.system(size: 14))
104 | .opacity(0.6)
105 | }
106 | .padding(.horizontal, 24)
107 | .padding(.vertical, 16)
108 | .background(.white)
109 | }
110 | }
111 |
112 | struct ActionSheets_Previews: PreviewProvider {
113 | static var previews: some View {
114 | ZStack {
115 | Rectangle()
116 | .ignoresSafeArea()
117 | ActionSheetFirst()
118 | }
119 |
120 | ZStack {
121 | Rectangle()
122 | .ignoresSafeArea()
123 | ActionSheetSecond()
124 | }
125 | }
126 | }
127 |
128 | #endif
129 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/Examples/FloatsBig.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FloatsBig.swift
3 | // PopupExample
4 | //
5 | // Created by Alisa Mylnikova on 09.06.2023.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct FloatTopLeading: View {
11 |
12 | var body: some View {
13 | ZStack {
14 | RoundedRectangle(cornerRadius: 12)
15 | .fill(Color("dark"))
16 |
17 | HStack(alignment: .top, spacing: 16) {
18 | Picture("avatar6", 48)
19 |
20 | VStack(alignment: .leading, spacing: 2) {
21 | WhiteBoldText("You are on Do Not Distrub")
22 | WhiteText("Do you want to update your status?", 13)
23 | .opacity(0.6)
24 |
25 | HStack(spacing: 18) {
26 | WhiteBoldText("Turn on")
27 | .padding(16, 5)
28 | .background(RoundedRectangle(cornerRadius: 8)
29 | .foregroundColor(Color("darkBlue")))
30 | WhiteText("Stay off", 16)
31 | .opacity(0.6)
32 | }
33 | .padding(.top, 14)
34 | }
35 |
36 | Spacer()
37 |
38 | Picture("cross", 10)
39 | }
40 | .padding(16)
41 | }
42 | .fixedSize()
43 | }
44 | }
45 |
46 | struct FloatTop: View {
47 |
48 | var body: some View {
49 | ZStack {
50 | RoundedRectangle(cornerRadius: 12)
51 | .fill(Color("semidark"))
52 |
53 | HStack(spacing: 16) {
54 | Picture("avatar5", 48)
55 |
56 | VStack(alignment: .leading, spacing: 2) {
57 | WhiteMediumText("Kate Middleton", 17)
58 | WhiteText("incoming call", 13)
59 | .opacity(0.6)
60 | }
61 | .padding(.trailing, 60)
62 |
63 | HStack(spacing: 14) {
64 | Picture("phone_call", 36)
65 | Picture("phone_call2", 36)
66 | }
67 | }
68 | .padding(14)
69 | }
70 | .fixedSize()
71 | }
72 | }
73 |
74 | struct FloatTopTrailing: View {
75 |
76 | var body: some View {
77 | ZStack {
78 | RoundedRectangle(cornerRadius: 10)
79 | .fill(Color("light"))
80 |
81 | HStack(spacing: 7) {
82 | Circle()
83 | .foregroundColor(Color("darkBlue"))
84 | .frame(width: 10, height: 10)
85 |
86 | Picture("avatar4", 45)
87 |
88 | VStack(alignment: .leading, spacing: 2) {
89 | HStack {
90 | BlackBoldText("@edsheeran", 16)
91 | BlackText ("followed you", 16)
92 | .opacity(0.4)
93 | .padding(.trailing, 15)
94 | DarkText("8:02 am", 13)
95 | .opacity(0.6)
96 | }
97 | .padding(.trailing, 8)
98 | .fixedSize()
99 | DarkText("I know it's a bad idea. But how can I help\nmyself?", 13)
100 | .opacity(0.6)
101 | }
102 | }
103 | .padding(8)
104 | }
105 | .fixedSize()
106 | }
107 | }
108 |
109 | struct FloatLeading: View {
110 |
111 | var body: some View {
112 | ZStack {
113 | RoundedRectangle(cornerRadius: 12)
114 | .fill(Color("purple"))
115 | .overlay(alignment: .topTrailing) {
116 | Picture("cross", 10)
117 | .padding(13)
118 | }
119 |
120 | VStack(alignment: .leading, spacing: 8) {
121 | Picture("gift2", 33)
122 | .padding(.bottom, 20)
123 |
124 | WhiteBoldText("We give you a gift!")
125 | WhiteText("30% discount until the end of the month on all products of the company.", 13)
126 | .opacity(0.8)
127 | }
128 | .padding(16)
129 | }
130 | .frame(width: 195)
131 | .fixedSize()
132 | }
133 | }
134 |
135 | struct FloatTrailing: View {
136 |
137 | var body: some View {
138 | ZStack {
139 | RoundedRectangle(cornerRadius: 12)
140 | .fill(Color("semilight"))
141 |
142 | HStack {
143 | Picture("check_circle", 27)
144 | BlackText("New file created with success", 15)
145 | }
146 | .padding(20, 15)
147 | }
148 | .fixedSize()
149 | }
150 | }
151 |
152 | struct FloatBottomLeading: View {
153 |
154 | var body: some View {
155 | HStack(spacing: 8) {
156 | Image(systemName: "wifi.slash")
157 | .foregroundColor(.white)
158 | .frame(width: 21, height: 21)
159 | WhiteText("Check your network connection and try again", 15)
160 | }
161 | .padding(32, 22)
162 | .background(Color("yellow").cornerRadius(12))
163 | }
164 | }
165 |
166 | struct FloatBottom: View {
167 |
168 | var body: some View {
169 | ZStack {
170 | Capsule()
171 | .fill(.black)
172 |
173 | HStack(spacing: 25) {
174 | Picture("file", 20)
175 | VStack(spacing: 2) {
176 | WhiteBoldText("Ooops! Download failed")
177 | WhiteText("The download was unable to complete. Please try again later.", 16)
178 | .opacity(0.6)
179 | }
180 | Text("Retry")
181 | .font(.custom(boldFont, size: 21))
182 | .foregroundColor(Color("lightBlue"))
183 | }
184 | .padding(26, 20)
185 | }
186 | .fixedSize()
187 | }
188 | }
189 |
190 | struct FloatBottomTrailing: View {
191 |
192 | var body: some View {
193 | ZStack {
194 | RoundedRectangle(cornerRadius: 10)
195 | .fill(Color.white)
196 |
197 | HStack(spacing: 0) {
198 | BlackText("Your message has been sent to Alex Brant", 15)
199 | .padding(20)
200 | Picture("avatar2", 32)
201 | .padding(.trailing, 7)
202 | }
203 | }
204 | .shadowedStyle()
205 | .fixedSize()
206 | }
207 | }
208 |
209 | struct Picture: View {
210 | let name: String
211 | let size: CGFloat
212 |
213 | init(_ name: String, _ size: CGFloat) {
214 | self.name = name
215 | self.size = size
216 | }
217 |
218 | var body: some View {
219 | Image(name)
220 | .aspectRatio(1.0, contentMode: .fit)
221 | .frame(width: size)
222 | }
223 | }
224 |
225 | let boldFont = "NunitoSans7pt-Bold"
226 | let mediumFont = "NunitoSans7pt-Medium"
227 | let lightFont = "NunitoSans7pt-Light"
228 | let regularFont = "NunitoSans7pt-Regular"
229 |
230 | struct WhiteBoldText: View {
231 | let text: String
232 | let size: CGFloat
233 |
234 | init(_ text: String, _ size: CGFloat = 16) {
235 | self.text = text
236 | self.size = size
237 | }
238 |
239 | var body: some View {
240 | Text(text)
241 | .font(.custom(boldFont, size: size))
242 | .foregroundColor(.white)
243 | .bold()
244 | }
245 | }
246 |
247 | struct WhiteMediumText: View {
248 | let text: String
249 | let size: CGFloat
250 |
251 | init(_ text: String, _ size: CGFloat) {
252 | self.text = text
253 | self.size = size
254 | }
255 |
256 | var body: some View {
257 | Text(text)
258 | .font(.custom(mediumFont, size: size))
259 | .foregroundColor(.white)
260 | }
261 | }
262 |
263 | struct WhiteText: View {
264 | let text: String
265 | let size: CGFloat
266 |
267 | init(_ text: String, _ size: CGFloat) {
268 | self.text = text
269 | self.size = size
270 | }
271 |
272 | var body: some View {
273 | Text(text)
274 | .font(.custom(regularFont, size: size))
275 | .foregroundColor(.white)
276 | }
277 | }
278 |
279 | struct BlackBoldText: View {
280 | let text: String
281 | let size: CGFloat
282 |
283 | init(_ text: String, _ size: CGFloat) {
284 | self.text = text
285 | self.size = size
286 | }
287 |
288 | var body: some View {
289 | Text(text)
290 | .font(.custom(boldFont, size: size))
291 | .foregroundColor(.black)
292 | .bold()
293 | }
294 | }
295 |
296 | struct BlackMediumText: View {
297 | let text: String
298 | let size: CGFloat
299 |
300 | init(_ text: String, _ size: CGFloat) {
301 | self.text = text
302 | self.size = size
303 | }
304 |
305 | var body: some View {
306 | Text(text)
307 | .font(.custom(mediumFont, size: size))
308 | .foregroundColor(.white)
309 | }
310 | }
311 |
312 | struct BlackText: View {
313 | let text: String
314 | let size: CGFloat
315 |
316 | init(_ text: String, _ size: CGFloat) {
317 | self.text = text
318 | self.size = size
319 | }
320 |
321 | var body: some View {
322 | Text(text)
323 | .font(.custom(regularFont, size: size))
324 | .foregroundColor(.black)
325 | }
326 | }
327 |
328 | struct DarkText: View {
329 | let text: String
330 | let size: CGFloat
331 |
332 | init(_ text: String, _ size: CGFloat) {
333 | self.text = text
334 | self.size = size
335 | }
336 |
337 | var body: some View {
338 | Text(text)
339 | .font(.custom(regularFont, size: size))
340 | .foregroundColor(Color("darkText"))
341 | }
342 | }
343 |
344 | extension View {
345 | func padding(_ horizontal: CGFloat, _ vertical: CGFloat) -> some View {
346 | self.padding(.horizontal, horizontal)
347 | .padding(.vertical, vertical)
348 | }
349 | }
350 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/Examples/FloatsSmall.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Floats.swift
3 | // Example
4 | //
5 | // Created by Alex.M on 19.05.2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct FloatTopFirst: View {
11 |
12 | @Environment(\.popupDismiss) var dismiss
13 |
14 | var body: some View {
15 | ZStack {
16 | RoundedRectangle(cornerRadius: 12)
17 | .fill(Color(hex: "E0E3E8"))
18 |
19 | HStack(spacing: 0) {
20 | Image("avatar1")
21 | .aspectRatio(1.0, contentMode: .fit)
22 | .cornerRadius(16)
23 | .padding(16.0)
24 |
25 | VStack(alignment: .leading, spacing: 8) {
26 | Group {
27 | Text("Adam Jameson")
28 | .bold()
29 | .foregroundColor(.black) +
30 | Text(" invites you to join his training")
31 | .foregroundColor(.black.opacity(0.6))
32 | }
33 |
34 | Button {
35 | debugPrint("Accepted!")
36 | dismiss?()
37 | } label: {
38 | Text("Accept".uppercased())
39 | .font(.system(size: 14, weight: .black))
40 | }
41 | .customButtonStyle(foreground: Color(hex: "9265F8"), background: .clear)
42 | }
43 |
44 | Spacer()
45 | }
46 | }
47 | .frame(height: 98)
48 | .padding(.horizontal, 16)
49 | }
50 | }
51 |
52 | struct FloatTopSecond: View {
53 | var body: some View {
54 | HStack(spacing: 0) {
55 | VStack(alignment: .leading, spacing: 2) {
56 | Text("We give you a gift!")
57 | .foregroundColor(.white)
58 | .font(.system(size: 18))
59 |
60 | Text("30% discount until the end of the month on all products of the company.")
61 | .foregroundColor(.white)
62 | .font(.system(size: 16))
63 | .opacity(0.8)
64 | }
65 |
66 | Spacer()
67 |
68 | Image("gift")
69 | .aspectRatio(1.0, contentMode: .fit)
70 | }
71 | .padding(16)
72 | .background(Color(hex: "9265F8").cornerRadius(12))
73 | .shadow(color: Color(hex: "9265F8").opacity(0.5), radius: 40, x: 0, y: 12)
74 | .padding(.horizontal, 16)
75 | }
76 | }
77 |
78 | struct FloatBottomFirst: View {
79 | var body: some View {
80 | HStack(spacing: 0) {
81 | Text("Your message has been sent to Alex Brant")
82 | .font(.system(size: 15))
83 | .foregroundColor(.black)
84 | Spacer()
85 | Image("avatar2")
86 | .frame(width: 32, height: 32)
87 | .cornerRadius(16)
88 | }
89 | .padding(16)
90 | .background(Color.white.cornerRadius(12))
91 | .shadowedStyle()
92 | .padding(.horizontal, 16)
93 | }
94 | }
95 |
96 | struct FloatBottomSecond: View {
97 | var body: some View {
98 | HStack(spacing: 8) {
99 | Image(systemName: "wifi.slash")
100 | .foregroundColor(.white)
101 | .frame(width: 24, height: 24)
102 |
103 | Text("Check your network connection and try again")
104 | .foregroundColor(.white)
105 | .font(.system(size: 16))
106 | }
107 | .padding(16)
108 | .background(Color(hex: "FFB93D").cornerRadius(12))
109 | .padding(.horizontal, 16)
110 | }
111 | }
112 |
113 | struct Floats_Previews: PreviewProvider {
114 | static var previews: some View {
115 | ZStack {
116 | Rectangle()
117 | .ignoresSafeArea()
118 | VStack {
119 | FloatTopFirst()
120 | FloatTopSecond()
121 | FloatBottomFirst()
122 | FloatBottomSecond()
123 | }
124 | }
125 | }
126 | }
127 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/Examples/InputSheets.swift:
--------------------------------------------------------------------------------
1 | //
2 | // InputSheets.swift
3 | // PopupExample
4 | //
5 | // Created by Alex.M on 28.09.2023.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct InputSheetBottom: View {
11 | @Binding var isShowing: Bool
12 |
13 | @State var nickname: String = ""
14 |
15 | var body: some View {
16 | VStack(spacing: 0) {
17 | Text("Nickname")
18 | .foregroundColor(.black)
19 | .font(.system(size: 20, weight: .bold))
20 | .kerning(0.38)
21 |
22 | Text("Usernames can only use letters, numbers, ., - and _ ")
23 | .font(.system(size: 14))
24 | .foregroundColor(Color(red: 1, green: 0.23, blue: 0.19))
25 | .frame(maxWidth: .infinity, alignment: .leading)
26 | .padding(12)
27 | .background {
28 | RoundedRectangle(cornerRadius: 10)
29 | .fill(Color(red: 0.98, green: 0.92, blue: 0.92))
30 | }
31 | .padding(.top, 16)
32 |
33 | TextField("Nickname", text: $nickname)
34 | .padding()
35 | .frame(height: 44)
36 | .background {
37 | RoundedRectangle(cornerRadius: 12)
38 | .stroke(Color(red: 1, green: 0.23, blue: 0.19), lineWidth: 0.5)
39 | }
40 | .padding(.top, 6)
41 |
42 | Button {
43 | isShowing = false
44 | } label: {
45 | Text("Save changes")
46 | .buttonStyle(.plain)
47 | .font(.system(size: 17))
48 | .frame(maxWidth: .infinity)
49 | .frame(height: 44)
50 | .background {
51 | RoundedRectangle(cornerRadius: 12)
52 | .fill(Color(red: 0.29, green: 0.38, blue: 1))
53 | }
54 | }
55 | .buttonStyle(.plain)
56 | .foregroundColor(.white)
57 | .padding(.top, 12)
58 | }
59 | .padding(16)
60 | .background(Color.white.cornerRadius(18))
61 | .shadowedStyle()
62 | .padding(.horizontal, 8)
63 | .padding(.bottom, 30)
64 | }
65 | }
66 |
67 | #Preview {
68 | InputSheetBottom(isShowing: .constant(true))
69 | }
70 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/Examples/Popups.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Popups.swift
3 | // Example
4 | //
5 | // Created by Alex.M on 20.05.2022.
6 | //
7 |
8 | import SwiftUI
9 | import PopupView
10 |
11 | struct PopupMiddle: View {
12 |
13 | @Environment(\.popupDismiss) var dismiss
14 | let item: SomeItem
15 |
16 | var body: some View {
17 | VStack(spacing: 12) {
18 | Image("winner")
19 | .resizable()
20 | .scaledToFit()
21 | .frame(maxWidth: 226, maxHeight: 226)
22 |
23 | Text("Congratulations!")
24 | .foregroundColor(.black)
25 | .font(.system(size: 24))
26 | .padding(.top, 12)
27 |
28 | Text(item.value)
29 | .foregroundColor(.black)
30 | .font(.system(size: 16))
31 | .opacity(0.6)
32 | .multilineTextAlignment(.center)
33 | .padding(.bottom, 20)
34 |
35 | Button {
36 | dismiss?()
37 | } label: {
38 | Text("Thanks")
39 | .font(.system(size: 18, weight: .bold))
40 | .frame(maxWidth: .infinity)
41 | .padding(.vertical, 18)
42 | .padding(.horizontal, 24)
43 | .foregroundColor(.white)
44 | .background(Color(hex: "9265F8"))
45 | .cornerRadius(12)
46 | }
47 | .buttonStyle(.plain)
48 | }
49 | .padding(EdgeInsets(top: 37, leading: 24, bottom: 40, trailing: 24))
50 | .background(Color.white.cornerRadius(20))
51 | .shadowedStyle()
52 | .padding(.horizontal, 40)
53 | }
54 | }
55 |
56 | struct PopupBottomFirst: View {
57 |
58 | @Binding var isPresented: Bool
59 |
60 | var body: some View {
61 | VStack(spacing: 12) {
62 | Text("Policy changes")
63 | .foregroundColor(.black)
64 | .font(.system(size: 24))
65 |
66 | Text("Policy change occurs through interactions between wide external changes or shocks to the political system and the success of the ideas in the coalitions, which may cause actors in the advocacy coalition to shift coalitions.")
67 | .foregroundColor(.black)
68 | .font(.system(size: 16))
69 | .opacity(0.6)
70 | .multilineTextAlignment(.center)
71 | .padding(.bottom, 12)
72 |
73 | Button {
74 | isPresented = false
75 | } label: {
76 | Text("Ok, I accept")
77 | .font(.system(size: 18, weight: .bold))
78 | .frame(maxWidth: .infinity)
79 | .padding(.vertical, 18)
80 | .foregroundColor(.white)
81 | .background(Color(hex: "FFB93D"))
82 | .cornerRadius(12)
83 | }
84 | .buttonStyle(.plain)
85 | }
86 | .padding(EdgeInsets(top: 37, leading: 24, bottom: 40, trailing: 24))
87 | .background(Color.white.cornerRadius(20))
88 | .shadowedStyle()
89 | .padding(.horizontal, 16)
90 | }
91 | }
92 |
93 | struct PopupBottomSecond: View {
94 |
95 | var body: some View {
96 | VStack(spacing: 12) {
97 | Image("chest")
98 | .resizable()
99 | .scaledToFit()
100 | .frame(maxWidth: 156, maxHeight: 156)
101 |
102 | Text("Personal offer")
103 | .foregroundColor(.black)
104 | .font(.system(size: 24))
105 | .padding(.top, 4)
106 |
107 | Text("Say hello to flexible funding – you're pre-screened for an exclusive personal loan offer through TD Bank. Enter your Personal Offer Code to get started.")
108 | .foregroundColor(.black)
109 | .font(.system(size: 16))
110 | .opacity(0.6)
111 | .multilineTextAlignment(.center)
112 | .padding(.bottom, 12)
113 |
114 | Text("Read More")
115 | .font(.system(size: 18, weight: .bold))
116 | .frame(maxWidth: .infinity)
117 | .padding(.vertical, 18)
118 | .background(
119 | LinearGradient(
120 | gradient: Gradient(colors: [Color(hex: "3DDCFF"), Color(hex: "CD3DFF")]),
121 | startPoint: .top,
122 | endPoint: .bottom))
123 | .cornerRadius(12)
124 | .foregroundColor(.white)
125 | .padding(.horizontal, 64)
126 | }
127 | .padding(EdgeInsets(top: 37, leading: 24, bottom: 40, trailing: 24))
128 | .background(Color.white.cornerRadius(20))
129 | .shadowedStyle()
130 | }
131 | }
132 |
133 |
134 | struct Popups_Previews: PreviewProvider {
135 | static var previews: some View {
136 | ZStack {
137 | Rectangle()
138 | .ignoresSafeArea()
139 | PopupMiddle(item: SomeItem(value: "item"))
140 | }
141 |
142 | ZStack {
143 | Rectangle()
144 | .ignoresSafeArea()
145 | PopupBottomFirst(isPresented: .constant(false))
146 | }
147 |
148 | ZStack {
149 | Rectangle()
150 | .ignoresSafeArea()
151 | PopupBottomSecond()
152 | }
153 | }
154 | }
155 |
156 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/Examples/Toasts.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Toasts.swift
3 | // Example
4 | //
5 | // Created by Alex.M on 19.05.2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct ToastTopFirst: View {
11 | var body: some View {
12 | Text("Unable to add to bag as this item is currently not available.")
13 | .foregroundColor(.white)
14 | .padding(EdgeInsets(top: 60, leading: 32, bottom: 16, trailing: 32))
15 | .frame(maxWidth: .infinity)
16 | .background(Color(hex: "FE504E"))
17 | }
18 | }
19 |
20 | struct ToastTopSecond: View {
21 | var body: some View {
22 | HStack {
23 | Image("avatar3")
24 | .frame(width: 48, height: 48)
25 | .cornerRadius(24)
26 |
27 | VStack(alignment: .leading) {
28 | HStack {
29 | Text("Camila Morrone")
30 | .font(.system(size: 15))
31 |
32 | Spacer()
33 |
34 | Text("now")
35 | .font(.system(size: 13))
36 | .opacity(0.6)
37 | }
38 |
39 | Text("Let's go have a cup of coffee! ☕️")
40 | .font(.system(size: 15, weight: .light))
41 | }
42 | }
43 | .foregroundColor(.white)
44 | .padding(EdgeInsets(top: 56, leading: 16, bottom: 16, trailing: 16))
45 | .frame(maxWidth: .infinity)
46 | .background(Color(hex: "87B9FF"))
47 | }
48 | }
49 |
50 | struct ToastBottomFirst: View {
51 | @Binding var isShowing: Bool
52 |
53 | var body: some View {
54 | HStack(alignment: .top, spacing: 16) {
55 | Image("fitness")
56 | .frame(width: 48, height: 48)
57 | .cornerRadius(8)
58 |
59 | VStack(alignment: .leading, spacing: 8) {
60 | Text("Log In to Fitness First")
61 | .font(.system(size: 16, weight: .bold))
62 | Text("To continue training, you need to Log in or Sign up")
63 | .font(.system(size: 16))
64 | .opacity(0.8)
65 | }
66 |
67 | Spacer()
68 |
69 | VStack(alignment: .leading, spacing: 4) {
70 | Button {
71 | self.isShowing = false
72 | } label: {
73 | Text("Log in")
74 | .frame(width: 112, height: 40)
75 | }
76 | .customButtonStyle(foreground: .white, background: Color(hex: "87B9FF"))
77 | .cornerRadius(8)
78 |
79 | Button {
80 | self.isShowing = false
81 | } label: {
82 | Text("Sign up")
83 | .frame(width: 112, height: 40)
84 | }
85 | .customButtonStyle()
86 | }
87 | }
88 | .foregroundColor(.black)
89 | .padding(EdgeInsets(top: 24, leading: 16, bottom: 42, trailing: 16))
90 | .frame(maxWidth: .infinity)
91 | .background(Color.white)
92 | }
93 | }
94 |
95 | struct ToastBottomSecond: View {
96 | var body: some View {
97 | HStack(alignment: .top, spacing: 16) {
98 | Image("checkmark")
99 | .frame(width: 48, height: 48)
100 | .cornerRadius(24)
101 |
102 | VStack(alignment: .leading, spacing: 4) {
103 | Text("Subscription completed!")
104 | .font(.system(size: 16, weight: .bold))
105 | Text("The next charge to your credit card will be made on May 25, 2022.")
106 | .font(.system(size: 16, weight: .light))
107 | .opacity(0.8)
108 | }
109 |
110 | Spacer()
111 | }
112 | .foregroundColor(.black)
113 | .padding(EdgeInsets(top: 24, leading: 16, bottom: 42, trailing: 16))
114 | .frame(maxWidth: .infinity)
115 | .background(Color.white)
116 | .shadow(color: .black.opacity(0.1), radius: 40, x: 0, y: -4)
117 | }
118 | }
119 |
120 | struct Toasts_Previews: PreviewProvider {
121 | static var previews: some View {
122 | ZStack {
123 | Rectangle()
124 | .ignoresSafeArea()
125 | VStack {
126 | ToastTopFirst()
127 | ToastTopSecond()
128 | ToastBottomFirst(isShowing: Binding.init(get: { true }, set: { _ in }))
129 | ToastBottomSecond()
130 | }
131 | }
132 | .previewDevice("iPhone 13 Pro Max")
133 | }
134 | }
135 |
136 |
137 |
138 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIAppFonts
6 |
7 | NunitoSans_7pt-Medium.ttf
8 | NunitoSans_7pt-Light.ttf
9 | NunitoSans_7pt-Regular.ttf
10 | NunitoSans_7pt-Bold.ttf
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/PopupExample.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | com.apple.security.app-sandbox
6 |
7 | com.apple.security.files.user-selected.read-only
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/PopupExampleApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PopupExampleApp.swift
3 | // PopupExample
4 | //
5 | // Created by Alisa Mylnikova on 04.05.2023.
6 | //
7 |
8 | import SwiftUI
9 | import PopupView
10 |
11 | @main
12 | struct PopupExampleApp: App {
13 | var body: some Scene {
14 | WindowGroup {
15 | ContentView()
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/PopupsList.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PopupsList.swift
3 | // Example
4 | //
5 | // Created by Alex.M on 19.05.2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | struct FloatsStateBig {
11 | var showingTopLeading = false
12 | var showingTop = false
13 | var showingTopTrailing = false
14 |
15 | var showingLeading = false
16 | // center is a regular popup
17 | var showingTrailing = false
18 |
19 | var showingBottomLeading = false
20 | var showingBottom = false
21 | var showingBottomTrailing = false
22 | }
23 |
24 | struct FloatsStateSmall {
25 | var showingTopFirst = false
26 | var showingTopSecond = false
27 | var showingBottomFirst = false
28 | var showingBottomSecond = false
29 | }
30 |
31 | struct ToastsState {
32 | var showingTopFirst = false
33 | var showingTopSecond = false
34 | var showingBottomFirst = false
35 | var showingBottomSecond = false
36 | }
37 |
38 | struct PopupsState {
39 | var middleItem: SomeItem?
40 | var showingBottomFirst = false
41 | var showingBottomSecond = false
42 | }
43 |
44 | struct ActionSheetsState {
45 | var showingFirst = false
46 | var showingSecond = false
47 | }
48 |
49 | struct InputSheetsState {
50 | var showingFirst = false
51 | }
52 |
53 | private struct SectionHeader: View {
54 | let name: String
55 | let count: Int
56 |
57 | var body: some View {
58 | HStack {
59 | Text(name)
60 | .font(.system(size: 24, weight: .bold))
61 | .foregroundColor(.black)
62 |
63 | Spacer()
64 |
65 | HStack(spacing: 4) {
66 | Text("\(count)")
67 | .font(.system(size: 18))
68 | .foregroundColor(.black)
69 | .opacity(0.8)
70 |
71 | Text("types")
72 | .font(.system(size: 18))
73 | .foregroundColor(.black)
74 | .opacity(0.5)
75 | }
76 | }
77 | .padding(.horizontal, 20)
78 | }
79 | }
80 |
81 | private struct PopupTypeView : View where Content : View {
82 | let title: String
83 | var detail: String = ""
84 | @ViewBuilder let icon: () -> Content
85 |
86 | var body: some View {
87 | ZStack(alignment: .leading) {
88 | RoundedRectangle(cornerRadius: 12)
89 | .fill(.white)
90 |
91 | HStack {
92 | icon()
93 | VStack(alignment: .leading, spacing: 0) {
94 | Text(title)
95 | .font(.system(size: 18))
96 | .foregroundColor(.black)
97 | Text(detail)
98 | .font(.system(size: 13))
99 | .foregroundColor(.black)
100 | .opacity(0.4)
101 | }
102 | }
103 | .padding()
104 | }
105 | .padding(.horizontal, 20)
106 | }
107 | }
108 |
109 | struct PopupsList: View {
110 | @Binding var floatsBig: FloatsStateBig
111 | @Binding var floatsSmall: FloatsStateSmall
112 | @Binding var toasts: ToastsState
113 | @Binding var popups: PopupsState
114 | @Binding var actionSheets: ActionSheetsState
115 | @Binding var inputSheets: InputSheetsState
116 |
117 | let hideAll: () -> ()
118 |
119 | var body: some View {
120 | ZStack {
121 | Rectangle()
122 | .fill(Color(hex: "F7F7F9"))
123 | .ignoresSafeArea()
124 |
125 | ScrollView {
126 | VStack(spacing: 12) {
127 | safeSpaceForMac()
128 |
129 | Group {
130 | SectionHeader(name: "Floats", count: 4)
131 | .padding(.bottom, 12)
132 |
133 | floatsSection()
134 | }
135 |
136 | Group {
137 | SectionHeader(name: "Toasts", count: 4)
138 | .padding(EdgeInsets(top: 20, leading: 0, bottom: 12, trailing: 0))
139 |
140 | toastsSection()
141 | }
142 |
143 | Group {
144 | SectionHeader(name: "Popups", count: 3)
145 | .padding(EdgeInsets(top: 20, leading: 0, bottom: 12, trailing: 0))
146 |
147 | popupsSection()
148 | }
149 |
150 | #if os(iOS)
151 | Group {
152 | SectionHeader(name: "Action sheets", count: 2)
153 | .padding(EdgeInsets(top: 20, leading: 0, bottom: 12, trailing: 0))
154 |
155 | actionSheetsSection()
156 | }
157 | #endif
158 |
159 | Group {
160 | SectionHeader(name: "Inputs", count: 1)
161 | .padding(.bottom, 12)
162 |
163 | inputsSection()
164 | }
165 |
166 | safeSpaceForMac()
167 | }
168 | }
169 | .padding(.top, 1)
170 | }
171 | }
172 |
173 | func safeSpaceForMac() -> some View {
174 | #if os(macOS)
175 | Color.clear.padding(.bottom, 40)
176 | #else
177 | EmptyView()
178 | #endif
179 | }
180 |
181 | @MainActor @ViewBuilder
182 | func floatsSection() -> some View {
183 | #if os(iOS)
184 | if UIDevice.current.userInterfaceIdiom == .phone {
185 | floatsSectionSmall()
186 | } else {
187 | floatsSectionBig()
188 | }
189 | #else
190 | floatsSectionBig()
191 | #endif
192 | }
193 |
194 | @ViewBuilder
195 | func floatsSectionSmall() -> some View {
196 | Button("Show multiple popups") {
197 | popups.showingBottomFirst = true
198 | toasts.showingBottomSecond = true
199 | floatsSmall.showingBottomFirst = true
200 | floatsSmall.showingTopSecond = true
201 | toasts.showingTopSecond = true
202 | }
203 | PopupButton(isShowing: $floatsSmall.showingTopFirst, hideAll: hideAll) {
204 | PopupTypeView(
205 | title: "Top version 1",
206 | detail: "Top float with a picture and one button"
207 | ) {
208 | SmallFloatsImage(alignment: .top)
209 | }
210 | }
211 | PopupButton(isShowing: $floatsSmall.showingTopSecond, hideAll: hideAll) {
212 | PopupTypeView(
213 | title: "Top version 2",
214 | detail: "Top float with a picture"
215 | ) {
216 | SmallFloatsImage(alignment: .top)
217 | }
218 | }
219 | PopupButton(isShowing: $floatsSmall.showingBottomFirst, hideAll: hideAll) {
220 | PopupTypeView(
221 | title: "Bottom version 1",
222 | detail: "Bottom float with a picture"
223 | ) {
224 | SmallFloatsImage(alignment: .bottom)
225 | }
226 | }
227 | PopupButton(isShowing: $floatsSmall.showingBottomSecond, hideAll: hideAll) {
228 | PopupTypeView(
229 | title: "Bottom version 2",
230 | detail: "Bottom float with a picture"
231 | ) {
232 | SmallFloatsImage(alignment: .bottom)
233 | }
234 | }
235 | }
236 |
237 | @ViewBuilder
238 | func floatsSectionBig() -> some View {
239 | PopupButton(isShowing: $floatsBig.showingTopLeading, hideAll: hideAll) {
240 | PopupTypeView(title: "Top Leading") {
241 | BigFloatsImage(alignment: .topLeading)
242 | }
243 | }
244 | PopupButton(isShowing: $floatsBig.showingTop, hideAll: hideAll) {
245 | PopupTypeView(title: "Top Center") {
246 | BigFloatsImage(alignment: .top)
247 | }
248 | }
249 | PopupButton(isShowing: $floatsBig.showingTopTrailing, hideAll: hideAll) {
250 | PopupTypeView(title: "Top Trailing") {
251 | BigFloatsImage(alignment: .topTrailing)
252 | }
253 | }
254 |
255 | PopupButton(isShowing: $floatsBig.showingLeading, hideAll: hideAll) {
256 | PopupTypeView(title: "Center Leading") {
257 | BigFloatsImage(alignment: .leading)
258 | }
259 | }
260 | PopupButton(isShowing: $floatsBig.showingTrailing, hideAll: hideAll) {
261 | PopupTypeView(title: "Center Trailing") {
262 | BigFloatsImage(alignment: .trailing)
263 | }
264 | }
265 |
266 | PopupButton(isShowing: $floatsBig.showingBottomLeading, hideAll: hideAll) {
267 | PopupTypeView(title: "Bottom Leading") {
268 | BigFloatsImage(alignment: .bottomLeading)
269 | }
270 | }
271 | PopupButton(isShowing: $floatsBig.showingBottom, hideAll: hideAll) {
272 | PopupTypeView(title: "Bottom Center") {
273 | BigFloatsImage(alignment: .bottom)
274 | }
275 | }
276 | PopupButton(isShowing: $floatsBig.showingBottomTrailing, hideAll: hideAll) {
277 | PopupTypeView(title: "Bottom Trailing") {
278 | BigFloatsImage(alignment: .bottomTrailing)
279 | }
280 | }
281 | }
282 |
283 | @ViewBuilder
284 | func toastsSection() -> some View {
285 | PopupButton(isShowing: $toasts.showingTopFirst, hideAll: hideAll) {
286 | PopupTypeView(
287 | title: "Top version 1",
288 | detail: "Top toast only text"
289 | ) {
290 | ToastImage(position: .top)
291 | }
292 | }
293 | PopupButton(isShowing: $toasts.showingTopSecond, hideAll: hideAll) {
294 | PopupTypeView(
295 | title: "Top version 2",
296 | detail: "Top float with picture"
297 | ) {
298 | ToastImage(position: .top)
299 | }
300 | }
301 | PopupButton(isShowing: $toasts.showingBottomFirst, hideAll: hideAll) {
302 | PopupTypeView(
303 | title: "Bottom version 1",
304 | detail: "Bottom float with a picture and two buttons"
305 | ) {
306 | ToastImage(position: .bottom)
307 | }
308 | }
309 | PopupButton(isShowing: $toasts.showingBottomSecond, hideAll: hideAll) {
310 | PopupTypeView(
311 | title: "Bottom version 2",
312 | detail: "Bottom float with a picture"
313 | ) {
314 | ToastImage(position: .bottom)
315 | }
316 | }
317 | }
318 |
319 | @ViewBuilder
320 | func popupsSection() -> some View {
321 | ItemPopupButton(item: $popups.middleItem, hideAll: hideAll) {
322 | PopupTypeView(
323 | title: "Middle",
324 | detail: "Popup in the middle of the screen with a picture"
325 | ) {
326 | PopupImage(style: .default)
327 | }
328 | }
329 | PopupButton(isShowing: $popups.showingBottomFirst, hideAll: hideAll) {
330 | PopupTypeView(
331 | title: "Bottom version 1",
332 | detail: "Popup bottom"
333 | ) {
334 | PopupImage(style: .bottomFirst)
335 | }
336 | }
337 | PopupButton(isShowing: $popups.showingBottomSecond, hideAll: hideAll) {
338 | PopupTypeView(
339 | title: "Bottom version 2",
340 | detail: "Popup bottom"
341 | ) {
342 | PopupImage(style: .bottomSecond)
343 | }
344 | }
345 | }
346 |
347 | @ViewBuilder
348 | func actionSheetsSection() -> some View {
349 | PopupButton(isShowing: $actionSheets.showingFirst, hideAll: hideAll) {
350 | PopupTypeView(
351 | title: "Version 1",
352 | detail: "Action sheets"
353 | ) {
354 | ActionSheetImage()
355 | }
356 | }
357 | PopupButton(isShowing: $actionSheets.showingSecond, hideAll: hideAll) {
358 | PopupTypeView(
359 | title: "Version 2",
360 | detail: "Action sheets"
361 | ) {
362 | ActionSheetImage()
363 | }
364 | }
365 | }
366 |
367 | @ViewBuilder
368 | func inputsSection() -> some View {
369 | PopupButton(isShowing: $inputSheets.showingFirst, hideAll: hideAll) {
370 | PopupTypeView(
371 | title: "Bottom Input",
372 | detail: "Popup in the bottom of the screen with an input text field"
373 | ) {
374 | InputSheetImage()
375 | }
376 | }
377 | }
378 | }
379 |
380 | struct PopupsList_Previews: PreviewProvider {
381 | static var previews: some View {
382 | PopupButton(
383 | isShowing: Binding.init(get: { true },
384 | set: { _ in }),
385 | hideAll: {})
386 | {
387 | PopupTypeView(
388 | title: "Top version 1",
389 | detail: "Top float with a picture and one button"
390 | ) {
391 | BigFloatsImage(alignment: .top)
392 | }
393 | }
394 | }
395 | }
396 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/PopupExample/PopupExample/Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.swift
3 | // Example
4 | //
5 | // Created by Alisa Mylnikova on 10/06/2021.
6 | //
7 |
8 | import SwiftUI
9 |
10 | extension Color {
11 | init(hex: String) {
12 | let scanner = Scanner(string: hex)
13 | var rgbValue: UInt64 = 0
14 | scanner.scanHexInt64(&rgbValue)
15 |
16 | let r = (rgbValue & 0xff0000) >> 16
17 | let g = (rgbValue & 0xff00) >> 8
18 | let b = rgbValue & 0xff
19 |
20 | self.init(red: Double(r) / 0xff, green: Double(g) / 0xff, blue: Double(b) / 0xff)
21 | }
22 | }
23 |
24 | extension View {
25 |
26 | @ViewBuilder
27 | func applyIf(_ condition: Bool, apply: (Self) -> T) -> some View {
28 | if condition {
29 | apply(self)
30 | } else {
31 | self
32 | }
33 | }
34 |
35 | func shadowedStyle() -> some View {
36 | self
37 | .shadow(color: .black.opacity(0.08), radius: 2, x: 0, y: 0)
38 | .shadow(color: .black.opacity(0.16), radius: 24, x: 0, y: 0)
39 | }
40 |
41 | func customButtonStyle(
42 | foreground: Color = .black,
43 | background: Color = .white
44 | ) -> some View {
45 | self.buttonStyle(
46 | ExampleButtonStyle(
47 | foreground: foreground,
48 | background: background
49 | )
50 | )
51 | }
52 |
53 | #if os(iOS)
54 | func cornerRadius(_ radius: CGFloat, corners: UIRectCorner) -> some View {
55 | clipShape(RoundedCorner(radius: radius, corners: corners))
56 | }
57 | #endif
58 | }
59 |
60 | private struct ExampleButtonStyle: ButtonStyle {
61 | let foreground: Color
62 | let background: Color
63 |
64 | func makeBody(configuration: Self.Configuration) -> some View {
65 | configuration.label
66 | .opacity(configuration.isPressed ? 0.45 : 1)
67 | .foregroundColor(configuration.isPressed ? foreground.opacity(0.55) : foreground)
68 | .background(configuration.isPressed ? background.opacity(0.55) : background)
69 | }
70 | }
71 |
72 | #if os(iOS)
73 | struct RoundedCorner: Shape {
74 | var radius: CGFloat = .infinity
75 | var corners: UIRectCorner = .allCorners
76 |
77 | func path(in rect: CGRect) -> Path {
78 | let path = UIBezierPath(roundedRect: rect, byRoundingCorners: corners, cornerRadii: CGSize(width: radius, height: radius))
79 | return Path(path.cgPath)
80 | }
81 | }
82 | #endif
83 |
84 | class Constants {
85 | static let privacyPolicy = """
86 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam consectetur orci eget rutrum dignissim. Vivamus aliquam a massa a scelerisque. Integer eleifend lectus non blandit ultricies. Maecenas volutpat neque ut elit facilisis sodales. Mauris et iaculis tellus. Etiam nec mi consequat, ornare quam in, ornare magna. Donec quis egestas nunc. Morbi vel orci leo. Suspendisse eget lectus a erat dignissim interdum et quis neque. Fusce dapibus rhoncus nulla. Cras sed ipsum congue, tempus mi nec, vestibulum lorem.
87 |
88 | Mauris rutrum urna ex, eget bibendum lectus vehicula nec. Mauris quis porttitor sapien, id vestibulum nibh. Proin mi lectus, pretium sed nulla bibendum, fringilla dignissim lacus. Vestibulum eget ante quis urna facilisis tristique. Curabitur mollis cursus mauris, vitae sollicitudin lacus fermentum nec. Etiam accumsan venenatis feugiat. Curabitur vitae posuere quam, imperdiet mattis elit. Nulla sollicitudin non neque sed aliquet. Donec lobortis iaculis interdum.
89 |
90 | Nam eu feugiat arcu. Suspendisse porta eu sapien et eleifend. Fusce viverra laoreet tellus, eget convallis odio. Vivamus eget mollis dui. Sed euismod sed justo in fermentum. Nam at augue convallis, vulputate ligula eu, convallis risus. Proin egestas pretium nibh, in blandit ipsum varius quis. Aenean dolor mauris, luctus vel consequat id, tristique sit amet sem. Donec at pulvinar sem. Mauris diam lacus, placerat eget dolor ac, hendrerit elementum velit.
91 |
92 | Integer sagittis ultricies commodo. Nullam eu diam at justo ornare viverra. Praesent ante metus, rhoncus ac condimentum id, malesuada viverra arcu. Nunc porta, odio at elementum viverra, tortor sem placerat lacus, eget scelerisque turpis odio at nisl. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Nulla varius luctus ex, eu sagittis leo tempor nec. Etiam viverra molestie iaculis. Fusce in cursus ipsum, et elementum metus. Nullam sed sodales ligula. Aliquam erat volutpat. Proin mattis nisi et lectus rutrum, quis aliquet metus aliquet. Nulla est nisi, condimentum sed pretium ac, scelerisque semper eros. Nullam varius diam at augue vehicula elementum eget a leo. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Etiam nisi enim, euismod ac tellus at, hendrerit dignissim turpis. Proin sit amet sapien posuere, facilisis velit quis, placerat purus.
93 |
94 | Maecenas eget felis in lacus pharetra tristique. Nunc vehicula porttitor dolor, non viverra magna blandit sit amet. Phasellus et pellentesque ante, at sollicitudin leo. Etiam at quam nec ex rhoncus sagittis. Nullam tempor lectus id felis efficitur tempus eget eget lectus. Mauris vitae odio nisi. Fusce pellentesque mattis enim, vitae tincidunt nisl tempus sed. Sed et lacus vitae lectus pretium congue nec molestie odio. Phasellus nec libero ac enim consequat dapibus. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Morbi suscipit, urna vel elementum consequat, eros urna tempor nulla, vel mattis arcu ex quis nisl. Phasellus consequat porta lectus, eu tristique ipsum laoreet sit amet. Nam scelerisque ipsum sem, vitae sodales risus gravida in.
95 |
96 | Maecenas felis velit, sodales ut diam vitae, sagittis aliquet neque. Duis tristique nisl at tristique hendrerit. Suspendisse sed egestas orci. Phasellus tempor cursus tellus, eget rhoncus justo mattis id. In a dapibus enim. Nulla eu neque tincidunt tellus finibus mattis. Mauris congue tellus vitae tortor laoreet accumsan.
97 |
98 | Aenean iaculis porta consectetur. Vivamus tristique erat consectetur mi congue sollicitudin. Donec pellentesque, arcu pellentesque rhoncus vestibulum, massa diam vehicula nulla, non lacinia nunc lacus ut felis. Nam euismod finibus quam nec placerat. In imperdiet egestas sapien, sed elementum purus. Nullam interdum nisl fermentum ultrices elementum. Quisque eu mi sapien. Morbi vestibulum urna vel lacinia ultrices. Ut urna tortor, luctus in lorem eget, euismod volutpat magna. Etiam a accumsan massa. Fusce finibus blandit diam ac tincidunt. Nullam vitae dolor augue.
99 |
100 | Maecenas maximus feugiat tellus sed vulputate. Proin ut ante vitae justo pulvinar laoreet. Donec fringilla justo consectetur mi consequat porttitor. Sed at mollis metus. Quisque at magna quis est malesuada aliquam sit amet at augue. Mauris hendrerit nunc ligula, in faucibus erat commodo quis. Nulla lacus dolor, cursus quis ligula eu, lacinia sollicitudin felis. Praesent odio tellus, pellentesque vitae leo ac, faucibus facilisis augue. Pellentesque bibendum nisl eget vehicula convallis. Maecenas velit urna, hendrerit quis nulla vitae, aliquam posuere erat. Integer accumsan sed arcu nec tempus. Etiam pharetra suscipit sapien id venenatis. Donec ultricies quis nisi vitae consectetur.
101 | """
102 | }
103 |
--------------------------------------------------------------------------------
/PopupExample/PopupWatchExample Watch App/ContentView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ContentView.swift
3 | // Example
4 | //
5 | // Created by Alisa Mylnikova on 23/04/2020.
6 | // Copyright © 2020 Exyte. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 | import PopupView
11 |
12 | struct ExampleButton : View {
13 |
14 | @Binding var showing: Bool
15 | var title: String
16 | var hideAll: ()->()
17 |
18 | var body: some View {
19 | Button {
20 | self.hideAll()
21 | self.showing.toggle()
22 | } label: {
23 | Text(title)
24 | .foregroundColor(.black)
25 | }
26 | .frame(maxHeight: 20)
27 | }
28 | }
29 |
30 | struct ContentView : View {
31 |
32 | let bgColor = Color(hex: "e0fbfc")
33 | let popupColor = Color(hex: "3d5a80")
34 | let topToastColor = Color(hex: "293241")
35 | let bottomToastColor = Color(hex: "98c1d9")
36 | let topFloatColor = Color(hex: "293241")
37 | let bottomFloatColor = Color(hex: "ee6c4d")
38 |
39 | @State var showingTopToast = false
40 | @State var showingBottomToast = false
41 | @State var showingTopFloater = false
42 |
43 | private var screenSize: CGSize {
44 | WKInterfaceDevice.current().screenBounds.size
45 | }
46 |
47 | var body: some View {
48 |
49 | let hideAll = {
50 | self.showingTopToast = false
51 | self.showingBottomToast = false
52 | self.showingTopFloater = false
53 | }
54 |
55 | return ZStack {
56 | bgColor
57 | .edgesIgnoringSafeArea(.all)
58 | VStack(spacing: 8) {
59 | ExampleButton(showing: $showingTopToast, title: "Top toast", hideAll: hideAll)
60 | ExampleButton(showing: $showingBottomToast, title: "Bottom toast", hideAll: hideAll)
61 | ExampleButton(showing: $showingTopFloater, title: "Top floater", hideAll: hideAll)
62 | }
63 | }
64 |
65 | .popup(isPresented: $showingTopToast) {
66 | createTopToast()
67 | } customize: {
68 | $0
69 | .type(.toast)
70 | .position(.top)
71 | }
72 |
73 | .popup(isPresented: $showingBottomToast) {
74 | createBottomToast()
75 | } customize: {
76 | $0
77 | .type(.toast)
78 | .position(.bottom)
79 | }
80 |
81 | .popup(isPresented: $showingTopFloater) {
82 | createTopFloater()
83 | } customize: {
84 | $0
85 | .type(.floater())
86 | .position(.top)
87 | .animation(.spring())
88 | .autohideIn(2)
89 | }
90 |
91 | }
92 |
93 | func createTopToast() -> some View {
94 | HStack {
95 | Image("shop_NA")
96 | .resizable()
97 | .aspectRatio(contentMode: ContentMode.fill)
98 | .frame(width: 50, height: 50)
99 | .cornerRadius(25)
100 |
101 | VStack(alignment: .leading, spacing: 2) {
102 | HStack {
103 | Text("Nik")
104 | .foregroundColor(.white)
105 | .fontWeight(.bold)
106 | Spacer()
107 | Text("11:30")
108 | .font(.system(size: 12))
109 | .foregroundColor(Color(red: 0.9, green: 0.9, blue: 0.9))
110 | }
111 |
112 | Text("How about a dinner in an hour? We could discuss that one urgent issue we should be discussing.")
113 | .lineLimit(2)
114 | .font(.system(size: 14))
115 | .foregroundColor(.white)
116 | }
117 | }
118 | .padding(15)
119 | .frame(width: screenSize.width)
120 | .background(self.topToastColor)
121 | }
122 |
123 | func createBottomToast() -> some View {
124 | HStack {
125 | Image("grapes")
126 | .resizable()
127 | .aspectRatio(contentMode: ContentMode.fill)
128 | .frame(width: 40, height: 40)
129 |
130 | VStack(alignment: .leading, spacing: 2) {
131 | Text("Grapes!")
132 | .foregroundColor(.black)
133 | .fontWeight(.bold)
134 |
135 | Text("Step right up!")
136 | .lineLimit(2)
137 | .font(.system(size: 14))
138 | .foregroundColor(.black)
139 | }
140 | }
141 | .padding(15)
142 | .frame(width: screenSize.width)
143 | .background(self.bottomToastColor)
144 | }
145 |
146 | func createTopFloater() -> some View {
147 | HStack(spacing: 10) {
148 | Image("transaction_coffee")
149 | .resizable()
150 | .aspectRatio(contentMode: ContentMode.fill)
151 | .frame(width: 20, height: 20)
152 | VStack(spacing: 8) {
153 | Text("Temperature")
154 | .font(.system(size: 12))
155 | .foregroundColor(.white)
156 |
157 | HStack(spacing: 0) {
158 | Color(red: 1, green: 112/255, blue: 59/255)
159 | .frame(width: 20, height: 5)
160 | Color(red: 1, green: 1, blue: 1)
161 | .frame(width: 60, height: 5)
162 | }
163 | .cornerRadius(2.5)
164 | }
165 | }
166 | .frame(width: 150, height: 60)
167 | .background(self.topFloatColor)
168 | .cornerRadius(30.0)
169 | }
170 |
171 | }
172 |
173 | extension Color {
174 | init(hex: String) {
175 | let scanner = Scanner(string: hex)
176 | var rgbValue: UInt64 = 0
177 | scanner.scanHexInt64(&rgbValue)
178 |
179 | let r = (rgbValue & 0xff0000) >> 16
180 | let g = (rgbValue & 0xff00) >> 8
181 | let b = rgbValue & 0xff
182 |
183 | self.init(red: Double(r) / 0xff, green: Double(g) / 0xff, blue: Double(b) / 0xff)
184 | }
185 | }
186 |
--------------------------------------------------------------------------------
/PopupExample/PopupWatchExample Watch App/PopupWatchExampleApp.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PopupWatchExampleApp.swift
3 | // PopupWatchExample Watch App
4 | //
5 | // Created by Alisa Mylnikova on 15.05.2023.
6 | //
7 |
8 | import SwiftUI
9 |
10 | @main
11 | struct PopupWatchExample_Watch_AppApp: App {
12 | var body: some Scene {
13 | WindowGroup {
14 | ContentView()
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/PopupExample/PopupWatchExample Watch App/Preview Content/Preview Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/Sources/PopupView/FullscreenPopup.swift:
--------------------------------------------------------------------------------
1 | //
2 | // FullscreenPopup.swift
3 | // Pods
4 | //
5 | // Created by Alisa Mylnikova on 29.12.2022.
6 | //
7 |
8 | import Foundation
9 | import SwiftUI
10 |
11 | @MainActor
12 | public struct FullscreenPopup: ViewModifier {
13 |
14 | // MARK: - Presentation
15 |
16 | @State var id = UUID()
17 |
18 | @Binding var isPresented: Bool
19 | @Binding var item: Item?
20 |
21 | var isBoolMode: Bool
22 |
23 | var popupPresented: Bool {
24 | item != nil || isPresented
25 | }
26 |
27 | // MARK: - Parameters
28 |
29 | /// If nil - never hides on its own
30 | var autohideIn: Double?
31 |
32 | /// Only allow dismiss by any means after this time passes
33 | var dismissibleIn: Double?
34 |
35 | /// Becomes true when `dismissibleIn` times finishes
36 | /// Makes no sense if `dismissibleIn` is nil
37 | var dismissEnabled: Binding
38 |
39 | /// Should close on tap outside - default is `false`
40 | var closeOnTapOutside: Bool
41 |
42 | /// Background color for outside area - default is `Color.clear`
43 | var backgroundColor: Color
44 |
45 | /// Custom background view for outside area
46 | var backgroundView: AnyView?
47 |
48 | /// If opaque - taps do not pass through popup's background color
49 | var displayMode: Popup.DisplayMode
50 |
51 | /// called when when dismiss animation starts
52 | var userWillDismissCallback: (DismissSource) -> ()
53 |
54 | /// called when when dismiss animation ends
55 | var userDismissCallback: (DismissSource) -> ()
56 |
57 | var params: Popup.PopupParameters
58 |
59 | var view: (() -> PopupContent)!
60 | var itemView: ((Item) -> PopupContent)!
61 |
62 | // MARK: - Presentation animation
63 |
64 | /// Trigger popup showing/hiding animations and...
65 | @State private var shouldShowContent = false
66 |
67 | /// ... once hiding animation is finished remove popup from the memory using this flag
68 | @State private var showContent = false
69 |
70 | /// keep track of closing state to avoid unnecessary showing bug
71 | @State private var closingIsInProcess = false
72 |
73 | /// show transparentNonAnimatingFullScreenCover
74 | @State private var showSheet = false
75 |
76 | /// opacity of background color
77 | @State private var animatableOpacity: CGFloat = 0
78 |
79 | /// A temporary variable to hold a copy of the `itemView` when the item is nil (to complete `itemView`'s dismiss animation)
80 | @State private var tempItemView: PopupContent?
81 |
82 | // MARK: - Autohide
83 |
84 | /// Class reference for capturing a weak reference later in dispatch work holder.
85 | private var isPresentedRef: ClassReference>?
86 | private var itemRef: ClassReference>?
87 |
88 | /// holder for autohiding dispatch work (to be able to cancel it when needed)
89 | @State private var autohidingWorkHolder = DispatchWorkHolder()
90 |
91 | /// holder for `dismissibleIn` dispatch work (to be able to cancel it when needed)
92 | @State private var dismissibleInWorkHolder = DispatchWorkHolder()
93 |
94 | // MARK: - Autohide With Dragging
95 | /// If user "grabbed" the popup to drag it around, put off the autohiding until he lifts his finger up
96 |
97 | /// is user currently holding th popup with his finger
98 | @State private var isDragging = false
99 |
100 | /// if autohide time was set up, shows that timer has come to an end already
101 | @State private var timeToHide = false
102 |
103 | // MARK: - dismissibleIn
104 |
105 | private var dismissEnabledRef: ClassReference>?
106 |
107 | // MARK: - Internal
108 |
109 | /// Set dismiss source to pass to dismiss callback
110 | @State private var dismissSource: DismissSource?
111 |
112 | /// Synchronize isPresented changes and animations
113 | private let eventsQueue = DispatchQueue(label: "eventsQueue", qos: .utility)
114 | @State private var eventsSemaphore = DispatchSemaphore(value: 1)
115 |
116 | init(isPresented: Binding = .constant(false),
117 | item: Binding- = .constant(nil),
118 | isBoolMode: Bool,
119 | params: Popup.PopupParameters,
120 | view: (() -> PopupContent)?,
121 | itemView: ((Item) -> PopupContent)?) {
122 | self._isPresented = isPresented
123 | self._item = item
124 | self.isBoolMode = isBoolMode
125 |
126 | self.params = params
127 | self.autohideIn = params.autohideIn
128 | self.dismissibleIn = params.dismissibleIn
129 | self.dismissEnabled = params.dismissEnabled
130 | self.closeOnTapOutside = params.closeOnTapOutside
131 | self.backgroundColor = params.backgroundColor
132 | self.backgroundView = params.backgroundView
133 | self.displayMode = params.displayMode
134 | self.userDismissCallback = params.dismissCallback
135 | self.userWillDismissCallback = params.willDismissCallback
136 |
137 | if let view = view {
138 | self.view = view
139 | }
140 | if let itemView = itemView {
141 | self.itemView = itemView
142 | }
143 |
144 | self.isPresentedRef = ClassReference(self.$isPresented)
145 | self.itemRef = ClassReference(self.$item)
146 | self.dismissEnabledRef = ClassReference(self.dismissEnabled)
147 | }
148 |
149 | public func body(content: Content) -> some View {
150 | if isBoolMode {
151 | main(content: content)
152 | .onChange(of: isPresented) { newValue in
153 | eventsQueue.async { [eventsSemaphore] in
154 | eventsSemaphore.wait()
155 | DispatchQueue.main.async {
156 | closingIsInProcess = !newValue
157 | appearAction(popupPresented: newValue)
158 | }
159 | }
160 | }
161 | .onAppear {
162 | if isPresented {
163 | appearAction(popupPresented: true)
164 | }
165 | }
166 | } else {
167 | main(content: content)
168 | .onChange(of: item) { newValue in
169 | DispatchQueue.main.asyncAfter(deadline: .now() + 0.03) {
170 | self.closingIsInProcess = newValue == nil
171 | if let newValue {
172 | /// copying `itemView`
173 | self.tempItemView = itemView(newValue)
174 | }
175 | appearAction(popupPresented: newValue != nil)
176 | }
177 | }
178 | .onAppear {
179 | if let item {
180 | self.tempItemView = itemView(item)
181 | appearAction(popupPresented: true)
182 | }
183 | }
184 | }
185 | }
186 |
187 | @ViewBuilder
188 | public func main(content: Content) -> some View {
189 | #if os(iOS)
190 | switch displayMode {
191 | case .overlay:
192 | ZStack {
193 | content
194 | constructPopup()
195 | }
196 |
197 | case .sheet:
198 | content.transparentNonAnimatingFullScreenCover(isPresented: $showSheet, dismissSource: dismissSource, userDismissCallback: userDismissCallback) {
199 | constructPopup()
200 | }
201 |
202 | case .window:
203 | content
204 | .onChange(of: showSheet) { newValue in
205 | if newValue {
206 | WindowManager.showInNewWindow(id: id, dismissClosure: {
207 | dismissSource = .binding
208 | isPresented = false
209 | item = nil
210 | }) {
211 | constructPopup()
212 | }
213 | } else {
214 | WindowManager.closeWindow(id: id)
215 | }
216 | }
217 | }
218 | #else
219 | ZStack {
220 | content
221 | constructPopup()
222 | }
223 | #endif
224 | }
225 |
226 | @ViewBuilder
227 | func constructPopup() -> some View {
228 | if showContent {
229 | PopupBackgroundView(
230 | id: $id,
231 | isPresented: $isPresented,
232 | item: $item,
233 | animatableOpacity: $animatableOpacity,
234 | dismissSource: $dismissSource,
235 | backgroundColor: backgroundColor,
236 | backgroundView: backgroundView,
237 | closeOnTapOutside: closeOnTapOutside,
238 | dismissEnabled: dismissEnabled
239 | )
240 | .modifier(getModifier())
241 | }
242 | }
243 |
244 | var viewForItem: (() -> PopupContent)? {
245 | if let item = item {
246 | return { itemView(item) }
247 | } else if let tempItemView {
248 | return { tempItemView }
249 | }
250 | return nil
251 | }
252 |
253 | private func getModifier() -> Popup {
254 | Popup(
255 | params: params,
256 | view: viewForItem != nil ? viewForItem! : view,
257 | shouldShowContent: $shouldShowContent,
258 | showContent: showContent,
259 | isDragging: $isDragging,
260 | timeToHide: $timeToHide,
261 | positionIsCalculatedCallback: {
262 | // once the closing has been started, don't allow position recalculation to trigger popup showing again
263 | if !closingIsInProcess {
264 | DispatchQueue.main.async {
265 | shouldShowContent = true // this will cause currentOffset change thus triggering the sliding showing animation
266 | withAnimation(.linear(duration: 0.2)) {
267 | animatableOpacity = 1 // this will cause cross dissolving animation for background color/view
268 | }
269 | }
270 | setupAutohide()
271 | setupdismissibleIn()
272 | }
273 | },
274 | dismissCallback: { source in
275 | dismissSource = source
276 | isPresented = false
277 | item = nil
278 | }
279 | )
280 | }
281 |
282 | func appearAction(popupPresented: Bool) {
283 | if popupPresented {
284 | dismissSource = nil
285 | showSheet = true // show transparent fullscreen sheet
286 | showContent = true // immediately load popup body
287 | // shouldShowContent is set after popup's frame is calculated, see positionIsCalculatedCallback
288 | } else {
289 | closingIsInProcess = true
290 | userWillDismissCallback(dismissSource ?? .binding)
291 | autohidingWorkHolder.work?.cancel()
292 | dismissibleInWorkHolder.work?.cancel()
293 | shouldShowContent = false // this will cause currentOffset change thus triggering the sliding hiding animation
294 | animatableOpacity = 0
295 | // do the rest once the animation is finished (see onAnimationCompleted())
296 | }
297 |
298 | // animation completion block isn't being called reliably when there are other animations happening at the same time (drag, autohide, etc.) so here we imitate onAnimationCompleted
299 | performWithDelay(0.3) {
300 | onAnimationCompleted()
301 | }
302 | }
303 |
304 | func onAnimationCompleted() {
305 | if shouldShowContent { // return if this was called on showing animation, only proceed if called on hiding
306 | eventsSemaphore.signal()
307 | return
308 | }
309 | showContent = false // unload popup body after hiding animation is done
310 | tempItemView = nil
311 | if dismissibleIn != nil {
312 | dismissEnabled.wrappedValue = false
313 | }
314 | performWithDelay(0.01) {
315 | showSheet = false
316 | }
317 | if displayMode != .sheet { // for .sheet this callback is called in fullScreenCover's onDisappear
318 | userDismissCallback(dismissSource ?? .binding)
319 | }
320 |
321 | eventsSemaphore.signal()
322 | }
323 |
324 | func setupAutohide() {
325 | // if needed, dispatch autohide and cancel previous one
326 | if let autohideIn = autohideIn {
327 | autohidingWorkHolder.work?.cancel()
328 |
329 | // Weak reference to avoid the work item capturing the struct,
330 | // which would create a retain cycle with the work holder itself.
331 |
332 | autohidingWorkHolder.work = DispatchWorkItem(block: { [weak isPresentedRef, weak itemRef] in
333 | if isDragging {
334 | timeToHide = true // raise this flag to hide the popup once the drag is over
335 | return
336 | }
337 | dismissSource = .autohide
338 | isPresentedRef?.value.wrappedValue = false
339 | itemRef?.value.wrappedValue = nil
340 | autohidingWorkHolder.work = nil
341 | })
342 | if popupPresented, let work = autohidingWorkHolder.work {
343 | DispatchQueue.main.asyncAfter(deadline: .now() + autohideIn, execute: work)
344 | }
345 | }
346 | }
347 |
348 | func setupdismissibleIn() {
349 | if let dismissibleIn = dismissibleIn {
350 | dismissibleInWorkHolder.work?.cancel()
351 |
352 | // Weak reference to avoid the work item capturing the struct,
353 | // which would create a retain cycle with the work holder itself.
354 |
355 | dismissibleInWorkHolder.work = DispatchWorkItem(block: { [weak dismissEnabledRef] in
356 | dismissEnabledRef?.value.wrappedValue = true
357 | dismissibleInWorkHolder.work = nil
358 | })
359 | if popupPresented, let work = dismissibleInWorkHolder.work {
360 | DispatchQueue.main.asyncAfter(deadline: .now() + dismissibleIn, execute: work)
361 | }
362 | }
363 | }
364 |
365 | func performWithDelay(_ delay: Double, block: @escaping ()->()) {
366 | DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
367 | block()
368 | }
369 | }
370 | }
371 |
--------------------------------------------------------------------------------
/Sources/PopupView/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Sources/PopupView/Modifiers.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Constructors.swift
3 | // Pods
4 | //
5 | // Created by Alisa Mylnikova on 11.10.2022.
6 | //
7 |
8 | import SwiftUI
9 |
10 | public typealias SendableClosure = @Sendable @MainActor () -> Void
11 |
12 | struct PopupDismissKey: EnvironmentKey {
13 | static let defaultValue: SendableClosure? = nil
14 | }
15 |
16 | public extension EnvironmentValues {
17 | var popupDismiss: SendableClosure? {
18 | get { self[PopupDismissKey.self] }
19 | set { self[PopupDismissKey.self] = newValue }
20 | }
21 | }
22 |
23 | @MainActor
24 | extension View {
25 | public func popup(
26 | isPresented: Binding,
27 | @ViewBuilder view: @escaping () -> PopupContent,
28 | customize: @escaping (Popup.PopupParameters) -> Popup.PopupParameters
29 | ) -> some View {
30 | self.modifier(
31 | FullscreenPopup(
32 | isPresented: isPresented,
33 | isBoolMode: true,
34 | params: customize(Popup.PopupParameters()),
35 | view: view,
36 | itemView: nil)
37 | )
38 | .environment(\.popupDismiss) {
39 | isPresented.wrappedValue = false
40 | }
41 | }
42 |
43 | public func popup(
44 | item: Binding
- ,
45 | @ViewBuilder itemView: @escaping (Item) -> PopupContent,
46 | customize: @escaping (Popup.PopupParameters) -> Popup.PopupParameters
47 | ) -> some View {
48 | self.modifier(
49 | FullscreenPopup
- (
50 | item: item,
51 | isBoolMode: false,
52 | params: customize(Popup.PopupParameters()),
53 | view: nil,
54 | itemView: itemView)
55 | )
56 | .environment(\.popupDismiss) {
57 | item.wrappedValue = nil
58 | }
59 | }
60 |
61 | public func popup(
62 | isPresented: Binding,
63 | @ViewBuilder view: @escaping () -> PopupContent) -> some View {
64 | self.modifier(
65 | FullscreenPopup(
66 | isPresented: isPresented,
67 | isBoolMode: true,
68 | params: Popup.PopupParameters(),
69 | view: view,
70 | itemView: nil)
71 | )
72 | .environment(\.popupDismiss) {
73 | isPresented.wrappedValue = false
74 | }
75 | }
76 |
77 | public func popup(
78 | item: Binding
- ,
79 | @ViewBuilder itemView: @escaping (Item) -> PopupContent) -> some View {
80 | self.modifier(
81 | FullscreenPopup
- (
82 | item: item,
83 | isBoolMode: false,
84 | params: Popup.PopupParameters(),
85 | view: nil,
86 | itemView: itemView)
87 | )
88 | .environment(\.popupDismiss) {
89 | item.wrappedValue = nil
90 | }
91 | }
92 | }
93 |
94 | #if os(iOS)
95 |
96 | @MainActor
97 | extension View {
98 | func onOrientationChange(isLandscape: Binding, onOrientationChange: @escaping () -> Void) -> some View {
99 | self.modifier(OrientationChangeModifier(isLandscape: isLandscape, onOrientationChange: onOrientationChange))
100 | }
101 | }
102 |
103 | @MainActor
104 | struct OrientationChangeModifier: ViewModifier {
105 | @Binding var isLandscape: Bool
106 | let onOrientationChange: () -> Void
107 |
108 | func body(content: Content) -> some View {
109 | content
110 | #if os(iOS)
111 | .onReceive(NotificationCenter.default
112 | .publisher(for: UIDevice.orientationDidChangeNotification)
113 | .receive(on: DispatchQueue.main)
114 | ) { _ in
115 | updateOrientation()
116 | }
117 | #endif
118 | // .onAppear {
119 | //#if os(iOS)
120 | // NotificationCenter.default.addObserver(forName: UIDevice.orientationDidChangeNotification, object: nil, queue: .main) { _ in
121 | // DispatchQueue.main.async {
122 | // updateOrientation()
123 | // }
124 | // }
125 | // updateOrientation()
126 | //#endif
127 | // }
128 | // .onDisappear {
129 | // #if os(iOS)
130 | // NotificationCenter.default.removeObserver(self, name: UIDevice.orientationDidChangeNotification, object: nil)
131 | // #endif
132 | // }
133 | .onChange(of: isLandscape) { _ in
134 | onOrientationChange()
135 | }
136 | }
137 |
138 | #if os(iOS)
139 | private func updateOrientation() {
140 | let newIsLandscape = UIDevice.current.orientation.isLandscape
141 | if newIsLandscape != isLandscape {
142 | isLandscape = newIsLandscape
143 | onOrientationChange()
144 | }
145 | }
146 | #endif
147 | }
148 |
149 | #endif
150 |
--------------------------------------------------------------------------------
/Sources/PopupView/PopupBackgroundView.swift:
--------------------------------------------------------------------------------
1 | //
2 | // with.swift
3 | // PopupView
4 | //
5 | // Created by Alisa Mylnikova on 28.03.2025.
6 | //
7 |
8 | import SwiftUI
9 |
10 | /// this is a separe struct with @Bindings because of how UIWindow doesn't receive updates in usual SwiftUI manner
11 | struct PopupBackgroundView: View {
12 |
13 | @Binding var id: UUID
14 |
15 | @Binding var isPresented: Bool
16 | @Binding var item: Item?
17 |
18 | @Binding var animatableOpacity: CGFloat
19 | @Binding var dismissSource: DismissSource?
20 |
21 | var backgroundColor: Color
22 | var backgroundView: AnyView?
23 | var closeOnTapOutside: Bool
24 | var dismissEnabled: Binding
25 |
26 | var body: some View {
27 | Group {
28 | if let backgroundView = backgroundView {
29 | backgroundView
30 | } else {
31 | backgroundColor
32 | }
33 | }
34 | .opacity(animatableOpacity)
35 | .applyIf(closeOnTapOutside) { view in
36 | view.contentShape(Rectangle())
37 | }
38 | .addTapIfNotTV(if: closeOnTapOutside) {
39 | if dismissEnabled.wrappedValue {
40 | dismissSource = .tapOutside
41 | isPresented = false
42 | item = nil
43 | }
44 | }
45 | .edgesIgnoringSafeArea(.all)
46 | .animation(.linear(duration: 0.2), value: animatableOpacity)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Sources/PopupView/PopupScrollViewDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PopupScrollViewDelegate.swift
3 | //
4 | //
5 | // Created by vadim.vitkovskiy on 15.02.2024.
6 | //
7 |
8 | #if os(iOS)
9 | import UIKit
10 |
11 | extension UIScrollView {
12 | func maxContentOffsetHeight() -> CGFloat {
13 | let contentHeight = contentSize.height
14 | let visibleHeight = bounds.height
15 | let maxOffsetHeight = max(0, contentHeight - visibleHeight)
16 | return maxOffsetHeight
17 | }
18 | }
19 |
20 | final class PopupScrollViewDelegate: NSObject, ObservableObject, UIScrollViewDelegate {
21 |
22 | var scrollView: UIScrollView?
23 |
24 | var gestureIsCreated = false
25 |
26 | var didReachTop: (Double) -> Void = {_ in }
27 | var scrollEnded: (Double) -> Void = {_ in }
28 |
29 | @objc
30 | func handlePan(_ gesture: UIPanGestureRecognizer) {
31 | let translation = gesture.translation(in: scrollView)
32 | let contentOffset = scrollView?.contentOffset.y ?? 0
33 | let maxContentOffset = scrollView?.maxContentOffsetHeight() ?? 0
34 |
35 | if contentOffset - translation.y > 0 {
36 | scrollView?.contentOffset.y = min(contentOffset - translation.y, maxContentOffset)
37 | gesture.setTranslation(.zero, in: scrollView)
38 | } else {
39 | scrollView?.contentOffset.y = 0
40 | didReachTop(contentOffset - translation.y)
41 | }
42 |
43 | if gesture.state == .ended && contentOffset - translation.y < 0 {
44 | scrollEnded(contentOffset - translation.y)
45 | }
46 | }
47 |
48 | func addGestureIfNeeded() {
49 | guard let gestures = scrollView?.gestureRecognizers else { return }
50 |
51 | if !gestureIsCreated {
52 | let panGesture = gestures[1] as? UIPanGestureRecognizer
53 | panGesture?.addTarget(self, action: #selector(handlePan))
54 | scrollView?.bounces = false
55 | gestureIsCreated = true
56 | }
57 | }
58 | }
59 | #endif
60 |
--------------------------------------------------------------------------------
/Sources/PopupView/PopupView.h:
--------------------------------------------------------------------------------
1 | //
2 | // PopupView.h
3 | // PopupView
4 | //
5 | // Created by Alisa Mylnikova on 23/04/2020.
6 | // Copyright © 2020 Exyte. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for PopupView.
12 | FOUNDATION_EXPORT double PopupViewVersionNumber;
13 |
14 | //! Project version string for PopupView.
15 | FOUNDATION_EXPORT const unsigned char PopupViewVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Sources/PopupView/PublicAPI.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PublicAPI.swift
3 | // PopupView
4 | //
5 | // Created by Alisa Mylnikova on 28.03.2025.
6 | //
7 |
8 | import SwiftUI
9 |
10 | public enum DismissSource {
11 | case binding // set isPresented to false ot item to nil
12 | case tapInside
13 | case tapOutside
14 | case drag
15 | case autohide
16 | }
17 |
18 | extension Popup {
19 |
20 | public enum PopupType {
21 | case `default`
22 | case toast
23 | case floater(verticalPadding: CGFloat = 10, horizontalPadding: CGFloat = 10, useSafeAreaInset: Bool = true)
24 | #if os(iOS)
25 | case scroll(headerView: AnyView)
26 | #endif
27 |
28 | var defaultPosition: Position {
29 | if case .default = self {
30 | return .center
31 | }
32 | return .bottom
33 | }
34 |
35 | var verticalPadding: CGFloat {
36 | if case let .floater(verticalPadding, _, _) = self {
37 | return verticalPadding
38 | }
39 | return 0
40 | }
41 |
42 | var horizontalPadding: CGFloat {
43 | if case let .floater(_, horizontalPadding, _) = self {
44 | return horizontalPadding
45 | }
46 | return 0
47 | }
48 |
49 | var useSafeAreaInset: Bool {
50 | if case let .floater(_, _, use) = self {
51 | return use
52 | }
53 | return false
54 | }
55 | }
56 |
57 | public enum DisplayMode {
58 | case overlay // place the popup above the content in a ZStack
59 | case sheet // using .fullscreenSheet
60 | case window // using UIWindow
61 | }
62 |
63 | public enum Position {
64 | case topLeading
65 | case top
66 | case topTrailing
67 |
68 | case leading
69 | case center // usual popup
70 | case trailing
71 |
72 | case bottomLeading
73 | case bottom
74 | case bottomTrailing
75 |
76 | var isTop: Bool {
77 | [.topLeading, .top, .topTrailing].contains(self)
78 | }
79 |
80 | var isVerticalCenter: Bool {
81 | [.leading, .center, .trailing].contains(self)
82 | }
83 |
84 | var isBottom: Bool {
85 | [.bottomLeading, .bottom, .bottomTrailing].contains(self)
86 | }
87 |
88 | var isLeading: Bool {
89 | [.topLeading, .leading, .bottomLeading].contains(self)
90 | }
91 |
92 | var isHorizontalCenter: Bool {
93 | [.top, .center, .bottom].contains(self)
94 | }
95 |
96 | var isTrailing: Bool {
97 | [.topTrailing, .trailing, .bottomTrailing].contains(self)
98 | }
99 | }
100 |
101 | public enum AppearAnimation {
102 | case topSlide
103 | case bottomSlide
104 | case leftSlide
105 | case rightSlide
106 | case centerScale
107 | case none
108 | }
109 |
110 | public struct PopupParameters {
111 | var type: PopupType = .default
112 | var displayMode: DisplayMode = .window
113 |
114 | var position: Position?
115 |
116 | var appearFrom: AppearAnimation?
117 | var disappearTo: AppearAnimation?
118 |
119 | var animation: Animation = .easeOut(duration: 0.3)
120 |
121 | /// If nil - never hides on its own
122 | var autohideIn: Double?
123 |
124 | /// Only allow dismiss by any means after this time passes
125 | var dismissibleIn: Double?
126 |
127 | /// Becomes true when `dismissibleIn` times finishes
128 | /// Makes no sense if `dismissibleIn` is nil
129 | var dismissEnabled: Binding = .constant(true)
130 |
131 | /// Should allow dismiss by dragging - default is `true`
132 | var dragToDismiss: Bool = true
133 |
134 | /// Minimum distance to drag to dismiss
135 | var dragToDismissDistance: CGFloat?
136 |
137 | /// Should close on tap - default is `true`
138 | var closeOnTap: Bool = true
139 |
140 | /// Should close on tap outside - default is `false`
141 | var closeOnTapOutside: Bool = false
142 |
143 | /// Background color for outside area
144 | var backgroundColor: Color = .clear
145 |
146 | /// Custom background view for outside area
147 | var backgroundView: AnyView?
148 |
149 | /// move up for keyboardHeight when it is displayed
150 | var useKeyboardSafeArea: Bool = false
151 |
152 | /// called when when dismiss animation starts
153 | var willDismissCallback: (DismissSource) -> () = {_ in}
154 |
155 | /// called when when dismiss animation ends
156 | var dismissCallback: (DismissSource) -> () = {_ in}
157 |
158 | public func type(_ type: PopupType) -> PopupParameters {
159 | var params = self
160 | params.type = type
161 | return params
162 | }
163 |
164 | public func displayMode(_ displayMode: DisplayMode) -> PopupParameters {
165 | var params = self
166 | params.displayMode = displayMode
167 | return params
168 | }
169 |
170 | public func position(_ position: Position) -> PopupParameters {
171 | var params = self
172 | params.position = position
173 | return params
174 | }
175 |
176 | public func appearFrom(_ appearFrom: AppearAnimation) -> PopupParameters {
177 | var params = self
178 | params.appearFrom = appearFrom
179 | return params
180 | }
181 |
182 | public func disappearTo(_ disappearTo: AppearAnimation) -> PopupParameters {
183 | var params = self
184 | params.disappearTo = disappearTo
185 | return params
186 | }
187 |
188 | public func animation(_ animation: Animation) -> PopupParameters {
189 | var params = self
190 | params.animation = animation
191 | return params
192 | }
193 |
194 | public func autohideIn(_ autohideIn: Double?) -> PopupParameters {
195 | var params = self
196 | params.autohideIn = autohideIn
197 | return params
198 | }
199 |
200 | public func dismissibleIn(_ dismissibleIn: Double?, _ dismissEnabled: Binding?) -> PopupParameters {
201 | var params = self
202 | params.dismissibleIn = dismissibleIn
203 | if let dismissEnabled = dismissEnabled {
204 | params.dismissEnabled = dismissEnabled
205 | }
206 | return params
207 | }
208 |
209 | /// Should allow dismiss by dragging - default is `true`
210 | public func dragToDismiss(_ dragToDismiss: Bool) -> PopupParameters {
211 | var params = self
212 | params.dragToDismiss = dragToDismiss
213 | return params
214 | }
215 |
216 | /// Minimum distance to drag to dismiss
217 | public func dragToDismissDistance(_ dragToDismissDistance: CGFloat) -> PopupParameters {
218 | var params = self
219 | params.dragToDismissDistance = dragToDismissDistance
220 | return params
221 | }
222 |
223 | /// Should close on tap - default is `true`
224 | public func closeOnTap(_ closeOnTap: Bool) -> PopupParameters {
225 | var params = self
226 | params.closeOnTap = closeOnTap
227 | return params
228 | }
229 |
230 | /// Should close on tap outside - default is `false`
231 | public func closeOnTapOutside(_ closeOnTapOutside: Bool) -> PopupParameters {
232 | var params = self
233 | params.closeOnTapOutside = closeOnTapOutside
234 | return params
235 | }
236 |
237 | public func backgroundColor(_ backgroundColor: Color) -> PopupParameters {
238 | var params = self
239 | params.backgroundColor = backgroundColor
240 | return params
241 | }
242 |
243 | public func backgroundView(_ backgroundView: ()->(BackgroundView)) -> PopupParameters {
244 | var params = self
245 | params.backgroundView = AnyView(backgroundView())
246 | return params
247 | }
248 |
249 | @available(*, deprecated, message: "use displayMode instead")
250 | public func isOpaque(_ isOpaque: Bool) -> PopupParameters {
251 | var params = self
252 | params.displayMode = isOpaque ? .sheet : .overlay
253 | return params
254 | }
255 |
256 | public func useKeyboardSafeArea(_ useKeyboardSafeArea: Bool) -> PopupParameters {
257 | var params = self
258 | params.useKeyboardSafeArea = useKeyboardSafeArea
259 | return params
260 | }
261 |
262 | // MARK: - dismiss callbacks
263 |
264 | public func willDismissCallback(_ dismissCallback: @escaping (DismissSource) -> ()) -> PopupParameters {
265 | var params = self
266 | params.willDismissCallback = dismissCallback
267 | return params
268 | }
269 |
270 | public func willDismissCallback(_ dismissCallback: @escaping () -> ()) -> PopupParameters {
271 | var params = self
272 | params.willDismissCallback = { _ in
273 | dismissCallback()
274 | }
275 | return params
276 | }
277 |
278 | @available(*, deprecated, renamed: "dismissCallback")
279 | public func dismissSourceCallback(_ dismissCallback: @escaping (DismissSource) -> ()) -> PopupParameters {
280 | var params = self
281 | params.dismissCallback = dismissCallback
282 | return params
283 | }
284 |
285 | public func dismissCallback(_ dismissCallback: @escaping (DismissSource) -> ()) -> PopupParameters {
286 | var params = self
287 | params.dismissCallback = dismissCallback
288 | return params
289 | }
290 |
291 | public func dismissCallback(_ dismissCallback: @escaping () -> ()) -> PopupParameters {
292 | var params = self
293 | params.dismissCallback = { _ in
294 | dismissCallback()
295 | }
296 | return params
297 | }
298 | }
299 | }
300 |
--------------------------------------------------------------------------------
/Sources/PopupView/Utils.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Utils.swift
3 | // PopupView
4 | //
5 | // Created by Alisa Mylnikova on 01.06.2022.
6 | // Copyright © 2022 Exyte. All rights reserved.
7 | //
8 |
9 | import SwiftUI
10 | import Combine
11 | import Foundation
12 |
13 | struct MemoryAddress: CustomStringConvertible {
14 |
15 | let intValue: Int
16 |
17 | var description: String {
18 | let length = 2 + 2 * MemoryLayout.size
19 | return String(format: "%0\(length)p", intValue)
20 | }
21 |
22 | // for structures
23 | init(of structPointer: UnsafePointer) {
24 | intValue = Int(bitPattern: structPointer)
25 | }
26 | }
27 |
28 | extension MemoryAddress where T: AnyObject {
29 |
30 | // for classes
31 | init(of classInstance: T) {
32 | intValue = unsafeBitCast(classInstance, to: Int.self)
33 | // or Int(bitPattern: Unmanaged.passUnretained(classInstance).toOpaque())
34 | }
35 | }
36 | final class DispatchWorkHolder {
37 | var work: DispatchWorkItem?
38 | }
39 |
40 | final class ClassReference {
41 | var value: T
42 |
43 | init(_ value: T) {
44 | self.value = value
45 | }
46 | }
47 |
48 | extension View {
49 |
50 | @ViewBuilder
51 | func valueChanged(value: T, onChange: @escaping (T) -> Void) -> some View {
52 | if #available(iOS 14.0, tvOS 14.0, macOS 11.0, watchOS 7.0, *) {
53 | self.onChange(of: value, perform: onChange)
54 | } else {
55 | self.onReceive(Just(value)) { value in
56 | onChange(value)
57 | }
58 | }
59 | }
60 | }
61 |
62 | extension View {
63 | @ViewBuilder
64 | func applyIf(_ condition: Bool, apply: (Self) -> T) -> some View {
65 | if condition {
66 | apply(self)
67 | } else {
68 | self
69 | }
70 | }
71 |
72 | @ViewBuilder
73 | func addTapIfNotTV(if condition: Bool, onTap: @escaping ()->()) -> some View {
74 | #if os(tvOS)
75 | self
76 | #else
77 | if condition {
78 | self.simultaneousGesture(
79 | TapGesture().onEnded {
80 | onTap()
81 | }
82 | )
83 | } else {
84 | self
85 | }
86 | #endif
87 | }
88 | }
89 |
90 | // MARK: - FrameGetter
91 |
92 | struct FrameGetter: ViewModifier {
93 |
94 | @Binding var frame: CGRect
95 |
96 | func body(content: Content) -> some View {
97 | content
98 | .background(
99 | GeometryReader { proxy -> AnyView in
100 | DispatchQueue.main.async {
101 | let rect = proxy.frame(in: .global)
102 | // This avoids an infinite layout loop
103 | if rect.integral != self.frame.integral {
104 | self.frame = rect
105 | }
106 | }
107 | return AnyView(EmptyView())
108 | }
109 | )
110 | }
111 | }
112 |
113 | internal extension View {
114 | func frameGetter(_ frame: Binding) -> some View {
115 | modifier(FrameGetter(frame: frame))
116 | }
117 | }
118 |
119 | struct SafeAreaGetter: ViewModifier {
120 |
121 | @Binding var safeArea: EdgeInsets
122 |
123 | func body(content: Content) -> some View {
124 | content
125 | .background(
126 | GeometryReader { proxy -> AnyView in
127 | DispatchQueue.main.async {
128 | let area = proxy.safeAreaInsets
129 | // This avoids an infinite layout loop
130 | if area != self.safeArea {
131 | self.safeArea = area
132 | }
133 | }
134 | return AnyView(EmptyView())
135 | }
136 | )
137 | }
138 | }
139 |
140 | extension View {
141 | public func safeAreaGetter(_ safeArea: Binding) -> some View {
142 | modifier(SafeAreaGetter(safeArea: safeArea))
143 | }
144 | }
145 |
146 | // MARK: - TransparentNonAnimatingFullScreenCover
147 |
148 | #if os(iOS)
149 |
150 | extension View {
151 |
152 | func transparentNonAnimatingFullScreenCover(
153 | isPresented: Binding,
154 | dismissSource: DismissSource?,
155 | userDismissCallback: @escaping (DismissSource) -> (),
156 | content: @escaping () -> Content) -> some View {
157 | modifier(TransparentNonAnimatableFullScreenModifier(isPresented: isPresented, dismissSource: dismissSource, userDismissCallback: userDismissCallback, fullScreenContent: content))
158 | }
159 | }
160 |
161 | private struct TransparentNonAnimatableFullScreenModifier: ViewModifier {
162 |
163 | @Binding var isPresented: Bool
164 | var dismissSource: DismissSource?
165 | var userDismissCallback: (DismissSource) -> ()
166 | let fullScreenContent: () -> (FullScreenContent)
167 |
168 | func body(content: Content) -> some View {
169 | content
170 | .onChange(of: isPresented) { isPresented in
171 | UIView.setAnimationsEnabled(false)
172 | }
173 | .fullScreenCover(isPresented: $isPresented) {
174 | ZStack {
175 | fullScreenContent()
176 | }
177 | .background(FullScreenCoverBackgroundRemovalView())
178 | .onAppear {
179 | if !UIView.areAnimationsEnabled {
180 | UIView.setAnimationsEnabled(true)
181 | }
182 | }
183 | .onDisappear {
184 | userDismissCallback(dismissSource ?? .binding)
185 | if !UIView.areAnimationsEnabled {
186 | UIView.setAnimationsEnabled(true)
187 | }
188 | }
189 | }
190 | }
191 | }
192 |
193 | private struct FullScreenCoverBackgroundRemovalView: UIViewRepresentable {
194 |
195 | private class BackgroundRemovalView: UIView {
196 | override func didMoveToWindow() {
197 | super.didMoveToWindow()
198 | superview?.superview?.backgroundColor = .clear
199 | }
200 | }
201 |
202 | func makeUIView(context: Context) -> UIView {
203 | return BackgroundRemovalView()
204 | }
205 |
206 | func updateUIView(_ uiView: UIView, context: Context) {}
207 | }
208 |
209 | #endif
210 |
211 | // MARK: - WindowManager
212 |
213 | #if os(iOS)
214 |
215 | // A generic wrapper that tracks changes in the view's state
216 | @MainActor
217 | class HostingViewState: ObservableObject {
218 | @Published var content: Content
219 | let id1: UUID
220 |
221 | private var cancellable: AnyCancellable?
222 |
223 | init(content: Content, id: UUID) {
224 | self.content = content
225 | self.id1 = id
226 | // Subscribe to changes in the content and trigger updates
227 | self.cancellable = self.observeStateChanges()
228 | }
229 |
230 | private func observeStateChanges() -> AnyCancellable {
231 | // Observe state changes using Combine
232 | // You can use `Just` here for simplicity, or expand it for more complex needs.
233 | // In real-world cases, this would listen to any changes in the state object passed.
234 |
235 | return Just(content)
236 | .sink { [weak self] newContent in
237 | guard let self else { return }
238 | WindowManager.shared.windows[self.id1]?.rootViewController = UIHostingController(rootView: newContent)
239 | // self?.content = newContent // Trigger the content update when state changes
240 | }
241 | }
242 | }
243 |
244 | @MainActor
245 | public final class WindowManager {
246 | static let shared = WindowManager()
247 | var windows: [UUID: UIWindow] = [:]
248 |
249 | // Show a new window with hosted SwiftUI content
250 | public static func showInNewWindow(id: UUID, dismissClosure: @escaping ()->(), content: @escaping () -> Content) {
251 | guard let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
252 | print("No valid scene available")
253 | return
254 | }
255 |
256 | let window = UIPassthroughWindow(windowScene: scene)
257 | window.backgroundColor = .clear
258 |
259 | let controller = UIPassthroughVC(rootView: content()
260 | .environment(\.popupDismiss) {
261 | dismissClosure()
262 | })
263 | controller.view.backgroundColor = .clear
264 | window.rootViewController = controller
265 | window.windowLevel = .alert + 1
266 | window.makeKeyAndVisible()
267 |
268 | // Store window reference
269 | shared.windows[id] = window
270 | }
271 |
272 | static func closeWindow(id: UUID) {
273 | shared.windows[id]?.isHidden = true
274 | shared.windows.removeValue(forKey: id)
275 | }
276 | }
277 |
278 | class UIPassthroughWindow: UIWindow {
279 |
280 | override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
281 | if let vc = self.rootViewController {
282 | vc.view.layoutSubviews() // otherwise the frame is as if the popup is still outside the screen
283 | if let _ = isTouchInsideSubview(point: point, vc: vc.view) {
284 | // pass tap to this UIPassthroughVC
285 | return vc.view
286 | }
287 | }
288 | return nil // pass to next window
289 | }
290 |
291 | private func isTouchInsideSubview(point: CGPoint, vc: UIView) -> UIView? {
292 | for subview in vc.subviews {
293 | if subview.frame.contains(point) {
294 | return subview
295 | }
296 | }
297 | return nil
298 | }
299 | }
300 |
301 | class UIPassthroughVC: UIHostingController {
302 |
303 | override func touchesBegan(_ touches: Set, with event: UIEvent?) {
304 | // Check if any touch is inside one of the subviews, if so, ignore it
305 | if !isTouchInsideSubview(touches) {
306 | // If touch is not inside any subview, pass the touch to the next responder
307 | super.touchesBegan(touches, with: event)
308 | }
309 | }
310 |
311 | override func touchesMoved(_ touches: Set, with event: UIEvent?) {
312 | if !isTouchInsideSubview(touches) {
313 | super.touchesMoved(touches, with: event)
314 | }
315 | }
316 |
317 | override func touchesEnded(_ touches: Set, with event: UIEvent?) {
318 | if !isTouchInsideSubview(touches) {
319 | super.touchesEnded(touches, with: event)
320 | }
321 | }
322 |
323 | override func touchesCancelled(_ touches: Set, with event: UIEvent?) {
324 | if !isTouchInsideSubview(touches) {
325 | super.touchesCancelled(touches, with: event)
326 | }
327 | }
328 |
329 | // Helper function to determine if any touch is inside a subview
330 | private func isTouchInsideSubview(_ touches: Set) -> Bool {
331 | guard let touch = touches.first else {
332 | return false
333 | }
334 |
335 | let touchLocation = touch.location(in: self.view)
336 |
337 | // Iterate over all subviews to check if the touch is inside any of them
338 | for subview in self.view.subviews {
339 | if subview.frame.contains(touchLocation) {
340 | return true
341 | }
342 | }
343 | return false
344 | }
345 | }
346 | #endif
347 |
348 | // MARK: - KeyboardHeightHelper
349 |
350 | #if os(iOS)
351 |
352 | @MainActor
353 | class KeyboardHeightHelper: ObservableObject {
354 |
355 | @Published var keyboardHeight: CGFloat = 0
356 | @Published var keyboardDisplayed: Bool = false
357 |
358 | init() {
359 | NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardWillShowNotification), name: UIResponder.keyboardWillShowNotification, object: nil)
360 | NotificationCenter.default.addObserver(self, selector: #selector(onKeyboardWillHideNotification), name: UIResponder.keyboardWillHideNotification, object: nil)
361 | }
362 |
363 | deinit {
364 | NotificationCenter.default.removeObserver(self)
365 | }
366 |
367 | @objc private func onKeyboardWillShowNotification(_ notification: Notification) {
368 | guard let userInfo = notification.userInfo,
369 | let keyboardRect = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? CGRect else { return }
370 |
371 | DispatchQueue.main.async {
372 | self.keyboardHeight = keyboardRect.height
373 | self.keyboardDisplayed = true
374 | }
375 | }
376 |
377 | @objc private func onKeyboardWillHideNotification(_ notification: Notification) {
378 | DispatchQueue.main.async {
379 | self.keyboardHeight = 0
380 | self.keyboardDisplayed = false
381 | }
382 | }
383 | }
384 |
385 | #else
386 |
387 | class KeyboardHeightHelper: ObservableObject {
388 |
389 | @Published var keyboardHeight: CGFloat = 0
390 | @Published var keyboardDisplayed: Bool = false
391 | }
392 |
393 | #endif
394 |
395 |
396 | // MARK: - Hide keyboard
397 |
398 | extension CGPoint {
399 |
400 | @MainActor
401 | static var pointFarAwayFromScreen: CGPoint {
402 | CGPoint(x: 2*CGSize.screenSize.width, y: 2*CGSize.screenSize.height)
403 | }
404 | }
405 |
406 | extension CGSize {
407 |
408 | @MainActor
409 | static var screenSize: CGSize {
410 | #if os(iOS) || os(tvOS)
411 | return UIScreen.main.bounds.size
412 | #elseif os(watchOS)
413 | return WKInterfaceDevice.current().screenBounds.size
414 | #elseif os(macOS)
415 | return NSScreen.main?.frame.size ?? .zero
416 | #elseif os(visionOS)
417 | return .zero
418 | #endif
419 | }
420 | }
421 |
--------------------------------------------------------------------------------