├── .gitignore
├── .swiftpm
└── xcode
│ └── xcshareddata
│ └── xcschemes
│ ├── JudoSDK.xcscheme
│ └── JudoServiceTests.xcscheme
├── JudoSample
├── JudoSample.xcodeproj
│ ├── project.pbxproj
│ ├── project.xcworkspace
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata
│ │ │ ├── IDEWorkspaceChecks.plist
│ │ │ └── swiftpm
│ │ │ └── Package.resolved
│ └── xcshareddata
│ │ └── xcschemes
│ │ └── JudoSample.xcscheme
└── JudoSample
│ ├── AppDelegate.swift
│ ├── Assets.xcassets
│ ├── AccentColor.colorset
│ │ └── Contents.json
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── Contents.json
│ ├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
│ ├── Info.plist
│ ├── JudoSample.entitlements
│ ├── SceneDelegate.swift
│ ├── ViewController.swift
│ ├── ar.lproj
│ └── LaunchScreen.strings
│ ├── de.lproj
│ └── LaunchScreen.strings
│ ├── es.lproj
│ └── LaunchScreen.strings
│ ├── fr.lproj
│ └── LaunchScreen.strings
│ ├── he.lproj
│ └── LaunchScreen.strings
│ ├── hi.lproj
│ └── LaunchScreen.strings
│ ├── ja.lproj
│ └── LaunchScreen.strings
│ ├── ko.lproj
│ └── LaunchScreen.strings
│ ├── pl.lproj
│ └── LaunchScreen.strings
│ ├── zh-Hans.lproj
│ └── LaunchScreen.strings
│ └── zh-Hant.lproj
│ └── LaunchScreen.strings
├── LICENSE
├── Package.resolved
├── Package.swift
├── README.md
├── Sources
├── JudoModel
│ ├── CodingUserInfoKey.swift
│ ├── DecodingCoordinator.swift
│ ├── Experience.swift
│ ├── Extensions
│ │ ├── CGPoint+Hashable.swift
│ │ ├── Error+debugDescription.swift
│ │ ├── JSONSerialization+valueForKeyPath.swift
│ │ ├── KeyedDecodingContainer+nodes.swift
│ │ ├── NSRegularExpression+utils.swift
│ │ └── OSLog+JudoModel.swift
│ ├── Node.swift
│ ├── Nodes
│ │ ├── Audio.swift
│ │ ├── Carousel.swift
│ │ ├── Collection.swift
│ │ ├── Conditional.swift
│ │ ├── DataSource.swift
│ │ ├── Divider.swift
│ │ ├── HStack.swift
│ │ ├── Icon.swift
│ │ ├── Image.swift
│ │ ├── Layer.swift
│ │ ├── NavBar.swift
│ │ ├── NavBarButton.swift
│ │ ├── PageControl.swift
│ │ ├── Rectangle.swift
│ │ ├── Screen.swift
│ │ ├── ScrollContainer.swift
│ │ ├── Spacer.swift
│ │ ├── Text.swift
│ │ ├── VStack.swift
│ │ ├── Video.swift
│ │ ├── WebView.swift
│ │ └── ZStack.swift
│ └── Value Types
│ │ ├── Accessibility.swift
│ │ ├── Action.swift
│ │ ├── BackButtonStyle.swift
│ │ ├── Background.swift
│ │ ├── Border.swift
│ │ ├── Color.swift
│ │ ├── ColorVariants.swift
│ │ ├── Condition.swift
│ │ ├── DynamicGradient.swift
│ │ ├── Fill.swift
│ │ ├── Font.swift
│ │ ├── FontResource.swift
│ │ ├── Frame.swift
│ │ ├── Gradient.swift
│ │ ├── GradientVariants.swift
│ │ ├── Metadata.swift
│ │ ├── ModalPresentationStyle.swift
│ │ ├── NamedIcon.swift
│ │ ├── Overlay.swift
│ │ ├── Padding.swift
│ │ ├── SegueStyle.swift
│ │ ├── Shadow.swift
│ │ ├── StatusBarStyle.swift
│ │ ├── StringTable.swift
│ │ └── SwiftUIValues.swift
└── JudoSDK
│ ├── Analytics.swift
│ ├── AssetsDownloader.swift
│ ├── Configuration.swift
│ ├── DownloadService.swift
│ ├── Events.swift
│ ├── ExperienceViewController.swift
│ ├── Extensions
│ ├── Collection+items.swift
│ ├── Condition+isSatisfied.swift
│ ├── Error+debugDescription.swift
│ ├── Node+hierarchy.swift
│ ├── OSLog+JudoSDK.swift
│ ├── String+interpolation.swift
│ ├── StringTable+resolve.swift
│ ├── UIApplication+present.swift
│ ├── UIControl+action.swift
│ ├── URL+API.swift
│ ├── URL+cache.swift
│ ├── URLSession+Result.swift
│ └── URLSession+dataPublisher.swift
│ ├── Judo.swift
│ ├── JudoRepository.swift
│ ├── MainQueue.swift
│ ├── Meta.swift
│ ├── Model
│ └── ViewID.swift
│ ├── RecoverableError.swift
│ ├── Resources
│ └── en.lproj
│ │ └── Localizable.strings
│ ├── UI
│ ├── CarouselState.swift
│ ├── EnvironmentValues+Judo.swift
│ ├── ImageFetcher.swift
│ ├── Model
│ │ ├── Action+handler.swift
│ │ ├── Color+named.swift
│ │ ├── Color+uiValues.swift
│ │ ├── ColorVariants+uikit.swift
│ │ ├── Font+uikit.swift
│ │ ├── Gradient+swiftUI.swift
│ │ ├── RealizeColor.swift
│ │ └── UIColor+named.swift
│ ├── Modifiers
│ │ ├── AccessibilityModifier.swift
│ │ ├── ActionModifier.swift
│ │ ├── AspectRatioModifier.swift
│ │ ├── BackgroundModifier.swift
│ │ ├── FontModifier.swift
│ │ ├── FrameModifier.swift
│ │ ├── IgnoresSafeAreaModifier.swift
│ │ ├── LayoutPriorityModifier.swift
│ │ ├── MaskModifier.swift
│ │ ├── OffsetModifier.swift
│ │ ├── OpacityModifier.swift
│ │ ├── OverlayModifier.swift
│ │ ├── PaddingModifier.swift
│ │ └── ShadowModifier.swift
│ ├── NavBarViewController.swift
│ ├── ScreenViewController.swift
│ ├── UIKitExtensions.swift
│ └── Views
│ │ ├── AnimatedImage.swift
│ │ ├── AudioView.swift
│ │ ├── CarouselView.swift
│ │ ├── CollectionView.swift
│ │ ├── ConditionalView.swift
│ │ ├── DataSourceView.swift
│ │ ├── DividerView.swift
│ │ ├── HStackView.swift
│ │ ├── IconView.swift
│ │ ├── ImageView.swift
│ │ ├── LayerView.swift
│ │ ├── PageControlView.swift
│ │ ├── RectangleView.swift
│ │ ├── ScrollContainerView.swift
│ │ ├── TextView.swift
│ │ ├── VStackView.swift
│ │ ├── VideoView.swift
│ │ ├── WebViewView.swift
│ │ └── ZStackView.swift
│ └── Vendor
│ ├── Introspect.swift
│ ├── JSON.swift
│ └── UIImage+Blurhash.swift
└── Tests
└── JudoServiceTests
├── AuthorizationTests.swift
├── ClipServiceTest.swift
├── JSONSerializationTests.swift
└── StringInterpolationTests.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | /.build
3 | /Packages
4 | xcuserdata/
5 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/xcshareddata/xcschemes/JudoSDK.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
44 |
50 |
51 |
57 |
58 |
59 |
60 |
62 |
63 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/xcshareddata/xcschemes/JudoServiceTests.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
14 |
15 |
17 |
23 |
24 |
25 |
26 |
27 |
37 |
38 |
44 |
45 |
47 |
48 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "Mocker",
6 | "repositoryURL": "https://github.com/WeTransfer/Mocker",
7 | "state": {
8 | "branch": null,
9 | "revision": "8ff37ffda243669ba7827f639f91f99b53fa4b49",
10 | "version": null
11 | }
12 | }
13 | ]
14 | },
15 | "version": 1
16 | }
17 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample.xcodeproj/xcshareddata/xcschemes/JudoSample.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
43 |
45 |
51 |
52 |
53 |
54 |
60 |
62 |
68 |
69 |
70 |
71 |
73 |
74 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/Assets.xcassets/AccentColor.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "colors" : [
3 | {
4 | "idiom" : "universal"
5 | }
6 | ],
7 | "info" : {
8 | "author" : "xcode",
9 | "version" : 1
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/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 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "author" : "xcode",
4 | "version" : 1
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | BGTaskSchedulerPermittedIdentifiers
6 |
7 | app.judo.background.refresh
8 |
9 | CFBundleDevelopmentRegion
10 | $(DEVELOPMENT_LANGUAGE)
11 | CFBundleExecutable
12 | $(EXECUTABLE_NAME)
13 | CFBundleIdentifier
14 | $(PRODUCT_BUNDLE_IDENTIFIER)
15 | CFBundleInfoDictionaryVersion
16 | 6.0
17 | CFBundleName
18 | $(PRODUCT_NAME)
19 | CFBundlePackageType
20 | $(PRODUCT_BUNDLE_PACKAGE_TYPE)
21 | CFBundleShortVersionString
22 | 1.0
23 | CFBundleURLTypes
24 |
25 |
26 | CFBundleTypeRole
27 | Viewer
28 | CFBundleURLName
29 | app.judo.SampleApp
30 | CFBundleURLSchemes
31 |
32 | myapp
33 |
34 |
35 |
36 | CFBundleVersion
37 | 1
38 | LSRequiresIPhoneOS
39 |
40 | UIApplicationSceneManifest
41 |
42 | UIApplicationSupportsMultipleScenes
43 |
44 | UISceneConfigurations
45 |
46 | UIWindowSceneSessionRoleApplication
47 |
48 |
49 | UISceneConfigurationName
50 | Default Configuration
51 | UISceneDelegateClassName
52 | $(PRODUCT_MODULE_NAME).SceneDelegate
53 | UISceneStoryboardFile
54 | Main
55 |
56 |
57 |
58 |
59 | UIApplicationSupportsIndirectInputEvents
60 |
61 | UIBackgroundModes
62 |
63 | fetch
64 | remote-notification
65 |
66 | UILaunchStoryboardName
67 | LaunchScreen
68 | UIMainStoryboardFile
69 | Main
70 | UIRequiredDeviceCapabilities
71 |
72 | armv7
73 |
74 | UISupportedInterfaceOrientations
75 |
76 | UIInterfaceOrientationPortrait
77 | UIInterfaceOrientationLandscapeLeft
78 | UIInterfaceOrientationLandscapeRight
79 |
80 | UISupportedInterfaceOrientations~ipad
81 |
82 | UIInterfaceOrientationPortrait
83 | UIInterfaceOrientationPortraitUpsideDown
84 | UIInterfaceOrientationLandscapeLeft
85 | UIInterfaceOrientationLandscapeRight
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/JudoSample.entitlements:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | aps-environment
6 | development
7 | com.apple.developer.associated-domains
8 |
9 | applinks:myapp.judo.app
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/SceneDelegate.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import UIKit
17 | import JudoSDK
18 | import os.log
19 |
20 | @available(iOS 13.0, *)
21 | class SceneDelegate: UIResponder, UIWindowSceneDelegate {
22 |
23 | var window: UIWindow?
24 |
25 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
26 | if let userActivity = connectionOptions.userActivities.first {
27 | Judo.sharedInstance.continueUserActivity(userActivity, animated: false)
28 | } else if let urlContext = connectionOptions.urlContexts.first {
29 | Judo.sharedInstance.openURL(urlContext.url, animated: false)
30 | }
31 | }
32 |
33 | func scene(_ scene: UIScene, openURLContexts URLContexts: Set) {
34 | if let context = URLContexts.first {
35 | Judo.sharedInstance.openURL(context.url, animated: true)
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/ViewController.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import UIKit
17 | //import JudoModel
18 | import JudoSDK
19 |
20 | class ViewController: UIViewController {
21 | @IBAction func presentExperience(_ sender: Any) {
22 | let url = URL(string: "")!
23 | Judo.sharedInstance.openURL(url, animated: true)
24 | }
25 |
26 | @IBAction func identify(_ sender: Any) {
27 | // Pass user ID and custom properties to Judo for personalization
28 | struct UserTraits: Codable {
29 | let name: String
30 | let pointsBalance: Int
31 | let premiumTier: Bool
32 | let tags: [String]
33 | }
34 |
35 | Judo.sharedInstance.identify(
36 | userID: "john@example.com",
37 | traits: UserTraits(
38 | name: "John Doe",
39 | pointsBalance: 50_000,
40 | premiumTier: true,
41 | tags: ["foo", "bar", "baz"]
42 | )
43 | )
44 | }
45 |
46 | @IBAction func reset(_ sender: Any) {
47 | // Clear user ID and custom properties
48 | Judo.sharedInstance.reset()
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/ar.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/de.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/es.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/fr.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/he.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/hi.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/ja.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/ko.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/pl.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/zh-Hans.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/JudoSample/JudoSample/zh-Hant.lproj/LaunchScreen.strings:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | copy, modify, and distribute this software in source code or binary form for use
4 | in connection with the web services and APIs provided by Rover.
5 |
6 | This copyright notice shall be included in all copies or substantial portions of
7 | the software.
8 |
9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
--------------------------------------------------------------------------------
/Package.resolved:
--------------------------------------------------------------------------------
1 | {
2 | "object": {
3 | "pins": [
4 | {
5 | "package": "Mocker",
6 | "repositoryURL": "https://github.com/WeTransfer/Mocker",
7 | "state": {
8 | "branch": null,
9 | "revision": "8ff37ffda243669ba7827f639f91f99b53fa4b49",
10 | "version": null
11 | }
12 | }
13 | ]
14 | },
15 | "version": 1
16 | }
17 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.3
2 |
3 | import PackageDescription
4 |
5 | let package = Package(
6 | name: "JudoSDK",
7 | defaultLocalization: "en",
8 | platforms: [
9 | .iOS(.v11)
10 | ],
11 | products: [
12 | .library(
13 | name: "JudoSDK",
14 | // TODO: consider commenting `type: .dynamic` before public release. it's here to use Xcode Previews in Sample app, to work around an Xcode bug.
15 | // type: .dynamic,
16 | targets: ["JudoSDK", "JudoModel"]
17 | )
18 | ],
19 | dependencies: [
20 | .package(url: "https://github.com/WeTransfer/Mocker", .revision("8ff37ffda243669ba7827f639f91f99b53fa4b49"))
21 | ],
22 | targets: [
23 | .target(
24 | name: "JudoSDK",
25 | dependencies: ["JudoModel"],
26 | resources: [.process("Resources")]
27 | ),
28 | .target(
29 | name: "JudoModel"
30 | ),
31 | .testTarget(
32 | name: "JudoServiceTests",
33 | dependencies: ["JudoSDK", "Mocker"]
34 | )
35 | ]
36 | )
37 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DEPRECATED
2 | This SDK is no longer maintained. It has been replaced with the Judo SwiftUI SDK: https://github.com/judoapp/judo-swiftui.
3 |
4 | [](http://unmaintained.tech/)
5 |
--------------------------------------------------------------------------------
/Sources/JudoModel/CodingUserInfoKey.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | extension CodingUserInfoKey {
19 | static let decodingCoordinator = CodingUserInfoKey(rawValue: "decodingCoordinator")!
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Experience.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public struct Experience: Decodable {
19 | public enum Appearance: String, Decodable {
20 | case light
21 | case dark
22 | case auto
23 | }
24 |
25 | /// A unique identifier for the Experience.
26 | public let id: String
27 | public let name: String
28 | public let revisionID: String
29 | /// A set of nodes contained in the document. Use `initialScreenID` to determine the initial node to render.
30 | public let nodes: [Node]
31 | public let localization: StringTable
32 | /// Fonts download URLs
33 | public let fonts: [URL]
34 | /// The ID of the initial node to render.
35 | public let initialScreenID: Screen.ID
36 | public let appearance: Appearance
37 |
38 | public init(id: String, name: String, revisionID: String, nodes: [Node], localization: StringTable, fonts: [URL], initialScreenID: Screen.ID, appearance: Appearance) {
39 | self.id = id
40 | self.name = name
41 | self.revisionID = revisionID
42 | self.nodes = nodes
43 | self.initialScreenID = initialScreenID
44 | self.localization = localization
45 | self.fonts = fonts
46 | self.appearance = appearance
47 | }
48 |
49 | /// Initialize Experience from data (JSON)
50 | /// - Parameter data: Experience data.
51 | /// - Throws: Throws error on failure.
52 | public init(decode data: Data) throws {
53 | let decoder = JSONDecoder()
54 | let coordinator = DecodingCoordinator()
55 | decoder.userInfo[.decodingCoordinator] = coordinator
56 | self = try decoder.decode(Self.self, from: data)
57 | }
58 |
59 | enum CodingKeys: String, CodingKey {
60 | case id
61 | case name
62 | case revisionID
63 | case nodes
64 | case fonts
65 | case initialScreenID
66 | case localization
67 | case appearance
68 | }
69 |
70 | public init(from decoder: Decoder) throws {
71 | let container = try decoder.container(keyedBy: CodingKeys.self)
72 |
73 | let id = try container.decode(String.self, forKey: .id)
74 | let revisionID = try container.decode(String.self, forKey: .revisionID)
75 | let name = try container.decode(String.self, forKey: .name)
76 | let initialScreenID = try container.decode(String.self, forKey: .initialScreenID)
77 | let localization = try container.decode(StringTable.self, forKey: .localization)
78 | let fonts = try container.decode([FontResource].self, forKey: .fonts)
79 |
80 | let coordinator = decoder.userInfo[.decodingCoordinator] as! DecodingCoordinator
81 |
82 | let nodes = try container.decodeNodes(forKey: .nodes)
83 | coordinator.resolveRelationships(nodes: nodes)
84 |
85 | let fontURLs = fonts.map { $0.url }
86 | let appearance = try container.decode(Appearance.self, forKey: .appearance)
87 | self.init(id: id, name: name, revisionID: revisionID, nodes: nodes, localization: localization, fonts: fontURLs, initialScreenID: initialScreenID, appearance: appearance)
88 | }
89 | }
90 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Extensions/CGPoint+Hashable.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 |
18 | extension CGPoint: Hashable {
19 | public func hash(into hasher: inout Hasher) {
20 | hasher.combine(x)
21 | hasher.combine(y)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Extensions/Error+debugDescription.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | extension Error {
19 | /// Get a string giving a much more comprehensive explanation of the error, particularly when coming from certain platform types (Codable, in particular).
20 | var debugDescription: String {
21 | return "Error: \(self.localizedDescription), details: \((self as NSError).userInfo.debugDescription)"
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Extensions/NSRegularExpression+utils.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | extension NSRegularExpression {
4 | func matches(_ string: String) -> Bool {
5 | let range = NSRange(location: 0, length: string.utf16.count)
6 | return firstMatch(in: string, range: range) != nil
7 | }
8 |
9 | func matches(in string: String, options: NSRegularExpression.MatchingOptions = []) -> [NSTextCheckingResult] {
10 | let range = NSRange(location: 0, length: string.utf16.count)
11 | return matches(in: string, options: options, range: range)
12 | }
13 |
14 | func matches(in string: String, groupIndex: Int) -> String? {
15 | guard let result = matches(in: string).first else {
16 | return nil
17 | }
18 |
19 | guard let range = Range(result.range(at: groupIndex), in: string) else {
20 | return nil
21 | }
22 | return String(string[range])
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Extensions/OSLog+JudoModel.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import os.log
18 |
19 | private var _judoLog = OSLog(subsystem: "app.judo.JudoSDK", category: "JudoModel")
20 |
21 | extension OSLog {
22 | static var judoLog: OSLog { _judoLog }
23 | }
24 |
25 | private func judoLoggingEnabled() -> Bool {
26 | ProcessInfo.processInfo.environment["JUDO_VERBOSE"] != nil
27 | }
28 |
29 | func judo_log(_ type: OSLogType, _ message: StaticString, _ args: CVarArg...) {
30 | guard judoLoggingEnabled() || type == .error else {
31 | return
32 | }
33 |
34 | // lack of splat means this mess:
35 | switch args.count {
36 | case 0:
37 | os_log(message, log: .judoLog, type: type)
38 | case 1:
39 | os_log(message, log: .judoLog, type: type, args[0])
40 | case 2:
41 | os_log(message, log: .judoLog, type: type, args[0], args[1])
42 | case 3:
43 | os_log(message, log: .judoLog, type: type, args[0], args[1], args[2])
44 | case 4:
45 | os_log(message, log: .judoLog, type: type, args[0], args[1], args[2], args[3])
46 | case 5:
47 | os_log(message, log: .judoLog, type: type, args[0], args[1], args[2], args[3], args[4])
48 | default:
49 | os_log(message, log: .judoLog, type: type, args[0], args[1], args[2], args[3], args[4], args[5])
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Audio.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 |
17 | import CoreGraphics
18 | import Foundation
19 |
20 | public class Audio: Layer {
21 |
22 | /// Audio URL
23 | public let sourceURL: String
24 |
25 | /// When true the audio will begin playing when the Screen is displayed.
26 | public let autoPlay: Bool
27 |
28 | /// When true the video will loop.
29 | public let looping: Bool
30 |
31 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, sourceURL: String, autoPlay: Bool, looping: Bool) {
32 | self.sourceURL = sourceURL
33 | self.autoPlay = autoPlay
34 | self.looping = looping
35 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
36 | }
37 |
38 | private enum CodingKeys: String, CodingKey {
39 | case sourceURL
40 | case autoPlay
41 | case looping
42 | }
43 |
44 | required init(from decoder: Decoder) throws {
45 | let container = try decoder.container(keyedBy: CodingKeys.self)
46 | sourceURL = try container.decode(String.self, forKey: .sourceURL)
47 | autoPlay = try container.decode(Bool.self, forKey: .autoPlay)
48 | looping = try container.decode(Bool.self, forKey: .looping)
49 | try super.init(from: decoder)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Carousel.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class Carousel: Layer {
20 | /// Indicates whether the Carousel continually wraps around to the first/last elements as you scroll.
21 | public let isLoopEnabled: Bool
22 |
23 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, isLoopEnabled: Bool) {
24 | self.isLoopEnabled = isLoopEnabled
25 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
26 | }
27 |
28 | // MARK: Decodable
29 |
30 | private enum CodingKeys: String, CodingKey {
31 | case isLoopEnabled
32 | }
33 |
34 | required init(from decoder: Decoder) throws {
35 | let container = try decoder.container(keyedBy: CodingKeys.self)
36 | isLoopEnabled = try container.decode(Bool.self, forKey: .isLoopEnabled)
37 | try super.init(from: decoder)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Collection.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class Collection: Layer {
20 | public struct SortDescriptor: Decodable {
21 | public var keyPath: String
22 | public var ascending: Bool
23 |
24 | public init(keyPath: String, ascending: Bool = true) {
25 | self.keyPath = keyPath
26 | self.ascending = ascending
27 | }
28 | }
29 |
30 | public struct Limit: Decodable {
31 | public var show: Int
32 | public var startAt: Int
33 |
34 | public init(show: Int, startAt: Int) {
35 | self.show = show
36 | self.startAt = startAt
37 | }
38 | }
39 |
40 | public let keyPath: String
41 | public let filters: [Condition]
42 | public let sortDescriptors: [SortDescriptor]
43 | public let limit: Limit?
44 |
45 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, keyPath: String, filters: [Condition] = [], sortDescriptors: [SortDescriptor] = [], limit: Limit? = nil) {
46 | self.keyPath = keyPath
47 | self.filters = filters
48 | self.sortDescriptors = sortDescriptors
49 | self.limit = limit
50 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
51 | }
52 |
53 | // MARK: Decodable
54 |
55 | private enum CodingKeys: String, CodingKey {
56 | case keyPath
57 | case filters
58 | case sortDescriptors
59 | case limit
60 | }
61 |
62 | required init(from decoder: Decoder) throws {
63 | let container = try decoder.container(keyedBy: CodingKeys.self)
64 | keyPath = try container.decode(String.self, forKey: .keyPath)
65 | filters = try container.decode([Condition].self, forKey: .filters)
66 | sortDescriptors = try container.decode([SortDescriptor].self, forKey: .sortDescriptors)
67 | limit = try container.decodeIfPresent(Limit.self, forKey: .limit)
68 | try super.init(from: decoder)
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Conditional.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class Conditional: Layer {
20 | public let conditions: [Condition]
21 |
22 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, conditions: [Condition] = []) {
23 | self.conditions = conditions
24 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
25 | }
26 |
27 | // MARK: Decodable
28 |
29 | private enum CodingKeys: String, CodingKey {
30 | case conditions
31 | }
32 |
33 | required init(from decoder: Decoder) throws {
34 | let container = try decoder.container(keyedBy: CodingKeys.self)
35 | conditions = try container.decode([Condition].self, forKey: .conditions)
36 | try super.init(from: decoder)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/DataSource.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import Combine
18 |
19 | public class DataSource: Layer, ObservableObject {
20 | public enum HTTPMethod: String, Codable, CaseIterable {
21 | case get = "GET"
22 | case post = "POST"
23 | case put = "PUT"
24 | }
25 |
26 | public struct Header: Codable, Hashable {
27 | public var key: String
28 | public var value: String
29 |
30 | public init(key: String, value: String) {
31 | self.key = key
32 | self.value = value
33 | }
34 | }
35 |
36 | public let url: String
37 | public let httpMethod: HTTPMethod
38 | public let httpBody: String?
39 | public let headers: [Header]
40 | public let pollInterval: Int?
41 |
42 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, url: String, httpMethod: HTTPMethod = .get, httpBody: String? = nil, headers: [Header], pollInterval: Int?) {
43 | self.url = url
44 | self.httpMethod = httpMethod
45 | self.httpBody = httpBody
46 | self.headers = headers
47 | self.pollInterval = pollInterval
48 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
49 | }
50 |
51 | // MARK: Decodable
52 |
53 | private enum CodingKeys: String, CodingKey {
54 | case url
55 | case httpMethod
56 | case httpBody
57 | case headers
58 | case pollInterval
59 | }
60 |
61 | required init(from decoder: Decoder) throws {
62 | let container = try decoder.container(keyedBy: CodingKeys.self)
63 | url = try container.decode(String.self, forKey: .url)
64 | httpMethod = try container.decode(HTTPMethod.self, forKey: .httpMethod)
65 | httpBody = try container.decodeIfPresent(String.self, forKey: .httpBody)
66 | headers = try container.decode([Header].self, forKey: .headers)
67 | pollInterval = try container.decodeIfPresent(Int.self, forKey: .pollInterval)
68 | try super.init(from: decoder)
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Divider.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class Divider: Layer {
20 | public let backgroundColor: ColorVariants
21 |
22 | // MARK: Decodable
23 |
24 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, backgroundColor: ColorVariants) {
25 | self.backgroundColor = backgroundColor
26 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
27 | }
28 |
29 | private enum CodingKeys: String, CodingKey {
30 | case backgroundColor
31 | }
32 |
33 | required init(from decoder: Decoder) throws {
34 | let container = try decoder.container(keyedBy: CodingKeys.self)
35 | backgroundColor = try container.decode(ColorVariants.self, forKey: .backgroundColor)
36 | try super.init(from: decoder)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/HStack.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class HStack: Layer {
20 | public let alignment: VerticalAlignment
21 | /// The gap that should be placed between each item in the stack.
22 | public let spacing: CGFloat
23 |
24 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, alignment: VerticalAlignment, spacing: CGFloat) {
25 | self.alignment = alignment
26 | self.spacing = spacing
27 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
28 | }
29 |
30 | // MARK: Decodable
31 |
32 | private enum CodingKeys: String, CodingKey {
33 | case alignment
34 | case spacing
35 | }
36 |
37 | required init(from decoder: Decoder) throws {
38 | let container = try decoder.container(keyedBy: CodingKeys.self)
39 | alignment = try container.decode(VerticalAlignment.self, forKey: .alignment)
40 | spacing = try container.decode(CGFloat.self, forKey: .spacing)
41 | try super.init(from: decoder)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Icon.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class Icon: Layer {
20 | public let icon: NamedIcon
21 | public let pointSize: Int
22 | public let color: ColorVariants
23 |
24 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, icon: NamedIcon, size: Int, color: ColorVariants) {
25 | self.icon = icon
26 | self.pointSize = size
27 | self.color = color
28 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
29 | }
30 |
31 | // MARK: Decodable
32 |
33 | private enum CodingKeys: String, CodingKey {
34 | case icon
35 | case pointSize
36 | case color
37 | }
38 |
39 | required public init(from decoder: Decoder) throws {
40 | let container = try decoder.container(keyedBy: CodingKeys.self)
41 | icon = try container.decode(NamedIcon.self, forKey: .icon)
42 | color = try container.decode(ColorVariants.self, forKey: .color)
43 | pointSize = try container.decode(Int.self, forKey: .pointSize)
44 | try super.init(from: decoder)
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Layer.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | public class Layer: Node {
17 | //
18 | }
19 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/NavBarButton.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class NavBarButton: Node {
20 | public enum Placement: String, Codable {
21 | case leading
22 | case trailing
23 | }
24 |
25 | public enum Style: String, Codable {
26 | case custom
27 | case done
28 | case close
29 | }
30 |
31 | public let placement: Placement
32 | public let style: Style
33 | public let title: String?
34 | public let icon: NamedIcon?
35 |
36 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, placement: Placement, style: Style, title: String?, icon: NamedIcon?) {
37 |
38 | self.placement = placement
39 | self.style = style
40 | self.title = title
41 | self.icon = icon
42 |
43 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
44 | }
45 |
46 | // MARK: Decodable
47 |
48 | private enum CodingKeys: String, CodingKey {
49 | case placement
50 | case style
51 | case title
52 | case icon
53 | }
54 |
55 | required init(from decoder: Decoder) throws {
56 | let container = try decoder.container(keyedBy: CodingKeys.self)
57 | placement = try container.decode(Placement.self, forKey: .placement)
58 | style = try container.decode(Style.self, forKey: .style)
59 | title = try container.decodeIfPresent(String.self, forKey: .title)
60 | icon = try container.decodeIfPresent(NamedIcon.self, forKey: .icon)
61 | try super.init(from: decoder)
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Rectangle.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class Rectangle: Layer {
20 | public let fill: Fill
21 | public let border: Border?
22 | public let cornerRadius: Int
23 |
24 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, fill: Fill, border: Border?, cornerRadius: Int) {
25 | self.fill = fill
26 | self.border = border
27 | self.cornerRadius = cornerRadius
28 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
29 | }
30 |
31 | // MARK: Decodable
32 |
33 | private enum CodingKeys: String, CodingKey {
34 | case fill
35 | case border
36 | case cornerRadius
37 | }
38 |
39 | required init(from decoder: Decoder) throws {
40 | let container = try decoder.container(keyedBy: CodingKeys.self)
41 | fill = try container.decode(Fill.self, forKey: .fill)
42 | border = try container.decodeIfPresent(Border.self, forKey: .border)
43 | cornerRadius = try container.decodeIfPresent(Int.self, forKey: .cornerRadius) ?? 0
44 |
45 | try super.init(from: decoder)
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Screen.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class Screen: Node {
20 | public let statusBarStyle: StatusBarStyle
21 | public let backButtonStyle: BackButtonStyle
22 | public let backgroundColor: ColorVariants
23 |
24 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, statusBarStyle: StatusBarStyle, backButtonStyle: BackButtonStyle, backgroundColor: ColorVariants) {
25 |
26 | self.statusBarStyle = statusBarStyle
27 | self.backButtonStyle = backButtonStyle
28 | self.backgroundColor = backgroundColor
29 |
30 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
31 | }
32 |
33 | // MARK: Decodable
34 |
35 | private enum CodingKeys: String, CodingKey {
36 | case statusBarStyle
37 | case backButtonStyle
38 | case backgroundColor
39 | }
40 |
41 | required init(from decoder: Decoder) throws {
42 | let container = try decoder.container(keyedBy: CodingKeys.self)
43 | statusBarStyle = try container.decode(StatusBarStyle.self, forKey: .statusBarStyle)
44 | backButtonStyle = try container.decode(BackButtonStyle.self, forKey: .backButtonStyle)
45 | backgroundColor = try container.decode(ColorVariants.self, forKey: .backgroundColor)
46 | try super.init(from: decoder)
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/ScrollContainer.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class ScrollContainer: Layer {
20 | /// Indicates the scroll direction.
21 | public let axis: Axis
22 | /// When true the scroll container will not display the scroll bar indicating the user's current scroll position.
23 | public let disableScrollBar: Bool
24 |
25 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, axis: Axis, disableScrollBar: Bool) {
26 | self.axis = axis
27 | self.disableScrollBar = disableScrollBar
28 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
29 | }
30 |
31 | // MARK: Decodable
32 |
33 | private enum CodingKeys: String, CodingKey {
34 | case axis
35 | case disableScrollBar
36 | }
37 |
38 | required init(from decoder: Decoder) throws {
39 | let container = try decoder.container(keyedBy: CodingKeys.self)
40 | axis = try container.decode(Axis.self, forKey: .axis)
41 | disableScrollBar = try container.decode(Bool.self, forKey: .disableScrollBar)
42 | try super.init(from: decoder)
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Spacer.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public final class Spacer: Layer {
19 | //
20 | }
21 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Text.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class Text: Layer {
20 | public enum Transform: String, Codable {
21 | case uppercase
22 | case lowercase
23 | }
24 | /// The text content to render.
25 | public let text: String
26 | public let font: Font
27 | public let textColor: ColorVariants
28 | /// The alignment behavior of the Text.
29 | public let textAlignment: TextAlignment
30 | public let lineLimit: Int?
31 | public let transform: Transform?
32 |
33 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, text: String, font: Font, textColor: ColorVariants, textAlignment: TextAlignment, lineLimit: Int?, transform: Text.Transform?) {
34 | self.text = text
35 | self.font = font
36 | self.textColor = textColor
37 | self.textAlignment = textAlignment
38 | self.lineLimit = lineLimit
39 | self.transform = transform
40 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
41 | }
42 |
43 | // MARK: Decodable
44 |
45 | private enum CodingKeys: String, CodingKey {
46 | case text
47 | case font
48 | case textColor
49 | case textAlignment
50 | case lineLimit
51 | case transform
52 | }
53 |
54 | required init(from decoder: Decoder) throws {
55 | let container = try decoder.container(keyedBy: CodingKeys.self)
56 | text = try container.decode(String.self, forKey: .text)
57 | font = try container.decode(Font.self, forKey: .font)
58 | textColor = try container.decode(ColorVariants.self, forKey: .textColor)
59 | textAlignment = try container.decode(TextAlignment.self, forKey: .textAlignment)
60 | lineLimit = try container.decodeIfPresent(Int.self, forKey: .lineLimit)
61 | transform = try container.decodeIfPresent(Transform.self, forKey: .transform)
62 | try super.init(from: decoder)
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/VStack.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class VStack: Layer {
20 | public let alignment: HorizontalAlignment
21 | /// The gap that should be placed between each item in the stack.
22 | public let spacing: CGFloat
23 |
24 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, alignment: HorizontalAlignment, spacing: CGFloat) {
25 | self.alignment = alignment
26 | self.spacing = spacing
27 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
28 | }
29 |
30 | // MARK: Decodable
31 |
32 | private enum CodingKeys: String, CodingKey {
33 | case alignment
34 | case spacing
35 | }
36 |
37 | required init(from decoder: Decoder) throws {
38 | let container = try decoder.container(keyedBy: CodingKeys.self)
39 | alignment = try container.decode(HorizontalAlignment.self, forKey: .alignment)
40 | spacing = try container.decode(CGFloat.self, forKey: .spacing)
41 | try super.init(from: decoder)
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/Video.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public class Video: Layer {
20 |
21 | public enum ResizingMode: String, Decodable {
22 | case scaleToFit
23 | case scaleToFill
24 | }
25 |
26 | /// Video URL
27 | public let sourceURL: String
28 |
29 | /// Poster image URL
30 | public let posterImageURL: String?
31 |
32 | /// Resizing mode
33 | public let resizingMode: ResizingMode
34 |
35 | /// When true the media player shown in the Judo layer will feature playback/transport controls.
36 | public let showControls: Bool
37 |
38 | /// When true the video will begin playing when the Screen is displayed.
39 | public let autoPlay: Bool
40 |
41 | /// When true the video will loop.
42 | public let looping: Bool
43 |
44 | /// When true audio track is inhibited from playback.
45 | public let removeAudio: Bool
46 |
47 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, sourceURL: String, posterImageURL: String?, resizingMode: ResizingMode, showControls: Bool, autoPlay: Bool, looping: Bool, removeAudio: Bool) {
48 | self.sourceURL = sourceURL
49 | self.posterImageURL = posterImageURL
50 | self.resizingMode = resizingMode
51 | self.showControls = showControls
52 | self.autoPlay = autoPlay
53 | self.looping = looping
54 | self.removeAudio = removeAudio
55 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
56 | }
57 |
58 | private enum CodingKeys: String, CodingKey {
59 | case sourceURL
60 | case posterImageURL
61 | case resizingMode
62 | case showControls
63 | case autoPlay
64 | case looping
65 | case removeAudio
66 | }
67 |
68 | required init(from decoder: Decoder) throws {
69 | let container = try decoder.container(keyedBy: CodingKeys.self)
70 | sourceURL = try container.decode(String.self, forKey: .sourceURL)
71 | posterImageURL = try container.decodeIfPresent(String.self, forKey: .posterImageURL)
72 | resizingMode = try container.decode(ResizingMode.self, forKey: .resizingMode)
73 | showControls = try container.decode(Bool.self, forKey: .showControls)
74 | autoPlay = try container.decode(Bool.self, forKey: .autoPlay)
75 | looping = try container.decode(Bool.self, forKey: .looping)
76 | removeAudio = try container.decode(Bool.self, forKey: .removeAudio)
77 | try super.init(from: decoder)
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/WebView.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class WebView: Layer {
20 | public enum Source: Equatable {
21 | case url(String)
22 | case html(String)
23 | }
24 |
25 | public let source: Source
26 | public let isScrollEnabled: Bool
27 |
28 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, source: Source, isScrollEnabled: Bool) {
29 | self.source = source
30 | self.isScrollEnabled = isScrollEnabled
31 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
32 | }
33 |
34 | // MARK: Decodable
35 |
36 | private enum CodingKeys: String, CodingKey {
37 | case source
38 | case isScrollEnabled
39 | }
40 |
41 | required init(from decoder: Decoder) throws {
42 | let container = try decoder.container(keyedBy: CodingKeys.self)
43 | source = try container.decode(Source.self, forKey: .source)
44 | isScrollEnabled = try container.decode(Bool.self, forKey: .isScrollEnabled)
45 |
46 | try super.init(from: decoder)
47 | }
48 | }
49 |
50 | extension WebView.Source: Decodable {
51 | private enum CodingKeys: String, CodingKey {
52 | case typeName = "__typeName"
53 | case value
54 | }
55 |
56 | public init(from decoder: Decoder) throws {
57 | let container = try decoder.container(keyedBy: CodingKeys.self)
58 | let typeName = try container.decode(String.self, forKey: .typeName)
59 | let value = try container.decode(String.self, forKey: .value)
60 | switch typeName {
61 | case "WebViewURLSource":
62 | self = .url(value)
63 | case "WebViewHTMLSource":
64 | self = .html(value)
65 | default:
66 | throw DecodingError.dataCorruptedError(
67 | forKey: .typeName,
68 | in: container,
69 | debugDescription: "Invalid value: \(typeName)"
70 | )
71 | }
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Nodes/ZStack.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public final class ZStack: Layer {
20 | public let alignment: Alignment
21 |
22 | public init(id: String = UUID().uuidString, name: String?, parent: Node? = nil, children: [Node] = [], ignoresSafeArea: Set? = nil, aspectRatio: CGFloat? = nil, padding: Padding? = nil, frame: Frame? = nil, layoutPriority: CGFloat? = nil, offset: CGPoint? = nil, shadow: Shadow? = nil, opacity: CGFloat? = nil, background: Background? = nil, overlay: Overlay? = nil, mask: Node? = nil, action: Action? = nil, accessibility: Accessibility? = nil, metadata: Metadata? = nil, alignment: Alignment) {
23 | self.alignment = alignment
24 | super.init(id: id, name: name, parent: parent, children: children, ignoresSafeArea: ignoresSafeArea, aspectRatio: aspectRatio, padding: padding, frame: frame, layoutPriority: layoutPriority, offset: offset, shadow: shadow, opacity: opacity, background: background, overlay: overlay, mask: mask, action: action, accessibility: accessibility, metadata: metadata)
25 | }
26 |
27 | // MARK: Decodable
28 |
29 | private enum CodingKeys: String, CodingKey {
30 | case alignment
31 | }
32 |
33 | required init(from decoder: Decoder) throws {
34 | let container = try decoder.container(keyedBy: CodingKeys.self)
35 | alignment = try container.decode(Alignment.self, forKey: .alignment)
36 | try super.init(from: decoder)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Accessibility.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public struct Accessibility: Decodable, Hashable {
19 | /// Hides the node from system accessibility features.
20 | /// When used on an Image this indicates to features
21 | /// such as VoiceOver that the image is decorative and
22 | /// can be safely ignored. When this property is true,
23 | /// accessibility is essentially disabled and all the other
24 | /// Accessibility properties have no effect.
25 | public let isHidden: Bool
26 | /// A textual description of the node for use in system accessibility
27 | /// features such as VoiceOver. When used on an image, this label is
28 | /// used for what is commonly known as "alt text".
29 | public let label: String?
30 | /// Indicates to system accessibility features the order the node is
31 | /// presented to the user. For example the order read by VoiceOver.
32 | /// Nodes with higher values are presented before nodes with lower values.
33 | /// The default value is 0.
34 | public let sortPriority: Int?
35 | /// Indicates to system accessibility features such as VoiceOver that
36 | /// the node is a header that divides content into sections such as a
37 | /// section title. This enables features like VoiceOver to be able to
38 | /// quickly navigate between sections of content.
39 | public let isHeader: Bool
40 | /// Setting this property on one node per screen enables system
41 | /// accessibility features such as VoiceOver to provide the user with
42 | /// a summary of the screen.
43 | public let isSummary: Bool
44 | /// Indicates to system accessibility features such as VoiceOver that
45 | /// interacting with this node will produce a sound.
46 | public let playsSound: Bool
47 | /// Indicates to system accessibility features such as VoiceOver that
48 | /// interacting with this node will begin playback of multimedia.
49 | public let startsMediaSession: Bool
50 |
51 | public init(isHidden: Bool, label: String?, sortPriority: Int?, isHeader: Bool, isSummary: Bool, playsSound: Bool, startsMediaSession: Bool) {
52 | self.isHidden = isHidden
53 | self.label = label
54 | self.sortPriority = sortPriority
55 | self.isHeader = isHeader
56 | self.isSummary = isSummary
57 | self.playsSound = playsSound
58 | self.startsMediaSession = startsMediaSession
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/BackButtonStyle.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public enum BackButtonStyle: Decodable {
19 | case `default`(title: String)
20 | case generic
21 | case minimal
22 |
23 | // MARK: Codable
24 |
25 | private enum CodingKeys: String, CodingKey {
26 | case typeName = "__typeName"
27 | case title
28 | }
29 |
30 | public init(from decoder: Decoder) throws {
31 | let container = try decoder.container(keyedBy: CodingKeys.self)
32 | let typeName = try container.decode(String.self, forKey: .typeName)
33 | switch typeName {
34 | case "DefaultBackButtonStyle":
35 | let title = try container.decode(String.self, forKey: .title)
36 | self = .default(title: title)
37 | case "GenericBackButtonStyle":
38 | self = .generic
39 | case "MinimalBackButtonStyle":
40 | self = .minimal
41 | default:
42 | throw DecodingError.dataCorruptedError(
43 | forKey: .typeName,
44 | in: container,
45 | debugDescription: "Invalid value: \(typeName)"
46 | )
47 | }
48 | }
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Background.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public struct Background: Decodable {
4 | /// Background layer node
5 | public let node: Node
6 |
7 | /// The alignment of the background inside the resulting frame.
8 | public let alignment: Alignment
9 |
10 | public init(_ node: Node, alignment: Alignment = .center) {
11 | self.node = node
12 | self.alignment = alignment
13 | }
14 |
15 | // MARK: Codable
16 |
17 | private enum CodingKeys: String, CodingKey {
18 | case node
19 | case alignment
20 | }
21 |
22 | public init(from decoder: Decoder) throws {
23 | let container = try decoder.container(keyedBy: CodingKeys.self)
24 | node = try container.decodeNode(forKey: .node)
25 | alignment = try container.decode(Alignment.self, forKey: .alignment)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Border.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public struct Border: Decodable {
19 | public let color: ColorVariants
20 | public let width: Int
21 |
22 | public init(color: ColorVariants, width: Int) {
23 | self.color = color
24 | self.width = width
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Color.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import CoreGraphics
18 |
19 | public struct Color: Hashable, Codable {
20 | /// A decimal between 0.0...1.0
21 | public let red: CGFloat
22 | /// A decimal between 0.0...1.0
23 | public let green: CGFloat
24 | /// A decimal between 0.0...1.0
25 | public let blue: CGFloat
26 | /// A decimal between 0.0...1.0
27 | public let alpha: CGFloat
28 |
29 | public init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
30 | self.red = red
31 | self.green = green
32 | self.blue = blue
33 | self.alpha = alpha
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/ColorVariants.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public struct ColorVariants: Codable, Hashable {
19 | /// An iOS system color
20 | public let systemName: String?
21 | /// The default color to use if there is no match for the device's mode.
22 | /// The color to use for when device has light mode enabled.
23 | public let `default`: JudoModel.Color?
24 | /// The color to use when the device has high contrast enabled.
25 | public let highContrast: JudoModel.Color?
26 | /// The color to use when the device has dark mode enabled.
27 | public let darkMode: JudoModel.Color?
28 | /// The color to use when the device has dark mode and high contrast enabled.
29 | public let darkModeHighContrast: JudoModel.Color?
30 |
31 | public init(systemName: String?, default: Color?, highContrast: Color?, darkMode: Color?, darkModeHighContrast: Color?) {
32 | self.systemName = systemName
33 | self.default = `default`
34 | self.highContrast = highContrast
35 | self.darkMode = darkMode
36 | self.darkModeHighContrast = darkModeHighContrast
37 | }
38 |
39 | public static let clear = ColorVariants(systemName: "clear", default: nil, highContrast: nil, darkMode: nil, darkModeHighContrast: nil)
40 | }
41 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Condition.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public struct Condition: Decodable {
19 | public enum Predicate: String, Decodable {
20 | case equals
21 | case doesNotEqual
22 | case isGreaterThan
23 | case isLessThan
24 | case isSet
25 | case isNotSet
26 | case isTrue
27 | case isFalse
28 | }
29 |
30 | public var keyPath: String
31 | public var predicate: Predicate
32 | public var value: Any?
33 |
34 | public init(keyPath: String, predicate: Predicate, value: Any? = nil) {
35 | self.keyPath = keyPath
36 | self.predicate = predicate
37 | self.value = value
38 | }
39 |
40 | private enum CodingKeys: String, CodingKey {
41 | case keyPath
42 | case predicate
43 | case value
44 | }
45 |
46 | public init(from decoder: Decoder) throws {
47 | let container = try decoder.container(keyedBy: CodingKeys.self)
48 | keyPath = try container.decode(String.self, forKey: .keyPath)
49 | predicate = try container.decode(Predicate.self, forKey: .predicate)
50 |
51 | if let value = try? container.decode(String.self, forKey: .value) {
52 | self.value = value
53 | } else if let value = try? container.decode(Double.self, forKey: .value) {
54 | self.value = value
55 | } else if let value = try? container.decode(Bool.self, forKey: .value) {
56 | self.value = value
57 | } else if let value = try? container.decode(Date.self, forKey: .value) {
58 | self.value = value
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/DynamicGradient.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | @available(*, deprecated, message: "Not in SDK")
19 | public struct DynamicGradient: Decodable, Hashable {
20 | public var `default`: JudoModel.Gradient
21 |
22 | // The following gradients should be used, in given order of precedence, if their selectors match the environment.
23 |
24 | public var darkModeHighContrast: JudoModel.Gradient?
25 |
26 | public var darkMode: JudoModel.Gradient?
27 |
28 | public var highContrast: JudoModel.Gradient?
29 |
30 | public init(gradient: JudoModel.Gradient) {
31 | self.default = gradient
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Fill.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import os.log
18 |
19 | public enum Fill: Decodable, Hashable {
20 | case flat(_ color: ColorVariants)
21 | case gradient(_ gradient: GradientVariants)
22 |
23 | // MARK: Decodable
24 |
25 | private enum CodingKeys: String, CodingKey {
26 | case typeName = "__typeName"
27 | case color
28 | case gradient
29 | }
30 |
31 | public init(from decoder: Decoder) throws {
32 | let container = try decoder.container(keyedBy: CodingKeys.self)
33 | let typeName = try container.decode(String.self, forKey: .typeName)
34 | switch typeName {
35 | case "FlatFill":
36 | let color = try container.decode(ColorVariants.self, forKey: .color)
37 | self = .flat(color)
38 | case "GradientFill":
39 | let gradient = try container.decode(GradientVariants.self, forKey: .gradient)
40 | self = .gradient(gradient)
41 | default:
42 | judo_log(.error, "Unsupported fill case name: %@", typeName)
43 | assertionFailure("Unsupported value \(typeName)")
44 | self = .flat(.clear)
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/FontResource.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public enum FontResource: Decodable {
4 | case fontResource(url: URL, fontName: String)
5 | case fontResourceCollection(url: URL, fontNames: [String])
6 |
7 | public var url: URL {
8 | switch self {
9 | case .fontResource(let url, _):
10 | return url
11 | case .fontResourceCollection(let url, _):
12 | return url
13 | }
14 | }
15 |
16 | enum CodingKeys: String, CodingKey {
17 | case typeName = "__typeName"
18 | case url
19 | case fontName
20 | case fontNames
21 | }
22 |
23 | public init(from decoder: Decoder) throws {
24 | let container = try decoder.container(keyedBy: CodingKeys.self)
25 | let typeName = try container.decode(String.self, forKey: .typeName)
26 | switch typeName {
27 | case "FontResource":
28 | let url = try container.decode(URL.self, forKey: .url)
29 | let fontName = try container.decode(String.self, forKey: .fontName)
30 | self = .fontResource(url: url, fontName: fontName)
31 | case "FontCollectionResource":
32 | let url = try container.decode(URL.self, forKey: .url)
33 | let fontNames = try container.decode([String].self, forKey: .fontNames)
34 | self = .fontResourceCollection(url: url, fontNames: fontNames)
35 | default:
36 | throw DecodingError.dataCorruptedError(
37 | forKey: .typeName,
38 | in: container,
39 | debugDescription: "Invalid value: \(typeName)"
40 | )
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Frame.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 | import Foundation
18 |
19 | public struct Frame: Decodable, Equatable {
20 | /// A fixed width for the frame.
21 | public let width: CGFloat?
22 | /// A fixed height for the frame.
23 | public let height: CGFloat?
24 | /// The minimum width of the resulting frame.
25 | public let minWidth: CGFloat?
26 | /// The maximum width of the resulting frame.
27 | public let maxWidth: CGFloat?
28 | /// The minimum height of the resulting frame.
29 | public let minHeight: CGFloat?
30 | /// The maximum height of the resulting frame.
31 | public let maxHeight: CGFloat?
32 | /// The alignment of the node inside the resulting frame.
33 | /// The alignment only applies if the node is smaller than the size of the resulting frame.
34 | public let alignment: Alignment
35 |
36 | public var isFixed: Bool {
37 | minWidth == nil && maxWidth == nil && minHeight == nil && maxHeight == nil
38 | }
39 |
40 | public init(width: CGFloat?, height: CGFloat?, minWidth: CGFloat?, maxWidth: CGFloat?, minHeight: CGFloat?, maxHeight: CGFloat?, alignment: Alignment) {
41 | self.width = width
42 | self.height = height
43 | self.minWidth = minWidth
44 | self.maxWidth = maxWidth
45 | self.minHeight = minHeight
46 | self.maxHeight = maxHeight
47 | self.alignment = alignment
48 | }
49 |
50 | private enum CodingKeys: String, CodingKey {
51 | case width
52 | case height
53 | case minWidth
54 | case maxWidth
55 | case minHeight
56 | case maxHeight
57 | case alignment
58 | }
59 |
60 | public init(from decoder: Decoder) throws {
61 | let container = try decoder.container(keyedBy: CodingKeys.self)
62 |
63 | width = try container.decodeIfPresent(CGFloat.self, forKey: .width)
64 | height = try container.decodeIfPresent(CGFloat.self, forKey: .height)
65 | minWidth = try container.decodeIfPresent(CGFloat.self, forKey: .minWidth)
66 | minHeight = try container.decodeIfPresent(CGFloat.self, forKey: .minHeight)
67 |
68 | if let maxWidthStringValue = try? container.decodeIfPresent(String.self, forKey: .maxWidth), maxWidthStringValue == "inf" {
69 | maxWidth = CGFloat.greatestFiniteMagnitude
70 | } else {
71 | maxWidth = try container.decodeIfPresent(CGFloat.self, forKey: .maxWidth)
72 | }
73 |
74 | if let maxHeightStringValue = try? container.decodeIfPresent(String.self, forKey: .maxHeight), maxHeightStringValue == "inf" {
75 | maxHeight = CGFloat.greatestFiniteMagnitude
76 | } else {
77 | maxHeight = try container.decodeIfPresent(CGFloat.self, forKey: .maxHeight)
78 | }
79 |
80 | alignment = try container.decode(Alignment.self, forKey: .alignment)
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Gradient.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 |
18 | public struct GradientStop: Hashable, Codable {
19 | /// A decimal between 0-1 indicating where along the gradient the color is reached.
20 | public var position: CGFloat
21 | /// The color that the gradient should pass through at this position.
22 | public var color: JudoModel.Color
23 |
24 | public init(position: CGFloat, color: Color) {
25 | self.position = position
26 | self.color = color
27 | }
28 | }
29 |
30 | public struct Gradient: Hashable, Decodable {
31 | /// In a parametric coordinate space, between 0 and 1.
32 | public let from: CGPoint
33 | /// In a parametric coordinate space, between 0 and 1.
34 | public let to: CGPoint
35 | /// Color and stop point data.
36 | public let stops: [GradientStop]
37 |
38 | public init(from: CGPoint, to: CGPoint, stops: [GradientStop]) {
39 | self.from = from
40 | self.to = to
41 | self.stops = stops
42 | }
43 |
44 | public static var `clear`: Gradient {
45 | return Gradient(
46 | from: CGPoint(x: 0.0, y: 0.5),
47 | to: CGPoint(x: 1.0, y: 0.5),
48 | stops: [
49 | GradientStop(position: 0, color: Color(red: 0, green: 0, blue: 0, alpha: 0)),
50 | GradientStop(position: 1, color: Color(red: 0, green: 0, blue: 0, alpha: 0))
51 | ]
52 | )
53 | }
54 |
55 | // MARK: Decodable
56 |
57 | private enum CodingKeys: String, CodingKey {
58 | case from
59 | case to
60 | case stops
61 | }
62 |
63 | public init(from decoder: Decoder) throws {
64 | let container = try decoder.container(keyedBy: CodingKeys.self)
65 |
66 | let fromArray = try container.decode([CGFloat].self, forKey: .from)
67 | from = CGPoint(x: CGFloat(fromArray[0]), y: CGFloat(fromArray[1]))
68 |
69 | let toArray = try container.decode([CGFloat].self, forKey: .to)
70 | to = CGPoint(x: CGFloat(toArray[0]), y: CGFloat(toArray[1]))
71 |
72 | stops = try container.decode([GradientStop].self, forKey: .stops)
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/GradientVariants.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | public struct GradientVariants: Hashable, Decodable {
17 | /// The default gradient to use if there is no match for the device's mode. The gradient for devices with light mode enabled.
18 | public let `default`: JudoModel.Gradient
19 | /// The gradient to use when the device has high contrast enabled.
20 | public let darkMode: JudoModel.Gradient?
21 | /// The gradient to use when the device has high contrast enabled.
22 | public let highContrast: JudoModel.Gradient?
23 | /// The gradient to use when the device has dark mode and high contrast enabled.
24 | public let darkModeHighContrast: JudoModel.Gradient?
25 |
26 | public init(default: Gradient, darkMode: Gradient?, highContrast: Gradient?, darkModeHighContrast: Gradient?) {
27 | self.default = `default`
28 | self.darkMode = darkMode
29 | self.highContrast = highContrast
30 | self.darkModeHighContrast = darkModeHighContrast
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Metadata.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | public struct Metadata: Codable, Hashable {
17 | public var properties: [String: String] = [:]
18 | public var tags: Set = []
19 |
20 | public init(properties: [String: String] = [:], tags: Set = []) {
21 | self.properties = properties
22 | self.tags = tags
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/ModalPresentationStyle.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public enum ModalPresentationStyle: String, Codable {
19 | case sheet
20 | case fullScreen
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/NamedIcon.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public struct NamedIcon: Decodable, Hashable {
19 | /// The name of a SF Symbol icon to use on iOS.
20 | public let symbolName: String
21 | /// The name of the Material Icons icon to use on Android.
22 | public let materialName: String
23 |
24 | public init(symbolName: String, materialName: String) {
25 | self.symbolName = symbolName
26 | self.materialName = materialName
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Overlay.swift:
--------------------------------------------------------------------------------
1 | import Foundation
2 |
3 | public struct Overlay: Decodable {
4 | /// Background layer node
5 | public let node: Node
6 |
7 | /// The alignment of the background inside the resulting frame.
8 | public let alignment: Alignment
9 |
10 | public init(_ node: Node, alignment: Alignment = .center) {
11 | self.node = node
12 | self.alignment = alignment
13 | }
14 |
15 | // MARK: Codable
16 |
17 | private enum CodingKeys: String, CodingKey {
18 | case node
19 | case alignment
20 | }
21 |
22 | public init(from decoder: Decoder) throws {
23 | let container = try decoder.container(keyedBy: CodingKeys.self)
24 | node = try container.decodeNode(forKey: .node)
25 | alignment = try container.decode(Alignment.self, forKey: .alignment)
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Padding.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import CoreGraphics
17 |
18 | public struct Padding: Decodable, Equatable {
19 | /// Padding distance for the top edge.
20 | public let top: CGFloat
21 | /// Padding distance for the leading edge.
22 | public let leading: CGFloat
23 | /// Padding distance for the bottom edge.
24 | public let bottom: CGFloat
25 | /// Padding distance for the trailing edge.
26 | public let trailing: CGFloat
27 |
28 | public init(top: CGFloat, leading: CGFloat, bottom: CGFloat, trailing: CGFloat) {
29 | self.top = top
30 | self.leading = leading
31 | self.bottom = bottom
32 | self.trailing = trailing
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/SegueStyle.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public enum SegueStyle: String, Decodable {
19 | case push
20 | case modal
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/Shadow.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public struct Shadow: Decodable, Hashable {
19 | /// The shadow's color.
20 | public let color: ColorVariants
21 | public let blur: Int
22 | public let x: Int
23 | public let y: Int
24 |
25 | public init(color: ColorVariants, blur: Int, x: Int, y: Int) {
26 | self.color = color
27 | self.blur = blur
28 | self.x = x
29 | self.y = y
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/StatusBarStyle.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public enum StatusBarStyle: String, Decodable {
19 | case `default`
20 | case light
21 | case dark
22 | case inverted
23 | }
24 |
--------------------------------------------------------------------------------
/Sources/JudoModel/Value Types/StringTable.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | public typealias StringKey = String
19 | public typealias LocaleIdentifier = String
20 |
21 | public typealias StringTable = [LocaleIdentifier: [StringKey: String]]
22 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/AssetsDownloader.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import os.log
18 |
19 | final class AssetsDownloader {
20 |
21 | private let session: URLSession
22 |
23 | init(cache: URLCache? = nil) {
24 | let configuration = URLSessionConfiguration.default
25 | configuration.httpShouldUsePipelining = true
26 | configuration.networkServiceType = .responsiveData
27 | configuration.waitsForConnectivity = true
28 | configuration.urlCache = cache
29 | configuration.requestCachePolicy = .returnCacheDataElseLoad
30 | session = URLSession(configuration: configuration)
31 | }
32 |
33 | func download(url: URL) {
34 | download(url: url, completion: { _ in })
35 | }
36 |
37 | func download(url: URL, completion: @escaping (Result) -> Void) {
38 | let request = URLRequest.assetRequest(url: url)
39 | let urlTask = session.dataTask(with: request) { data, response, error in
40 | if let error = error {
41 | completion(.failure(error))
42 | return
43 | }
44 |
45 | if let data = data {
46 | completion(.success(data))
47 | }
48 | }
49 |
50 | urlTask.resume()
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/DownloadService.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import os.log
18 |
19 | /// Download service.
20 | final class DownloadService {
21 | internal var persistentFetchedExperienceURLs: Set {
22 | get {
23 | Set((Judo.userDefaults.array(forKey: "persistentFetchedExperienceURLs") as? [String])?.compactMap({ URL(string: $0) }) ?? [])
24 | }
25 | set {
26 | Judo.userDefaults.set(newValue.map(\.absoluteString), forKey: "persistentFetchedExperienceURLs")
27 | }
28 | }
29 |
30 | private var lastSeenCache: URLCache?
31 | private var _urlSession: URLSession
32 | private var urlSession: URLSession {
33 | get {
34 | if let lastSeenCache = lastSeenCache, lastSeenCache !== Judo.sharedInstance.urlCache {
35 | judo_log(.debug, "Judo cache setup changed since last usage of DownloadService, recreating URLSession.")
36 | _urlSession = URLSession(configuration: Self.defaultURLSessionConfiguration(cache: Judo.sharedInstance.urlCache))
37 | self.lastSeenCache = Judo.sharedInstance.urlCache
38 | }
39 | return _urlSession
40 | }
41 | set {
42 | _urlSession = newValue
43 | }
44 | }
45 |
46 | /// Instantiate instance
47 | /// - Parameter configuration: Service configuration.
48 | init(urlSession: URLSession? = nil) {
49 | self.lastSeenCache = Judo.sharedInstance.urlCache
50 | self._urlSession = urlSession ?? URLSession(configuration: Self.defaultURLSessionConfiguration(cache: Judo.sharedInstance.urlCache))
51 | }
52 |
53 | static func defaultURLSessionConfiguration(cache: URLCache) -> URLSessionConfiguration {
54 | let configuration = URLSessionConfiguration.default
55 | configuration.urlCache = cache
56 | configuration.networkServiceType = .responsiveData
57 | return configuration
58 | }
59 |
60 | /// Fetch experience asynchronously.
61 | /// - Parameter completion: Fetched experience data
62 | func fetchExperienceData(url: URL, cachePolicy: URLRequest.CachePolicy, completion: @escaping (Result) -> Void) {
63 | var urlRequest = URLRequest.apiRequest(url: url)
64 | urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
65 | urlRequest.cachePolicy = cachePolicy
66 | urlSession.dataTask(with: urlRequest) { result in
67 | completion(Result {
68 | let data = try result.get()
69 |
70 | // Remember fetched experience urls
71 | self.persistentFetchedExperienceURLs.insert(url)
72 |
73 | return data
74 | })
75 | }.resume()
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/Extensions/Collection+items.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | extension Collection {
21 | func items(data: Any?, urlParameters: [String: String], userInfo: [String: Any]) -> [Any] {
22 | guard var result = JSONSerialization.value(forKeyPath: keyPath, data: data, urlParameters: urlParameters, userInfo: userInfo) as? [Any] else {
23 | return []
24 | }
25 |
26 | filters.forEach { condition in
27 | result = result.filter { data in
28 | condition.isSatisfied(
29 | data: data,
30 | urlParameters: urlParameters,
31 | userInfo: userInfo
32 | )
33 | }
34 | }
35 |
36 | if !sortDescriptors.isEmpty {
37 | result.sort { a, b in
38 | for descriptor in sortDescriptors {
39 | let a = JSONSerialization.value(
40 | forKeyPath: descriptor.keyPath,
41 | data: a,
42 | urlParameters: urlParameters,
43 | userInfo: userInfo
44 | )
45 |
46 | let b = JSONSerialization.value(
47 | forKeyPath: descriptor.keyPath,
48 | data: b,
49 | urlParameters: urlParameters,
50 | userInfo: userInfo
51 | )
52 |
53 | switch (a, b) {
54 | case (let a as String, let b as String) where a != b:
55 | return descriptor.ascending ? a < b : a > b
56 | case (let a as Double, let b as Double) where a != b:
57 | return descriptor.ascending ? a < b : a > b
58 | case (let a as Bool, let b as Bool) where a != b:
59 | return descriptor.ascending ? a == false : a == true
60 | case (let a as Date, let b as Date) where a != b:
61 | return descriptor.ascending ? a < b : a > b
62 | default:
63 | break
64 | }
65 | }
66 |
67 | return false
68 | }
69 | }
70 |
71 | if let limit = limit {
72 | let startAt = max(limit.startAt - 1, 0)
73 | let lowerBound = min(startAt, result.indices.upperBound)
74 | let limitedRange = result.indices.clamped(to: lowerBound.. Bool) -> Node? {
25 | reduce(nil) { result, node in
26 | guard result == nil else {
27 | return result
28 | }
29 |
30 | if predicate(node) {
31 | return node
32 | }
33 |
34 | return node.children.highest(where: predicate)
35 | }
36 | }
37 |
38 | /// Traverses the node graph, starting with the node's children, until it finds a node that matches the
39 | /// supplied predicate, from the bottom of the z-order.
40 | func lowest(where predicate: (Node) -> Bool) -> Node? {
41 | reversed().reduce(nil) { result, node in
42 | guard result == nil else {
43 | return result
44 | }
45 |
46 | if predicate(node) {
47 | return node
48 | }
49 |
50 | return node.children.lowest(where: predicate)
51 | }
52 | }
53 |
54 | func traverse(_ block: (Node) -> Void) {
55 | forEach { node in
56 | block(node)
57 | node.children.traverse(block)
58 | }
59 | }
60 |
61 | func flatten() -> [Node] {
62 | flatMap { node -> [Node] in
63 | [node] + node.children.flatten()
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/Extensions/OSLog+JudoSDK.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import os.log
18 |
19 | private var _judoLog = OSLog(subsystem: "app.judo.JudoSDK", category: "JudoSDK")
20 |
21 | extension OSLog {
22 | static var judoLog: OSLog { _judoLog }
23 | }
24 |
25 | private func judoLoggingEnabled() -> Bool {
26 | ProcessInfo.processInfo.environment["JUDO_VERBOSE"] != nil
27 | }
28 |
29 | func judo_log(_ type: OSLogType, _ message: StaticString, _ args: CVarArg...) {
30 | guard judoLoggingEnabled() || type == .error else {
31 | return
32 | }
33 |
34 | // lack of splat means this mess:
35 | switch args.count {
36 | case 0:
37 | os_log(message, log: .judoLog, type: type)
38 | case 1:
39 | os_log(message, log: .judoLog, type: type, args[0])
40 | case 2:
41 | os_log(message, log: .judoLog, type: type, args[0], args[1])
42 | case 3:
43 | os_log(message, log: .judoLog, type: type, args[0], args[1], args[2])
44 | case 4:
45 | os_log(message, log: .judoLog, type: type, args[0], args[1], args[2], args[3])
46 | case 5:
47 | os_log(message, log: .judoLog, type: type, args[0], args[1], args[2], args[3], args[4])
48 | default:
49 | os_log(message, log: .judoLog, type: type, args[0], args[1], args[2], args[3], args[4], args[5])
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/Extensions/StringTable+resolve.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import JudoModel
18 |
19 | extension StringTable {
20 | func resolve(key: StringKey) -> String {
21 | // A simple (and not complete) attempt at RFC 4647 basic filtering.
22 |
23 | let preferredLocale = Locale.preferredLocale()
24 |
25 | if let matchedLocale = self[preferredLocale.identifier], let translation = matchedLocale[key] {
26 | return translation
27 | }
28 |
29 | guard let languageCode = preferredLocale.languageCode else {
30 | return key
31 | }
32 |
33 | let matchedLanguage = self.first { (languageEntry, string) in
34 | languageEntry == languageCode || languageEntry.starts(with: "\(languageCode)-") || languageEntry.starts(with: "\(languageCode)_")
35 | }?.value
36 |
37 | return matchedLanguage?[key] ?? key
38 | }
39 | }
40 |
41 | fileprivate extension Locale {
42 | static func preferredLocale() -> Locale {
43 | guard let preferredIdentifier = Locale.preferredLanguages.first else {
44 | return Locale.current
45 | }
46 |
47 | switch preferredIdentifier.lowercased(with: Locale(identifier: "en-US")) {
48 | case "zh-hant":
49 | return Locale(identifier: "zh-CN")
50 | case "zh-hans":
51 | return Locale(identifier: "zh-TW")
52 | default:
53 | return Locale(identifier: preferredIdentifier)
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/Extensions/UIControl+action.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import UIKit
17 |
18 | extension UIControl {
19 |
20 | func addAction(for controlEvents: UIControl.Event, _ action: @escaping (UIControl) -> Void) {
21 |
22 | @objc final class UIControlClosureBox: NSObject {
23 | private let closure: (UIControl) -> Void
24 |
25 | init(_ closure: @escaping (UIControl) -> Void) {
26 | self.closure = closure
27 | }
28 |
29 | @objc func invoke(_ sender: UIControl) {
30 | closure(sender)
31 | }
32 | }
33 |
34 | let box = UIControlClosureBox(action)
35 | addTarget(box, action: #selector(UIControlClosureBox.invoke(_:)), for: controlEvents)
36 | objc_setAssociatedObject(self, "\(UUID())", box, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
37 | }
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/Extensions/URL+cache.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import UIKit
18 |
19 | extension URL {
20 | func cachedImage() -> UIImage? {
21 | if let image = Judo.sharedInstance.imageCache.object(forKey: self as NSURL) {
22 | return image
23 | }
24 |
25 | if let cacheEntry = Judo.sharedInstance.assetsURLCache.cachedResponse(for: URLRequest(url: self)), let image = UIImage(data: cacheEntry.data) {
26 | return image
27 | }
28 |
29 | return nil
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/Extensions/URLSession+dataPublisher.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import JudoModel
17 | import Combine
18 | import Foundation
19 |
20 | @available(iOS 13.0, *)
21 | extension URLSession {
22 | func dataPublisher(for request: URLRequest) -> AnyPublisher, Never> {
23 | dataTaskPublisher(for: request)
24 | .retry(1)
25 | .tryMap { element -> Data in
26 | guard let httpResponse = element.response as? HTTPURLResponse,
27 | httpResponse.statusCode == 200 else {
28 | throw URLError(.badServerResponse)
29 | }
30 |
31 | return element.data
32 | }
33 | .tryMap { data in
34 | try JSONSerialization.jsonObject(with: data)
35 | }
36 | .map { data in
37 | .success(data)
38 | }
39 | .catch { error in
40 | Just(.failure(error)).eraseToAnyPublisher()
41 | }
42 | .receive(on: RunLoop.main)
43 | .eraseToAnyPublisher()
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/JudoRepository.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import JudoModel
18 | import os.log
19 |
20 | final public class JudoRepository {
21 | enum Error: Swift.Error {
22 | case notAvailable
23 | }
24 |
25 | /// Data synchronization service
26 | let downloadService = DownloadService()
27 |
28 | /// Retrieve Experience data.
29 | /// - Parameter url: Experience URL
30 | public func retrieveExperience(url: URL, ignoreCache: Bool = false, completion: @escaping (Result) -> Void) {
31 | guard (NSURLComponents(url: url, resolvingAgainstBaseURL: true)?.host) != nil else {
32 | judo_log(.error, "Attempt to retrieve an Experience for an unknown host.")
33 | DispatchQueue.main.async {
34 | completion(Result.failure(UnsupportedDomainError(domain: "")))
35 | }
36 | return
37 | }
38 |
39 | downloadService.fetchExperienceData(url: url, cachePolicy: ignoreCache ? .reloadIgnoringLocalAndRemoteCacheData : .useProtocolCachePolicy) { result in
40 | do {
41 | let experienceData = try result.get()
42 | let experience = try Experience(decode: experienceData)
43 | DispatchQueue.main.async {
44 | completion(.success(experience))
45 | }
46 | } catch {
47 | DispatchQueue.main.async {
48 | completion(.failure(error))
49 | }
50 | }
51 | }
52 | }
53 | }
54 |
55 | struct UnsupportedDomainError: Error, LocalizedError {
56 | var domain: String
57 |
58 | var errorDescription: String? {
59 | "Unsupported Judo domain: \(domain)"
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/MainQueue.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | private let mainQueueKey: DispatchSpecificKey = {
19 | let key = DispatchSpecificKey()
20 | DispatchQueue.main.setSpecific(key: key, value: "judoMainQueueValue")
21 | return key
22 | }()
23 |
24 | extension DispatchQueue {
25 |
26 | static var isMainQueue: Bool {
27 | DispatchQueue.getSpecific(key: mainQueueKey) != nil
28 | }
29 |
30 | static func toMain(_ block: @escaping () -> Void) {
31 |
32 | // Being on the main thread does not guarantee to be on the main queue.
33 | if DispatchQueue.isMainQueue {
34 | block()
35 | } else {
36 | if Thread.isMainThread {
37 | DispatchQueue.main.async {
38 | block()
39 | }
40 | } else {
41 | // Execution is not on the main queue and thread at this point.
42 | DispatchQueue.main.sync {
43 | block()
44 | }
45 | }
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/Meta.swift:
--------------------------------------------------------------------------------
1 | enum Meta {
2 | public static let APIVersion: Int = 2
3 | public static let SDKVersion: String = "1.8.6"
4 | }
5 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/Model/ViewID.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 |
18 | struct ViewID: Hashable {
19 | var nodeID: String
20 | var collectionIndex = 0
21 | }
22 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/RecoverableError.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | protocol RecoverableError {
17 | var canRecover: Bool { get }
18 | }
19 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/Resources/en.lproj/Localizable.strings:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/judoapp/judo-ios/ccefe31abccb8b3af12504adc30eb2c1f8273cf2/Sources/JudoSDK/Resources/en.lproj/Localizable.strings
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/CarouselState.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Combine
17 |
18 | @available(iOS 13.0, *)
19 | final class CarouselState: ObservableObject {
20 | @Published var currentPageForCarousel: [ViewID: Int] = [:]
21 | @Published var currentNumberOfPagesForCarousel: [ViewID: Int] = [:]
22 | }
23 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Model/Color+uiValues.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import UIKit
18 | import SwiftUI
19 | import JudoModel
20 |
21 | @available(iOS 13.0, *)
22 | extension JudoModel.Color {
23 | var swiftUIColor: SwiftUI.Color {
24 | Color(.displayP3, red: Double(red), green: Double(green), blue: Double(blue), opacity: Double(alpha))
25 | }
26 |
27 | var uiColor: UIColor {
28 | UIColor(displayP3Red: CGFloat(red), green: CGFloat(green), blue: CGFloat(blue), alpha: CGFloat(alpha))
29 | }
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Model/ColorVariants+uikit.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import UIKit
17 | import SwiftUI
18 | import JudoModel
19 |
20 | @available(iOS 13.0, *)
21 | extension ColorVariants {
22 | func uikitUIColor(colorScheme: ColorScheme, colorSchemeContrast: ColorSchemeContrast) -> UIColor? {
23 | if let systemColor = systemName {
24 | return UIColor.named(systemColor)
25 | } else if let highContrast = highContrast, colorScheme != .dark, colorSchemeContrast == .increased {
26 | return highContrast.uiColor
27 | } else if let darkModeHighContrast = darkModeHighContrast, colorScheme == .dark, colorSchemeContrast == .increased {
28 | return darkModeHighContrast.uiColor
29 | } else if let darkMode = darkMode, colorScheme == .dark {
30 | return darkMode.uiColor
31 | } else if let `default` = `default` {
32 | return `default`.uiColor
33 | } else {
34 | return nil
35 | }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Model/Gradient+swiftUI.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import SwiftUI
18 | import JudoModel
19 |
20 | // MARK: SwiftUI Value
21 |
22 | @available(iOS 13.0, *)
23 | public extension JudoModel.Gradient {
24 | func swiftUIGradient(startPoint: UnitPoint? = nil, endPoint: UnitPoint? = nil) -> LinearGradient {
25 | LinearGradient(
26 | gradient: Gradient(
27 | stops: stops
28 | .sorted { $0.position < $1.position }
29 | .map { Gradient.Stop(color: $0.color.swiftUIColor, location: CGFloat($0.position)) }
30 | ),
31 | startPoint: startPoint ?? .init(x: from.x, y: from.y),
32 | endPoint: endPoint ?? .init(x: to.x, y: to.y)
33 | )
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Model/RealizeColor.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 |
20 | /// Realize a ColorVariants into a UIColor or SwiftUI.Color.
21 | @available(iOS 13.0, *)
22 | struct RealizeColor: View where Content: View {
23 | @Environment(\.colorScheme) private var colorScheme
24 | @Environment(\.colorSchemeContrast) private var colorSchemeContrast
25 |
26 | private let colorVariants: ColorVariants
27 | private let content: (C) -> Content
28 |
29 | init(_ colorVariants: ColorVariants, @ViewBuilder content: @escaping (C) -> Content) where C == SwiftUI.Color {
30 | self.colorVariants = colorVariants
31 | self.content = content
32 | }
33 |
34 | init(_ colorVariants: ColorVariants, @ViewBuilder content: @escaping (C) -> Content) where C == UIColor {
35 | self.colorVariants = colorVariants
36 | self.content = content
37 | }
38 |
39 | var body: some View {
40 | if C.self == SwiftUI.Color.self {
41 | content(swiftUIColor() as! C)
42 | } else if C.self == UIColor.self {
43 | content(uikitUIColor() as! C)
44 | }
45 | }
46 |
47 | private func swiftUIColor() -> SwiftUI.Color {
48 | if let systemColor = self.colorVariants.systemName {
49 | return SwiftUI.Color.named(systemColor)
50 | } else if let highContrast = self.colorVariants.highContrast, colorScheme != .dark, colorSchemeContrast == .increased {
51 | return highContrast.swiftUIColor
52 | } else if let darkModeHighContrast = self.colorVariants.darkModeHighContrast, colorScheme == .dark, colorSchemeContrast == .increased {
53 | return darkModeHighContrast.swiftUIColor
54 | } else if let darkMode = self.colorVariants.darkMode, colorScheme == .dark {
55 | return darkMode.swiftUIColor
56 | } else if let `default` = self.colorVariants.default {
57 | return `default`.swiftUIColor
58 | } else {
59 | return Color(.clear)
60 | }
61 | }
62 |
63 | private func uikitUIColor() -> UIColor {
64 | self.colorVariants.uikitUIColor(colorScheme: colorScheme, colorSchemeContrast: colorSchemeContrast) ?? .clear
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/ActionModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct ActionModifier: ViewModifier {
21 | var layer: Layer
22 |
23 | @Environment(\.experience) private var experience
24 | @Environment(\.screen) private var screen
25 | @Environment(\.presentAction) private var presentAction
26 | @Environment(\.showAction) private var showAction
27 | @Environment(\.experienceViewController) private var experienceViewControllerHolder
28 | @Environment(\.screenViewController) private var screenViewControllerHolder
29 | @Environment(\.data) private var data
30 | @Environment(\.urlParameters) private var urlParameters
31 | @Environment(\.userInfo) private var userInfo
32 | @Environment(\.authorize) private var authorize
33 |
34 | @ViewBuilder
35 | func body(content: Content) -> some View {
36 | if let action = layer.action, let experience = experience, let screen = screen, let experienceViewController = experienceViewControllerHolder?.experienceViewController, let screenViewController = screenViewControllerHolder?.screenViewController {
37 | Button {
38 | action.handle(experience: experience, node: layer, screen: screen, data: data, urlParameters: urlParameters, userInfo: userInfo, authorize: authorize, experienceViewController: experienceViewController, screenViewController: screenViewController)
39 | } label: {
40 | content
41 | }
42 | .buttonStyle(PlainButtonStyle())
43 | } else {
44 | content
45 | }
46 | }
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/AspectRatioModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct AspectRatioModifier: ViewModifier {
21 | var node: Node
22 |
23 | @ViewBuilder
24 | func body(content: Content) -> some View {
25 | if let aspectRatio = node.aspectRatio {
26 | content.aspectRatio(aspectRatio, contentMode: .fit)
27 | } else {
28 | content
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/BackgroundModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct BackgroundModifier: ViewModifier {
21 | var node: Node
22 |
23 | @ViewBuilder
24 | func body(content: Content) -> some View {
25 | if let background = node.background, let layer = background.node as? Layer {
26 | content.background(
27 | LayerView(layer: layer).environment(\.isEnabled, false),
28 | alignment: background.alignment.swiftUIValue
29 | )
30 | } else {
31 | content
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/FontModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import UIKit
18 | import JudoModel
19 |
20 | @available(iOS 13.0, *)
21 | struct FontModifier: ViewModifier {
22 | @Environment(\.sizeCategory) private var sizeCategory
23 | @State private var uiFont: SwiftUI.Font
24 |
25 | var font: JudoModel.Font
26 |
27 | init(font: JudoModel.Font) {
28 | self.font = font
29 | self._uiFont = .init(initialValue: getUIFont(for: font))
30 | }
31 |
32 | func body(content: Content) -> some View {
33 | content
34 | .font(uiFont)
35 | .onReceive(NotificationCenter.default.publisher(for: Judo.didRegisterCustomFontNotification)) { _ in
36 | uiFont = getUIFont(for: font)
37 | }
38 | }
39 | }
40 |
41 | @available(iOS 13.0, *)
42 | private func getUIFont(for font: JudoModel.Font) -> SwiftUI.Font {
43 | if let uifont = font.uikitFont {
44 | return SwiftUI.Font(uifont)
45 | }
46 |
47 | return .body
48 | }
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/FrameModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct FrameModifier: ViewModifier {
21 | var node: Node
22 |
23 | @ViewBuilder
24 | func body(content: Content) -> some View {
25 | if let frame = node.frame {
26 | if frame.isFixed {
27 | content
28 | .frame(
29 | width: frame.width,
30 | height: frame.height,
31 | alignment: frame.alignment.swiftUIValue
32 | )
33 | } else {
34 | content
35 | .frame(
36 | minWidth: frame.minWidth,
37 | maxWidth: frame.maxWidth,
38 | minHeight: frame.minHeight,
39 | maxHeight: frame.maxHeight,
40 | alignment: frame.alignment.swiftUIValue
41 | )
42 | }
43 | } else {
44 | content
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/IgnoresSafeAreaModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct IgnoresSafeAreaModifier: ViewModifier {
21 | var node: Node
22 |
23 | @ViewBuilder
24 | func body(content: Content) -> some View {
25 | if let ignoredSafeAreaEdges = node.ignoresSafeArea {
26 | content.edgesIgnoringSafeArea(SwiftUI.Edge.Set(set: ignoredSafeAreaEdges))
27 | } else {
28 | content
29 | }
30 | }
31 | }
32 |
33 | @available(iOS 13.0, *)
34 | private extension SwiftUI.Edge.Set {
35 | init(set: Set) {
36 | self = SwiftUI.Edge.Set(set.map { edge in
37 | SwiftUI.Edge.Set.Element(edge.swiftUIValue)
38 | })
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/LayoutPriorityModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct LayoutPriorityModifier: ViewModifier {
21 | var node: Node
22 |
23 | @ViewBuilder
24 | func body(content: Content) -> some View {
25 | if let layoutPriority = node.layoutPriority {
26 | content.layoutPriority(Double(layoutPriority))
27 | } else {
28 | content
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/MaskModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct MaskModifier: ViewModifier {
21 | var node: Node
22 |
23 | @ViewBuilder
24 | func body(content: Content) -> some View {
25 | if let mask = node.mask as? Layer {
26 | content.mask(
27 | LayerView(layer: mask)
28 | .environment(\.isEnabled, false)
29 | )
30 | } else {
31 | content
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/OffsetModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct OffsetModifier: ViewModifier {
21 | var node: Node
22 |
23 | @ViewBuilder
24 | func body(content: Content) -> some View {
25 | if let offset = node.offset {
26 | content.offset(x: offset.x, y: offset.y)
27 | } else {
28 | content
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/OpacityModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct OpacityModifier: ViewModifier {
21 | var node: Node
22 |
23 | @ViewBuilder
24 | func body(content: Content) -> some View {
25 | if let opacity = node.opacity {
26 | content.opacity(Double(opacity))
27 | } else {
28 | content
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/OverlayModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct OverlayModifier: ViewModifier {
21 | var node: Node
22 |
23 | @ViewBuilder
24 | func overlayContents(layer: Layer) -> some View {
25 | // Workaround: SwiftUI Overlays over UIkit views that use gesture recognizers other than tap (namely, swipe, such as ScrollViews) will block the input. The workaround is to embed the SwiftUI overlay inside UIKit itself, which, presumably, is able to properly marshal the gesture input.
26 | if node is Carousel || node is ScrollContainer {
27 | SwiftUIWrapper {
28 | LayerView(layer: layer)
29 | }
30 | .environment(\.isEnabled, false)
31 | .allowsHitTesting(false)
32 | } else {
33 | LayerView(layer: layer)
34 | .environment(\.isEnabled, false)
35 | .allowsHitTesting(false)
36 | }
37 | }
38 |
39 | @ViewBuilder
40 | func body(content: Content) -> some View {
41 | if let overlay = node.overlay, let layer = overlay.node as? Layer {
42 | content.overlay(
43 | overlayContents(layer: layer),
44 | alignment: overlay.alignment.swiftUIValue
45 | )
46 | } else {
47 | content
48 | }
49 | }
50 | }
51 |
52 | @available(iOS 13.0, *)
53 | private struct SwiftUIWrapper: UIViewControllerRepresentable {
54 | let content: () -> T
55 |
56 | func makeUIViewController(context: Context) -> UIHostingController {
57 | let hostingController = UIHostingController(rootView: content())
58 | hostingController.view.backgroundColor = .clear
59 | return hostingController
60 | }
61 |
62 | func updateUIViewController(_ uiViewController: UIHostingController, context: Context) {
63 | uiViewController.rootView = content()
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/PaddingModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct PaddingModifier: ViewModifier {
21 | var node: Node
22 |
23 | @ViewBuilder
24 | func body(content: Content) -> some View {
25 | if let padding = node.padding {
26 | content.padding(
27 | EdgeInsets(
28 | top: CGFloat(padding.top),
29 | leading: CGFloat(padding.leading),
30 | bottom: CGFloat(padding.bottom),
31 | trailing: CGFloat(padding.trailing)
32 | )
33 | )
34 | } else {
35 | content
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Modifiers/ShadowModifier.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct ShadowModifier: ViewModifier {
21 | var node: Node
22 |
23 | @ViewBuilder
24 | func body(content: Content) -> some View {
25 | if let shadow = node.shadow {
26 | RealizeColor(shadow.color) { shadowColor in
27 | content
28 | .shadow(
29 | color: shadowColor,
30 | radius: CGFloat(shadow.blur / 2),
31 | x: CGFloat(shadow.x),
32 | y: CGFloat(shadow.y)
33 | )
34 | }
35 | } else {
36 | content
37 | }
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Views/AnimatedImage.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import SwiftUI
18 | import Combine
19 |
20 | @available(iOS 13.0, *)
21 | struct AnimatedImage: View {
22 | @State private var frameIndex = 0
23 |
24 | private let timer: Publishers.Autoconnect
25 | private let images: [UIImage]
26 |
27 | init(uiImage image: UIImage) {
28 | self.images = image.images ?? [image]
29 | self.timer = Timer.publish(every: image.duration / Double(images.count), on: .main, in: .common).autoconnect()
30 | }
31 |
32 | var body: some View {
33 | Image(uiImage: images[frameIndex])
34 | .resizable()
35 | .onReceive(timer) { _ in
36 | if frameIndex + 1 < images.count {
37 | frameIndex += 1
38 | } else {
39 | frameIndex = 0
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Views/AudioView.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import Foundation
17 | import SwiftUI
18 | import JudoModel
19 | import AVKit
20 | import Combine
21 |
22 | @available(iOS 13.0, *)
23 | struct AudioView: View {
24 | @Environment(\.data) private var data
25 | @Environment(\.urlParameters) private var urlParameters
26 | @Environment(\.userInfo) private var userInfo
27 |
28 | let audio: JudoModel.Audio
29 | @State private var isVisible = true
30 |
31 | var body: some View {
32 | if let urlString = audio.sourceURL.evaluatingExpressions(data: data, urlParameters: urlParameters, userInfo: userInfo), let sourceURL = URL(string: urlString) {
33 | AudioPlayerView(
34 | sourceURL: sourceURL,
35 | looping: audio.looping,
36 | autoPlay: audio.autoPlay,
37 | isVisible: isVisible
38 | )
39 | .onDisappear { isVisible = false }
40 | .onAppear { isVisible = true }
41 | .modifier(AudioPlayerFrameModifier())
42 | }
43 | }
44 | }
45 |
46 | @available(iOS 13.0, *)
47 | private struct AudioPlayerView: UIViewControllerRepresentable {
48 | var sourceURL: URL
49 | var looping: Bool
50 | var autoPlay: Bool
51 | var isVisible: Bool
52 |
53 | func makeUIViewController(context: Context) -> AVPlayerViewController {
54 | AudioPlayerViewController(sourceURL: sourceURL, looping: looping)
55 | }
56 |
57 | func updateUIViewController(_ viewController: AVPlayerViewController, context: Context) {
58 | if !isVisible {
59 | viewController.player?.pause()
60 | } else if autoPlay {
61 | viewController.player?.play()
62 | }
63 | }
64 | }
65 |
66 | @available(iOS 13.0, *)
67 | private class AudioPlayerViewController: AVPlayerViewController {
68 | private var looper: AVPlayerLooper?
69 |
70 | init(sourceURL: URL, looping: Bool) {
71 | super.init(nibName: nil, bundle: nil)
72 |
73 | let playerItem = AVPlayerItem(url: sourceURL)
74 |
75 | if looping {
76 | let player = AVQueuePlayer()
77 | self.player = player
78 | self.looper = AVPlayerLooper(player: player, templateItem: playerItem)
79 | } else {
80 | player = AVPlayer(playerItem: playerItem)
81 | }
82 | }
83 |
84 | required init?(coder: NSCoder) {
85 | fatalError("init(coder:) has not been implemented")
86 | }
87 | }
88 |
89 | @available(iOS 13.0, *)
90 | fileprivate struct AudioPlayerFrameModifier: ViewModifier {
91 |
92 | @ViewBuilder
93 | func body(content: Content) -> some View {
94 | if #available(iOS 16.0, *) {
95 | content.frame(height: 110)
96 | } else {
97 | content.frame(height: 44)
98 | }
99 | }
100 | }
101 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Views/CollectionView.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import JudoModel
17 | import SwiftUI
18 |
19 | @available(iOS 13.0, *)
20 | struct CollectionView: View {
21 | @Environment(\.data) private var data
22 | @Environment(\.urlParameters) private var urlParameters
23 | @Environment(\.userInfo) private var userInfo
24 | var collection: Collection
25 |
26 | var body: some View {
27 | if let items = items {
28 | ForEach(Array(zip(items.indices, items)), id: \.0) { index, item in
29 | ForEach(layers) { layer in
30 | LayerView(layer: layer)
31 | .environment(\.collectionIndex, index)
32 | .environment(\.data, item)
33 | }
34 | }
35 | }
36 | }
37 |
38 | private var items: [Any]? {
39 | collection.items(
40 | data: data,
41 | urlParameters: urlParameters,
42 | userInfo: userInfo
43 | )
44 | }
45 |
46 | private var layers: [Layer] {
47 | collection.children.compactMap { $0 as? Layer }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Views/ConditionalView.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import JudoModel
17 | import SwiftUI
18 |
19 | @available(iOS 13.0, *)
20 | struct ConditionalView: View {
21 | @Environment(\.data) private var data
22 | @Environment(\.urlParameters) private var urlParameters
23 | @Environment(\.userInfo) private var userInfo
24 | var conditional: Conditional
25 |
26 | var body: some View {
27 | if allConditionsSatisfied {
28 | ForEach(conditional.children.compactMap { $0 as? Layer }) {
29 | LayerView(layer: $0)
30 | }
31 | }
32 | }
33 |
34 | private var allConditionsSatisfied: Bool {
35 | conditional.conditions.allSatisfy { condition in
36 | condition.isSatisfied(
37 | data: data,
38 | urlParameters: urlParameters,
39 | userInfo: userInfo
40 | )
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Views/DividerView.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct DividerView: View {
21 | var divider: JudoModel.Divider
22 |
23 | var body: some View {
24 | RealizeColor(divider.backgroundColor) { backgroundColor in
25 | SwiftUI.Divider().background(backgroundColor)
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Views/HStackView.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct HStackView: View {
21 | var stack: JudoModel.HStack
22 |
23 | var body: some View {
24 | SwiftUI.HStack(alignment: stack.alignment.swiftUIValue, spacing: stack.spacing) {
25 | ForEach(orderedLayers) {
26 | LayerView(layer: $0)
27 | }
28 | }
29 | }
30 |
31 | private var orderedLayers: [Layer] {
32 | stack.children.compactMap { $0 as? Layer }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Views/IconView.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct IconView: View {
21 | var icon: Icon
22 |
23 | var body: some View {
24 | RealizeColor(icon.color) { color in
25 | SwiftUI.Image(systemName: icon.icon.symbolName)
26 | .foregroundColor(color)
27 | .font(SwiftUI.Font.system(size: CGFloat(icon.pointSize)))
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Views/RectangleView.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct RectangleView: View {
21 | var rectangle: JudoModel.Rectangle
22 |
23 | @Environment(\.colorScheme) private var colorScheme
24 | @Environment(\.colorSchemeContrast) private var colorSchemeContrast
25 |
26 | @ViewBuilder
27 | var body: some View {
28 | // For some reason SwiftUI's Rectangle will not allow you apply both a fill and a border so
29 | // we must use a ZStack to apply both. The trailing compositingGroup modifier ensures that
30 | // the ShadowModifier renders properly.
31 | SwiftUI.ZStack {
32 | switch rectangle.fill {
33 | case .flat(let color):
34 | RealizeColor(color) { color in
35 | RoundedRectangle(
36 | cornerRadius: CGFloat(rectangle.cornerRadius),
37 | style: .circular
38 | )
39 | .fill(color)
40 | }
41 | case .gradient(let gradientVariants):
42 | RoundedRectangle(
43 | cornerRadius: CGFloat(rectangle.cornerRadius),
44 | style: .circular
45 | )
46 | .fill(
47 | gradientVariants.resolve(colorScheme: colorScheme, colorSchemeContrast: colorSchemeContrast).swiftUIGradient()
48 | )
49 | }
50 |
51 | if let border = rectangle.border {
52 | RealizeColor(border.color) { borderColor in
53 | RoundedRectangle(
54 | cornerRadius: CGFloat(rectangle.cornerRadius),
55 | style: .circular
56 | )
57 | .strokeBorder(lineWidth: CGFloat(border.width), antialiased: true)
58 | .foregroundColor(borderColor)
59 | }
60 | }
61 | }
62 | .compositingGroup()
63 | }
64 | }
65 |
66 | @available(iOS 13.0, *)
67 | private extension GradientVariants {
68 | func resolve(colorScheme: ColorScheme, colorSchemeContrast: ColorSchemeContrast) -> JudoModel.Gradient {
69 | if colorScheme == .dark && colorSchemeContrast == .increased {
70 | return darkModeHighContrast ?? self.default
71 | } else if colorScheme == .dark {
72 | return darkMode ?? self.default
73 | } else if colorSchemeContrast == .increased {
74 | return highContrast ?? self.default
75 | } else {
76 | return self.default
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Views/TextView.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct TextView: View {
21 | @Environment(\.data) private var data
22 | @Environment(\.stringTable) private var stringTable
23 | @Environment(\.urlParameters) private var urlParameters
24 | @Environment(\.userInfo) private var userInfo
25 |
26 | var text: JudoModel.Text
27 |
28 | var body: some View {
29 | let textString = stringTable.resolve(key: text.text)
30 |
31 | if let textValue = textString.evaluatingExpressions(data: data, urlParameters: urlParameters, userInfo: userInfo) {
32 | RealizeColor(self.text.textColor) { textColor in
33 | SwiftUI.Text(transformed(textValue))
34 | .modifier(
35 | FontModifier(font: self.text.font)
36 | )
37 | .foregroundColor(textColor)
38 | }
39 | .multilineTextAlignment(uiTextAlignment)
40 | .lineLimit(self.text.lineLimit)
41 | .fixedSize(horizontal: false, vertical: true)
42 | }
43 | }
44 |
45 | private func transformed(_ text: String) -> String {
46 | switch self.text.transform {
47 | case .lowercase:
48 | return text.lowercased()
49 | case .uppercase:
50 | return text.uppercased()
51 | case .none:
52 | return text
53 | }
54 | }
55 |
56 | private var uiTextAlignment: SwiftUI.TextAlignment {
57 | switch text.textAlignment {
58 | case .center:
59 | return .center
60 | case .leading:
61 | return .leading
62 | case .trailing:
63 | return .trailing
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Views/VStackView.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct VStackView: View {
21 | var stack: JudoModel.VStack
22 |
23 | var body: some View {
24 | SwiftUI.VStack(alignment: stack.alignment.swiftUIValue, spacing: stack.spacing) {
25 | ForEach(orderedLayers) {
26 | LayerView(layer: $0)
27 | }
28 | }
29 | }
30 |
31 | private var orderedLayers: [Layer] {
32 | stack.children.compactMap { $0 as? Layer }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Sources/JudoSDK/UI/Views/ZStackView.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import SwiftUI
17 | import JudoModel
18 |
19 | @available(iOS 13.0, *)
20 | struct ZStackView: View {
21 | var stack: JudoModel.ZStack
22 |
23 | var body: some View {
24 | SwiftUI.ZStack(alignment: stack.alignment.swiftUIValue) {
25 | ForEach(orderedLayers) {
26 | LayerView(layer: $0)
27 | }
28 | }
29 | }
30 |
31 | private var orderedLayers: [Layer] {
32 | stack.children.compactMap { $0 as? Layer }.reversed()
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Tests/JudoServiceTests/JSONSerializationTests.swift:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2020-present, Rover Labs, Inc. All rights reserved.
2 | // You are hereby granted a non-exclusive, worldwide, royalty-free license to use,
3 | // copy, modify, and distribute this software in source code or binary form for use
4 | // in connection with the web services and APIs provided by Rover.
5 | //
6 | // This copyright notice shall be included in all copies or substantial portions of
7 | // the software.
8 | //
9 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
10 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
11 | // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
12 | // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
13 | // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 | // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
15 |
16 | import XCTest
17 | @testable import JudoSDK
18 |
19 | class JSONSerializationTests: XCTestCase {
20 |
21 | override func setUpWithError() throws {
22 | // Put setup code here. This method is called before the invocation of each test method in the class.
23 | }
24 |
25 | override func tearDownWithError() throws {
26 | // Put teardown code here. This method is called after the invocation of each test method in the class.
27 | }
28 |
29 | func testValueForKeyPath() throws {
30 | let exampleData = [
31 | "hello": 42
32 | ]
33 |
34 | let value = JSONSerialization.value(forKeyPath: "data.hello", data: exampleData, urlParameters: [:], userInfo: [:])
35 | XCTAssertEqual(value as! Int, 42)
36 | }
37 |
38 | func testMissingValueForKeyPath() throws {
39 | let exampleData = [
40 | "another": 42
41 | ]
42 |
43 | let value = JSONSerialization.value(forKeyPath: "data.missing", data: exampleData, urlParameters: [:], userInfo: [:])
44 | XCTAssertNil(value)
45 | }
46 |
47 | func testKeyPathTraversal() throws {
48 | let exampleData = [
49 | "nested": [
50 | "hello": 42,
51 | "attribute_with.period": 69,
52 |
53 | // because you know some deranged API out there will do this.
54 | "attribute_with_trailing_period.": 1337,
55 | ".attribute_with_leading_period": 7331
56 | ],
57 | "flattened.attributes": [
58 | "hello": 24
59 | ]
60 | ]
61 |
62 | let nestedValue = JSONSerialization.value(forKeyPath: "data.nested.hello", data: exampleData, urlParameters: [:], userInfo: [:])
63 | XCTAssertEqual(nestedValue as! Int, 42)
64 |
65 | let dictValue = JSONSerialization.value(forKeyPath: "data.nested", data: exampleData, urlParameters: [:], userInfo: [:])
66 | XCTAssert(dictValue is [String: Any])
67 |
68 | let value = JSONSerialization.value(forKeyPath: "data.flattened.attributes.hello", data: exampleData, urlParameters: [:], userInfo: [:])
69 | XCTAssertEqual(value as! Int, 24)
70 |
71 | let keyWithPeriodValue = JSONSerialization.value(forKeyPath: "data.nested.attribute_with.period", data: exampleData, urlParameters: [:], userInfo: [:])
72 | XCTAssertEqual(keyWithPeriodValue as! Int, 69)
73 |
74 | let derangedLeadingPeriodValue = JSONSerialization.value(forKeyPath: "data.nested..attribute_with_leading_period", data: exampleData, urlParameters: [:], userInfo: [:])
75 | XCTAssertEqual(derangedLeadingPeriodValue as! Int, 7331)
76 |
77 | let derangedTrailingPeriodValue = JSONSerialization.value(forKeyPath: "data.nested.attribute_with_trailing_period.", data: exampleData, urlParameters: [:], userInfo: [:])
78 | XCTAssertEqual(derangedTrailingPeriodValue as! Int, 1337)
79 | }
80 | }
81 |
--------------------------------------------------------------------------------