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.
Files changed (140) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +5 -0
  3. data/CODE_OF_CONDUCT.md +84 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +53 -0
  6. data/Rakefile +2 -0
  7. data/exe/turbo-native-initializer +3 -0
  8. data/lib/turbo-native-initializer.rb +1 -0
  9. data/lib/turbo_native_initializer/generator.rb +79 -0
  10. data/lib/turbo_native_initializer/templates/android_stack/app/.gitignore +1 -0
  11. data/lib/turbo_native_initializer/templates/android_stack/app/build.gradle.kts.tt +44 -0
  12. data/lib/turbo_native_initializer/templates/android_stack/app/proguard-rules.pro +21 -0
  13. data/lib/turbo_native_initializer/templates/android_stack/app/src/debug/AndroidManifest.xml.tt +4 -0
  14. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/AndroidManifest.xml.tt +29 -0
  15. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/assets/json/configuration.json +11 -0
  16. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/base/NavDestination.kt.tt +69 -0
  17. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebFragment.kt.tt +37 -0
  18. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebHomeFragment.kt.tt +15 -0
  19. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebModalFragment.kt.tt +17 -0
  20. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/main/MainActivity.kt.tt +18 -0
  21. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/main/MainSessionNavHostFragment.kt.tt +37 -0
  22. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/java/dev/hotwire/turbo/turbonativeproject/util/Constants.kt.tt +8 -0
  23. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/anim/nav_slide_enter.xml +10 -0
  24. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/anim/nav_slide_exit.xml +7 -0
  25. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/anim/nav_slide_pop_enter.xml +15 -0
  26. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/anim/nav_slide_pop_exit.xml +15 -0
  27. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/anim/overshoot_interpolator.xml +4 -0
  28. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/drawable/ic_close.xml +5 -0
  29. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/drawable/ic_launcher_foreground.xml +17 -0
  30. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/layout/activity_main.xml.tt +17 -0
  31. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/layout/fragment_web_home.xml +36 -0
  32. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/layout/toolbar_progress.xml +13 -0
  33. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/menu/web.xml +14 -0
  34. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
  35. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
  36. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  37. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  38. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  39. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  40. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  41. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  42. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/values/colors.xml +5 -0
  43. data/lib/turbo_native_initializer/templates/android_stack/app/src/main/res/values/themes.xml.tt +5 -0
  44. data/lib/turbo_native_initializer/templates/android_stack/build.gradle.kts +5 -0
  45. data/lib/turbo_native_initializer/templates/android_stack/gradle/wrapper/gradle-wrapper.jar +0 -0
  46. data/lib/turbo_native_initializer/templates/android_stack/gradle/wrapper/gradle-wrapper.properties +6 -0
  47. data/lib/turbo_native_initializer/templates/android_stack/gradle.properties +23 -0
  48. data/lib/turbo_native_initializer/templates/android_stack/gradlew +185 -0
  49. data/lib/turbo_native_initializer/templates/android_stack/gradlew.bat +89 -0
  50. data/lib/turbo_native_initializer/templates/android_stack/local.properties +10 -0
  51. data/lib/turbo_native_initializer/templates/android_stack/settings.gradle.kts.tt +17 -0
  52. data/lib/turbo_native_initializer/templates/android_tabs/app/.gitignore +1 -0
  53. data/lib/turbo_native_initializer/templates/android_tabs/app/build.gradle.kts.tt +44 -0
  54. data/lib/turbo_native_initializer/templates/android_tabs/app/proguard-rules.pro +21 -0
  55. data/lib/turbo_native_initializer/templates/android_tabs/app/src/debug/AndroidManifest.xml.tt +4 -0
  56. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/AndroidManifest.xml.tt +29 -0
  57. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/assets/json/configuration.json +11 -0
  58. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/base/NavDestination.kt.tt +69 -0
  59. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebFragment.kt.tt +29 -0
  60. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebHomeFragment.kt.tt +15 -0
  61. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/features/web/WebModalFragment.kt.tt +17 -0
  62. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/main/MainActivity.kt.tt +47 -0
  63. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/main/TabOneSessionNavHostFragment.kt.tt +37 -0
  64. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/main/TabTwoSessionNavHostFragment.kt.tt +37 -0
  65. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/java/dev/hotwire/turbo/turbonativeproject/util/Constants.kt.tt +8 -0
  66. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/anim/nav_slide_enter.xml +10 -0
  67. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/anim/nav_slide_exit.xml +7 -0
  68. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/anim/nav_slide_pop_enter.xml +15 -0
  69. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/anim/nav_slide_pop_exit.xml +15 -0
  70. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/anim/overshoot_interpolator.xml +4 -0
  71. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/drawable/ic_close.xml +5 -0
  72. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/drawable/ic_home.xml +5 -0
  73. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/drawable/ic_launcher_foreground.xml +17 -0
  74. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/drawable/ic_settings.xml +5 -0
  75. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/layout/activity_main.xml.tt +34 -0
  76. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/layout/fragment_web_home.xml +36 -0
  77. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/layout/toolbar_progress.xml +13 -0
  78. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/menu/bottom_navigation_menu.xml +12 -0
  79. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/menu/web.xml +14 -0
  80. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml +5 -0
  81. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml +5 -0
  82. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xhdpi/ic_launcher.png +0 -0
  83. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png +0 -0
  84. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xxhdpi/ic_launcher.png +0 -0
  85. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png +0 -0
  86. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png +0 -0
  87. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png +0 -0
  88. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/values/colors.xml +5 -0
  89. data/lib/turbo_native_initializer/templates/android_tabs/app/src/main/res/values/themes.xml.tt +5 -0
  90. data/lib/turbo_native_initializer/templates/android_tabs/build.gradle.kts +5 -0
  91. data/lib/turbo_native_initializer/templates/android_tabs/gradle/wrapper/gradle-wrapper.jar +0 -0
  92. data/lib/turbo_native_initializer/templates/android_tabs/gradle/wrapper/gradle-wrapper.properties +6 -0
  93. data/lib/turbo_native_initializer/templates/android_tabs/gradle.properties +23 -0
  94. data/lib/turbo_native_initializer/templates/android_tabs/gradlew +185 -0
  95. data/lib/turbo_native_initializer/templates/android_tabs/gradlew.bat +89 -0
  96. data/lib/turbo_native_initializer/templates/android_tabs/local.properties +10 -0
  97. data/lib/turbo_native_initializer/templates/android_tabs/settings.gradle.kts.tt +17 -0
  98. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Configuration/Info.plist +29 -0
  99. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Configuration/path-configuration.json +10 -0
  100. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Controllers/ErrorPresenter.swift +74 -0
  101. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Controllers/TurboNavigationController.swift +123 -0
  102. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Controllers/ViewController.swift +20 -0
  103. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Delegates/AppDelegate.swift +8 -0
  104. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Delegates/SceneDelegate.swift.tt +139 -0
  105. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  106. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
  107. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/AppIcon.appiconset/turbo.png +0 -0
  108. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/Contents.json +6 -0
  109. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/SplashIcon.imageset/Contents.json +21 -0
  110. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Assets.xcassets/SplashIcon.imageset/turbo.png +0 -0
  111. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Base.lproj/LaunchScreen.storyboard +39 -0
  112. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/Resources/Base.lproj/Main.storyboard.tt +32 -0
  113. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject/TurboNativeProject.swift.tt +10 -0
  114. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject.xcodeproj/project.pbxproj.tt +436 -0
  115. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  116. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  117. data/lib/turbo_native_initializer/templates/ios_stack/TurboNativeProject.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +14 -0
  118. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Configuration/Info.plist +29 -0
  119. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Configuration/path-configuration.json +10 -0
  120. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Controllers/ErrorPresenter.swift +74 -0
  121. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Controllers/TurboNavigationController.swift +123 -0
  122. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Controllers/ViewController.swift +20 -0
  123. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Delegates/AppDelegate.swift +8 -0
  124. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Delegates/SceneDelegate.swift.tt +156 -0
  125. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
  126. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json +14 -0
  127. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/AppIcon.appiconset/turbo.png +0 -0
  128. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/Contents.json +6 -0
  129. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/SplashIcon.imageset/Contents.json +21 -0
  130. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Assets.xcassets/SplashIcon.imageset/turbo.png +0 -0
  131. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Base.lproj/LaunchScreen.storyboard +39 -0
  132. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/Resources/Base.lproj/Main.storyboard +69 -0
  133. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject/TurboNativeProject.swift.tt +10 -0
  134. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject.xcodeproj/project.pbxproj.tt +436 -0
  135. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject.xcodeproj/project.xcworkspace/contents.xcworkspacedata +7 -0
  136. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist +8 -0
  137. data/lib/turbo_native_initializer/templates/ios_tabs/TurboNativeProject.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved +14 -0
  138. data/lib/turbo_native_initializer/version.rb +3 -0
  139. data/lib/turbo_native_initializer.rb +5 -0
  140. 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
+ }
@@ -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
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "colors" : [
3
+ {
4
+ "idiom" : "universal"
5
+ }
6
+ ],
7
+ "info" : {
8
+ "author" : "xcode",
9
+ "version" : 1
10
+ }
11
+ }
@@ -0,0 +1,14 @@
1
+ {
2
+ "images" : [
3
+ {
4
+ "filename" : "turbo.png",
5
+ "idiom" : "universal",
6
+ "platform" : "ios",
7
+ "size" : "1024x1024"
8
+ }
9
+ ],
10
+ "info" : {
11
+ "author" : "xcode",
12
+ "version" : 1
13
+ }
14
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "info" : {
3
+ "author" : "xcode",
4
+ "version" : 1
5
+ }
6
+ }
@@ -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
+ }
@@ -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>
@@ -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
+ }