turbo-native-initializer 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
}
|