turbo-native-initializer 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/LICENSE.txt +21 -0
- data/README.md +53 -0
- data/Rakefile +2 -0
- data/exe/turbo-native-initializer +3 -0
- data/lib/turbo-native-initializer.rb +1 -0
- data/lib/turbo_native_initializer/generator.rb +79 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/.gitignore +1 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/build.gradle.kts.tt +44 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/proguard-rules.pro +21 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/debug/AndroidManifest.xml.tt +4 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/AndroidManifest.xml.tt +29 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/assets/json/configuration.json +11 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/base/NavDestination.kt.tt +69 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebFragment.kt.tt +37 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebHomeFragment.kt.tt +15 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebModalFragment.kt.tt +17 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/main/MainActivity.kt.tt +18 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/main/MainSessionNavHostFragment.kt.tt +37 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/util/Constants.kt.tt +8 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/anim/nav_slide_enter.xml +10 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/anim/nav_slide_exit.xml +7 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/anim/nav_slide_pop_enter.xml +15 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/anim/nav_slide_pop_exit.xml +15 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/anim/overshoot_interpolator.xml +4 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/drawable/ic_close.xml +5 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/drawable/ic_launcher_foreground.xml +17 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/layout/activity_main.xml.tt +17 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/layout/fragment_web_home.xml +36 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/layout/toolbar_progress.xml +13 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/menu/web.xml +14 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/values/colors.xml +5 -0
- data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/values/themes.xml.tt +5 -0
- data/lib/turbo_native_initializer/templates/android_stack/build.gradle.kts +5 -0
- data/lib/turbo_native_initializer/templates/android_stack/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/lib/turbo_native_initializer/templates/android_stack/gradle/wrapper/gradle-wrapper.properties +6 -0
- data/lib/turbo_native_initializer/templates/android_stack/gradle.properties +23 -0
- data/lib/turbo_native_initializer/templates/android_stack/gradlew +185 -0
- data/lib/turbo_native_initializer/templates/android_stack/gradlew.bat +89 -0
- data/lib/turbo_native_initializer/templates/android_stack/local.properties +10 -0
- data/lib/turbo_native_initializer/templates/android_stack/settings.gradle.kts.tt +17 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/.gitignore +1 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/build.gradle.kts.tt +44 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/proguard-rules.pro +21 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/debug/AndroidManifest.xml.tt +4 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/AndroidManifest.xml.tt +29 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/assets/json/configuration.json +11 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/base/NavDestination.kt.tt +69 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebFragment.kt.tt +29 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebHomeFragment.kt.tt +15 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebModalFragment.kt.tt +17 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/main/MainActivity.kt.tt +47 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/main/TabOneSessionNavHostFragment.kt.tt +37 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/main/TabTwoSessionNavHostFragment.kt.tt +37 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/util/Constants.kt.tt +8 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/anim/nav_slide_enter.xml +10 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/anim/nav_slide_exit.xml +7 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/anim/nav_slide_pop_enter.xml +15 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/anim/nav_slide_pop_exit.xml +15 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/anim/overshoot_interpolator.xml +4 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/drawable/ic_close.xml +5 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/drawable/ic_home.xml +5 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/drawable/ic_launcher_foreground.xml +17 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/drawable/ic_settings.xml +5 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/layout/activity_main.xml.tt +34 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/layout/fragment_web_home.xml +36 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/layout/toolbar_progress.xml +13 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/menu/bottom_navigation_menu.xml +12 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/menu/web.xml +14 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/values/colors.xml +5 -0
- data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/values/themes.xml.tt +5 -0
- data/lib/turbo_native_initializer/templates/android_tabs/build.gradle.kts +5 -0
- data/lib/turbo_native_initializer/templates/android_tabs/gradle/wrapper/gradle-wrapper.jar +0 -0
- data/lib/turbo_native_initializer/templates/android_tabs/gradle/wrapper/gradle-wrapper.properties +6 -0
- data/lib/turbo_native_initializer/templates/android_tabs/gradle.properties +23 -0
- data/lib/turbo_native_initializer/templates/android_tabs/gradlew +185 -0
- data/lib/turbo_native_initializer/templates/android_tabs/gradlew.bat +89 -0
- data/lib/turbo_native_initializer/templates/android_tabs/local.properties +10 -0
- data/lib/turbo_native_initializer/templates/android_tabs/settings.gradle.kts.tt +17 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Configuration/Info.plist +29 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Configuration/path-configuration.json +10 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Controllers/ErrorPresenter.swift +74 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Controllers/TurboNavigationController.swift +123 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Controllers/ViewController.swift +20 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Delegates/AppDelegate.swift +8 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Delegates/SceneDelegate.swift.tt +139 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/AppIcon.appiconset/turbo.png +0 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/Contents.json +6 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/SplashIcon.imageset/Contents.json +21 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/SplashIcon.imageset/turbo.png +0 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Base.lproj/LaunchScreen.storyboard +39 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Base.lproj/Main.storyboard.tt +32 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/TurboNativeProject.swift.tt +10 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject.xcodeproj/project.pbxproj.tt +436 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +14 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Configuration/Info.plist +29 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Configuration/path-configuration.json +10 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Controllers/ErrorPresenter.swift +74 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Controllers/TurboNavigationController.swift +123 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Controllers/ViewController.swift +20 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Delegates/AppDelegate.swift +8 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Delegates/SceneDelegate.swift.tt +156 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/AppIcon.appiconset/turbo.png +0 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/Contents.json +6 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/SplashIcon.imageset/Contents.json +21 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/SplashIcon.imageset/turbo.png +0 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Base.lproj/LaunchScreen.storyboard +39 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Base.lproj/Main.storyboard +69 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/TurboNativeProject.swift.tt +10 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject.xcodeproj/project.pbxproj.tt +436 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
- data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +14 -0
- data/lib/turbo_native_initializer/version.rb +3 -0
- data/lib/turbo_native_initializer.rb +5 -0
- metadata +199 -0
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import UIKit
|
|
3
|
+
import Turbo
|
|
4
|
+
|
|
5
|
+
class TurboNavigationController : UINavigationController {
|
|
6
|
+
|
|
7
|
+
var session: Session!
|
|
8
|
+
var modalSession: Session!
|
|
9
|
+
|
|
10
|
+
func push(url: URL) {
|
|
11
|
+
let properties = session.pathConfiguration?.properties(for: url) ?? [:]
|
|
12
|
+
route(url: url, options: VisitOptions(action: .advance), properties: properties)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
func route(url: URL, options: VisitOptions, properties: PathProperties) {
|
|
16
|
+
// This is a simplified version of how you might build out the routing
|
|
17
|
+
// and navigation functions of your app. In a real app, these would be separate objects
|
|
18
|
+
|
|
19
|
+
// Dismiss any modals when receiving a new navigation
|
|
20
|
+
if presentedViewController != nil {
|
|
21
|
+
dismiss(animated: true)
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// - Create view controller appropriate for url/properties
|
|
25
|
+
// - Navigate to that with the correct presentation
|
|
26
|
+
let viewController = makeViewController(for: url, properties: properties)
|
|
27
|
+
navigate(to: viewController, action: options.action, properties: properties)
|
|
28
|
+
|
|
29
|
+
// - Initiate the visit with Turbo
|
|
30
|
+
if isVisitable(properties) {
|
|
31
|
+
visit(viewController: viewController, with: options)
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
extension TurboNavigationController {
|
|
37
|
+
private func isModal(_ properties: PathProperties) -> Bool {
|
|
38
|
+
return properties["presentation"] as? String == "modal"
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private func isClearAll(_ properties: PathProperties) -> Bool {
|
|
42
|
+
return properties["presentation"] as? String == "clear-all"
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private func isPop(_ properties: PathProperties) -> Bool {
|
|
46
|
+
return properties["presentation"] as? String == "pop"
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
private func isRefresh(_ properties: PathProperties) -> Bool {
|
|
50
|
+
return properties["presentation"] as? String == "refresh"
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
private func isNone(_ properties: PathProperties) -> Bool {
|
|
54
|
+
return properties["presentation"] as? String == "none"
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
private func isReplaceAll(_ properties: PathProperties) -> Bool {
|
|
58
|
+
return properties["presentation"] as? String == "replace-all"
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
private func isReplace(_ properties: PathProperties) -> Bool {
|
|
62
|
+
return properties["presentation"] as? String == "replace"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
private func isVisitable(_ properties: PathProperties) -> Bool {
|
|
66
|
+
return properties["visitable"] as? Bool ?? true
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
private func makeViewController(for url: URL, properties: PathProperties = [:]) -> UIViewController {
|
|
70
|
+
// There are many options for determining how to map urls to view controllers
|
|
71
|
+
// The demo uses the path configuration for determining which view controller and presentation
|
|
72
|
+
// to use, but that's completely optional. You can use whatever logic you prefer to determine
|
|
73
|
+
// how you navigate and route different URLs.
|
|
74
|
+
|
|
75
|
+
if let viewController = properties["view-controller"] as? String {
|
|
76
|
+
switch viewController {
|
|
77
|
+
case "numbers":
|
|
78
|
+
assertionFailure("NumbersViewController is not implemented")
|
|
79
|
+
default:
|
|
80
|
+
assertionFailure("Invalid view controller, defaulting to WebView")
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
return ViewController(url: url)
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
private func navigate(to viewController: UIViewController, action: VisitAction, properties: PathProperties = [:], animated: Bool = true) {
|
|
88
|
+
let modalNavController = UINavigationController(rootViewController: viewController)
|
|
89
|
+
modalNavController.modalPresentationStyle = .fullScreen
|
|
90
|
+
|
|
91
|
+
if isModal(properties) {
|
|
92
|
+
present(modalNavController, animated: animated)
|
|
93
|
+
} else if isClearAll(properties) {
|
|
94
|
+
popToRootViewController(animated: true)
|
|
95
|
+
} else if isPop(properties) {
|
|
96
|
+
popViewController(animated: true)
|
|
97
|
+
} else if isRefresh(properties) {
|
|
98
|
+
session.reload()
|
|
99
|
+
} else if isNone(properties) {
|
|
100
|
+
// Will result in no navigation action being taken
|
|
101
|
+
} else if isReplaceAll(properties) {
|
|
102
|
+
setViewControllers([viewController], animated: false)
|
|
103
|
+
} else if isReplace(properties) || action == .replace {
|
|
104
|
+
setViewControllers(Array(viewControllers.dropLast()) + [viewController], animated: false)
|
|
105
|
+
} else {
|
|
106
|
+
pushViewController(viewController, animated: animated)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private func visit(viewController: UIViewController, with options: VisitOptions, modal: Bool = false) {
|
|
111
|
+
guard let visitable = viewController as? Visitable else { return }
|
|
112
|
+
|
|
113
|
+
// Each Session corresponds to a single web view. A good rule of thumb
|
|
114
|
+
// is to use a session per navigation stack. Here we're using a different session
|
|
115
|
+
// when presenting a modal. We keep that around for any modal presentations so
|
|
116
|
+
// we don't have to create more than we need since each new session incurs a cold boot visit cost
|
|
117
|
+
if modal {
|
|
118
|
+
modalSession.visit(visitable, options: options)
|
|
119
|
+
} else {
|
|
120
|
+
session.visit(visitable, options: options)
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
import Turbo
|
|
3
|
+
|
|
4
|
+
final class ViewController: VisitableViewController, ErrorPresenter {
|
|
5
|
+
override func viewDidLoad() {
|
|
6
|
+
super.viewDidLoad()
|
|
7
|
+
|
|
8
|
+
view.backgroundColor = .systemBackground
|
|
9
|
+
|
|
10
|
+
navigationItem.backButtonDisplayMode = .minimal
|
|
11
|
+
|
|
12
|
+
if presentingViewController != nil {
|
|
13
|
+
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(dismissModal))
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
@objc func dismissModal() {
|
|
18
|
+
dismiss(animated: true)
|
|
19
|
+
}
|
|
20
|
+
}
|
data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Delegates/AppDelegate.swift
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
@main
|
|
4
|
+
class AppDelegate: UIResponder, UIApplicationDelegate {
|
|
5
|
+
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
|
|
6
|
+
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
|
|
7
|
+
}
|
|
8
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
import WebKit
|
|
3
|
+
import SafariServices
|
|
4
|
+
import Turbo
|
|
5
|
+
|
|
6
|
+
final class SceneDelegate: UIResponder {
|
|
7
|
+
private static var sharedProcessPool = WKProcessPool()
|
|
8
|
+
|
|
9
|
+
var window: UIWindow?
|
|
10
|
+
|
|
11
|
+
private let baseURL = <%= name %>.baseURL
|
|
12
|
+
private let rootURL1 = <%= name %>.homeURL1
|
|
13
|
+
private let rootURL2 = <%= name %>.homeURL2
|
|
14
|
+
|
|
15
|
+
private var tabBarController: UITabBarController!
|
|
16
|
+
|
|
17
|
+
private lazy var navigationController1 = {
|
|
18
|
+
tabBarController.viewControllers![0] as! TurboNavigationController
|
|
19
|
+
}()
|
|
20
|
+
|
|
21
|
+
private lazy var navigationController2 = {
|
|
22
|
+
tabBarController.viewControllers![1] as! TurboNavigationController
|
|
23
|
+
}()
|
|
24
|
+
|
|
25
|
+
// MARK: - Setup
|
|
26
|
+
|
|
27
|
+
private func configureRootViewController() {
|
|
28
|
+
guard let window = window else { fatalError() }
|
|
29
|
+
|
|
30
|
+
window.tintColor = UIColor(named: "Tint")
|
|
31
|
+
|
|
32
|
+
tabBarController = (window.rootViewController as! UITabBarController)
|
|
33
|
+
|
|
34
|
+
navigationController1.session = session1
|
|
35
|
+
navigationController1.modalSession = modalSession
|
|
36
|
+
|
|
37
|
+
navigationController2.session = session2
|
|
38
|
+
navigationController2.modalSession = modalSession
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private func navigationController() -> TurboNavigationController {
|
|
42
|
+
tabBarController.selectedViewController as! TurboNavigationController
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
private func session() -> Session {
|
|
46
|
+
navigationController().session
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// MARK: - Sessions
|
|
50
|
+
|
|
51
|
+
private lazy var session1 = makeSession()
|
|
52
|
+
private lazy var session2 = makeSession()
|
|
53
|
+
private lazy var modalSession = makeSession()
|
|
54
|
+
|
|
55
|
+
private func makeSession() -> Session {
|
|
56
|
+
let configuration = WKWebViewConfiguration()
|
|
57
|
+
configuration.applicationNameForUserAgent = "Turbo Native iOS"
|
|
58
|
+
configuration.processPool = Self.sharedProcessPool
|
|
59
|
+
|
|
60
|
+
let webView = WKWebView(frame: .zero, configuration: configuration)
|
|
61
|
+
webView.uiDelegate = self
|
|
62
|
+
|
|
63
|
+
let session = Session(webView: webView)
|
|
64
|
+
session.delegate = self
|
|
65
|
+
session.pathConfiguration = pathConfiguration
|
|
66
|
+
return session
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// MARK: - Path Configuration
|
|
70
|
+
|
|
71
|
+
private lazy var pathConfiguration = PathConfiguration(sources: [
|
|
72
|
+
.file(Bundle.main.url(forResource: "path-configuration", withExtension: "json")!),
|
|
73
|
+
])
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
extension SceneDelegate: UIWindowSceneDelegate {
|
|
77
|
+
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
|
|
78
|
+
guard let _ = scene as? UIWindowScene else { return }
|
|
79
|
+
|
|
80
|
+
configureRootViewController()
|
|
81
|
+
|
|
82
|
+
navigationController1.route(url: rootURL1, options: VisitOptions(action: .replace), properties: [:])
|
|
83
|
+
navigationController2.route(url: rootURL2, options: VisitOptions(action: .replace), properties: [:])
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
extension SceneDelegate: SessionDelegate {
|
|
88
|
+
func session(_ session: Session, didProposeVisit proposal: VisitProposal) {
|
|
89
|
+
navigationController().route(url: proposal.url, options: proposal.options, properties: proposal.properties)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
func session(_ session: Session, didFailRequestForVisitable visitable: Visitable, error: Error) {
|
|
93
|
+
if let errorPresenter = visitable as? ErrorPresenter {
|
|
94
|
+
errorPresenter.presentError(error) { [weak self] in
|
|
95
|
+
self?.session().reload()
|
|
96
|
+
}
|
|
97
|
+
} else {
|
|
98
|
+
assertionFailure("Visit failed!")
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
// When a form submission completes in the modal session, we need to
|
|
103
|
+
// manually clear the snapshot cache in the default session, since we
|
|
104
|
+
// don't want potentially stale cached snapshots to be used
|
|
105
|
+
func sessionDidFinishFormSubmission(_ session: Session) {
|
|
106
|
+
if (session == modalSession) {
|
|
107
|
+
self.session().clearSnapshotCache()
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
func sessionDidLoadWebView(_ session: Session) {
|
|
112
|
+
session.webView.navigationDelegate = self
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
func sessionWebViewProcessDidTerminate(_ session: Session) {
|
|
116
|
+
session.reload()
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
extension SceneDelegate: WKNavigationDelegate {
|
|
121
|
+
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
|
122
|
+
if navigationAction.navigationType == .linkActivated {
|
|
123
|
+
// Any link that's not on the same domain as the Turbo root url will go through here
|
|
124
|
+
// Other links on the domain, but that have an extension that is non-html will also go here
|
|
125
|
+
// You can decide how to handle those, by default if you're not the navigationDelegate
|
|
126
|
+
// the Session will open them in the default browser
|
|
127
|
+
|
|
128
|
+
let url = navigationAction.request.url!
|
|
129
|
+
|
|
130
|
+
// For this demo, we'll load files from our domain in a SafariViewController so you
|
|
131
|
+
// don't need to leave the app. You might expand this in your app
|
|
132
|
+
// to open all audio/video/images in a native media viewer
|
|
133
|
+
if url.host == baseURL.host, !url.pathExtension.isEmpty {
|
|
134
|
+
let safariViewController = SFSafariViewController(url: url)
|
|
135
|
+
navigationController().present(safariViewController, animated: true)
|
|
136
|
+
} else {
|
|
137
|
+
UIApplication.shared.open(url)
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
decisionHandler(.cancel)
|
|
141
|
+
} else {
|
|
142
|
+
decisionHandler(.allow)
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
extension SceneDelegate: WKUIDelegate {
|
|
148
|
+
func webView(_ webView: WKWebView, runJavaScriptConfirmPanelWithMessage message: String, initiatedByFrame frame: WKFrameInfo, completionHandler: @escaping (Bool) -> Void) {
|
|
149
|
+
let confirm = UIAlertController(title: nil, message: message, preferredStyle: .alert)
|
|
150
|
+
confirm.addAction(UIAlertAction(title: "Cancel", style: .cancel) { _ in completionHandler(false) })
|
|
151
|
+
confirm.addAction(UIAlertAction(title: "OK", style: .default) { _ in completionHandler(true) })
|
|
152
|
+
|
|
153
|
+
// JavaScript alerts in Turbo Native
|
|
154
|
+
navigationController().present(confirm, animated: true)
|
|
155
|
+
}
|
|
156
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"images" : [
|
|
3
|
+
{
|
|
4
|
+
"filename" : "turbo.png",
|
|
5
|
+
"idiom" : "universal",
|
|
6
|
+
"scale" : "1x"
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"idiom" : "universal",
|
|
10
|
+
"scale" : "2x"
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"idiom" : "universal",
|
|
14
|
+
"scale" : "3x"
|
|
15
|
+
}
|
|
16
|
+
],
|
|
17
|
+
"info" : {
|
|
18
|
+
"author" : "xcode",
|
|
19
|
+
"version" : 1
|
|
20
|
+
}
|
|
21
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
|
3
|
+
<device id="retina5_9" orientation="portrait" appearance="light"/>
|
|
4
|
+
<dependencies>
|
|
5
|
+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
|
|
6
|
+
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
|
7
|
+
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
|
8
|
+
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
9
|
+
</dependencies>
|
|
10
|
+
<scenes>
|
|
11
|
+
<!--View Controller-->
|
|
12
|
+
<scene sceneID="EHf-IW-A2E">
|
|
13
|
+
<objects>
|
|
14
|
+
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
|
15
|
+
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
|
16
|
+
<rect key="frame" x="0.0" y="0.0" width="375" height="812"/>
|
|
17
|
+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
18
|
+
<subviews>
|
|
19
|
+
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" fixedFrame="YES" image="SplashIcon" translatesAutoresizingMaskIntoConstraints="NO" id="eXr-0W-qZz">
|
|
20
|
+
<rect key="frame" x="137" y="356" width="100" height="100"/>
|
|
21
|
+
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
|
|
22
|
+
</imageView>
|
|
23
|
+
</subviews>
|
|
24
|
+
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
|
25
|
+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
|
26
|
+
</view>
|
|
27
|
+
</viewController>
|
|
28
|
+
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
|
29
|
+
</objects>
|
|
30
|
+
<point key="canvasLocation" x="50.399999999999999" y="373.89162561576359"/>
|
|
31
|
+
</scene>
|
|
32
|
+
</scenes>
|
|
33
|
+
<resources>
|
|
34
|
+
<image name="SplashIcon" width="1024" height="1024"/>
|
|
35
|
+
<systemColor name="systemBackgroundColor">
|
|
36
|
+
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
|
37
|
+
</systemColor>
|
|
38
|
+
</resources>
|
|
39
|
+
</document>
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21701" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="33v-ad-2dz">
|
|
3
|
+
<device id="retina6_12" orientation="portrait" appearance="light"/>
|
|
4
|
+
<dependencies>
|
|
5
|
+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21679"/>
|
|
6
|
+
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
|
7
|
+
<capability name="System colors in document resources" minToolsVersion="11.0"/>
|
|
8
|
+
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
|
9
|
+
</dependencies>
|
|
10
|
+
<scenes>
|
|
11
|
+
<!--Item 2-->
|
|
12
|
+
<scene sceneID="GwE-Ch-DRP">
|
|
13
|
+
<objects>
|
|
14
|
+
<viewController id="cXb-wA-NUs" customClass="TurboNavigationController" customModule="ContactsIOS" customModuleProvider="target" sceneMemberID="viewController">
|
|
15
|
+
<view key="view" contentMode="scaleToFill" id="WTF-II-zfk">
|
|
16
|
+
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
|
17
|
+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
18
|
+
<viewLayoutGuide key="safeArea" id="CoL-dA-Hxa"/>
|
|
19
|
+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
|
20
|
+
</view>
|
|
21
|
+
<tabBarItem key="tabBarItem" title="Item 2" image="gear" catalog="system" id="rhZ-zi-yeq"/>
|
|
22
|
+
</viewController>
|
|
23
|
+
<placeholder placeholderIdentifier="IBFirstResponder" id="ife-PY-okT" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
|
24
|
+
</objects>
|
|
25
|
+
<point key="canvasLocation" x="1271" y="-647"/>
|
|
26
|
+
</scene>
|
|
27
|
+
<!--Item 1-->
|
|
28
|
+
<scene sceneID="pAD-IL-Hdw">
|
|
29
|
+
<objects>
|
|
30
|
+
<viewController id="0en-nE-vJA" customClass="TurboNavigationController" customModule="ContactsIOS" customModuleProvider="target" sceneMemberID="viewController">
|
|
31
|
+
<view key="view" contentMode="scaleToFill" id="bFn-PZ-ClM">
|
|
32
|
+
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
|
|
33
|
+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
|
34
|
+
<viewLayoutGuide key="safeArea" id="K5f-nY-Cgh"/>
|
|
35
|
+
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
|
|
36
|
+
</view>
|
|
37
|
+
<tabBarItem key="tabBarItem" title="Item 1" image="house" catalog="system" id="ZWo-HO-m4a"/>
|
|
38
|
+
</viewController>
|
|
39
|
+
<placeholder placeholderIdentifier="IBFirstResponder" id="GRr-XE-fAM" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
|
40
|
+
</objects>
|
|
41
|
+
<point key="canvasLocation" x="1270" y="-1254"/>
|
|
42
|
+
</scene>
|
|
43
|
+
<!--Tab Bar Controller-->
|
|
44
|
+
<scene sceneID="So3-hc-mhH">
|
|
45
|
+
<objects>
|
|
46
|
+
<tabBarController id="33v-ad-2dz" sceneMemberID="viewController">
|
|
47
|
+
<tabBar key="tabBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="fR1-GM-qEi">
|
|
48
|
+
<rect key="frame" x="0.0" y="0.0" width="393" height="49"/>
|
|
49
|
+
<autoresizingMask key="autoresizingMask"/>
|
|
50
|
+
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
|
51
|
+
</tabBar>
|
|
52
|
+
<connections>
|
|
53
|
+
<segue destination="0en-nE-vJA" kind="relationship" relationship="viewControllers" id="z0u-hS-Voh"/>
|
|
54
|
+
<segue destination="cXb-wA-NUs" kind="relationship" relationship="viewControllers" id="eJZ-00-JTF"/>
|
|
55
|
+
</connections>
|
|
56
|
+
</tabBarController>
|
|
57
|
+
<placeholder placeholderIdentifier="IBFirstResponder" id="KRh-ez-iFz" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
|
58
|
+
</objects>
|
|
59
|
+
<point key="canvasLocation" x="364" y="-951"/>
|
|
60
|
+
</scene>
|
|
61
|
+
</scenes>
|
|
62
|
+
<resources>
|
|
63
|
+
<image name="gear" catalog="system" width="128" height="122"/>
|
|
64
|
+
<image name="house" catalog="system" width="128" height="93"/>
|
|
65
|
+
<systemColor name="systemBackgroundColor">
|
|
66
|
+
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
|
67
|
+
</systemColor>
|
|
68
|
+
</resources>
|
|
69
|
+
</document>
|
data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/TurboNativeProject.swift.tt
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
|
|
3
|
+
struct <%= name %> {
|
|
4
|
+
private static let developmentURL = URL(string: "http://localhost:3000")!
|
|
5
|
+
private static let productionURL = URL(string: "https://turbo-native-demo.glitch.me")!
|
|
6
|
+
|
|
7
|
+
static var baseURL: URL { productionURL }
|
|
8
|
+
static var homeURL1: URL { baseURL.appendingPathComponent("/") }
|
|
9
|
+
static var homeURL2: URL { baseURL.appendingPathComponent("/") }
|
|
10
|
+
}
|