Skip to content

Commit

Permalink
Merge pull request #142 from hotwired/strada-sample
Browse files Browse the repository at this point in the history
Strada sample components in the Demo app
  • Loading branch information
jayohms authored Sep 20, 2023
2 parents 7ce71d4 + eb88747 commit c476bac
Show file tree
Hide file tree
Showing 13 changed files with 466 additions and 31 deletions.
2 changes: 2 additions & 0 deletions Demo/AppDelegate.swift
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import UIKit
import Turbo
import Strada

@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
#if DEBUG
TurboLog.debugLoggingEnabled = true
Strada.config.debugLoggingEnabled = true
#endif

return true
Expand Down
66 changes: 62 additions & 4 deletions Demo/Demo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
84ACD7322AAE743300234C57 /* Turbo in Frameworks */ = {isa = PBXBuildFile; productRef = 84ACD7312AAE743300234C57 /* Turbo */; };
C106CBE3257FF87700498F6F /* ErrorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C106CBE2257FF87700498F6F /* ErrorPresenter.swift */; };
C10DF228257AB81D009412E7 /* path-configuration.json in Resources */ = {isa = PBXBuildFile; fileRef = C10DF227257AB81D009412E7 /* path-configuration.json */; };
C10DF242257AD845009412E7 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C10DF241257AD845009412E7 /* ViewController.swift */; };
C153F0082578057900926D30 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C153F0072578057900926D30 /* AppDelegate.swift */; };
C153F00A2578057900926D30 /* SceneController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C153F0092578057900926D30 /* SceneController.swift */; };
C153F00F2578057900926D30 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C153F00D2578057900926D30 /* Main.storyboard */; };
Expand All @@ -19,6 +18,13 @@
C153F03525784BEA00926D30 /* NumbersViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C153F03425784BEA00926D30 /* NumbersViewController.swift */; };
C175FE782579905300C8DF50 /* Demo.swift in Sources */ = {isa = PBXBuildFile; fileRef = C175FE772579905300C8DF50 /* Demo.swift */; };
CB4FB651273AE23B00119FD3 /* TurboNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB4FB650273AE23B00119FD3 /* TurboNavigationController.swift */; };
E226F7822AB1B7F20059D594 /* Strada in Frameworks */ = {isa = PBXBuildFile; productRef = E226F7812AB1B7F20059D594 /* Strada */; };
E226F7842AB1BBF30059D594 /* TurboWebViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = E226F7832AB1BBF30059D594 /* TurboWebViewController.swift */; };
E226F7872AB1BE030059D594 /* WKWebViewConfiguration+App.swift in Sources */ = {isa = PBXBuildFile; fileRef = E226F7862AB1BE030059D594 /* WKWebViewConfiguration+App.swift */; };
E226F78A2AB1BF880059D594 /* FormComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E226F7892AB1BF880059D594 /* FormComponent.swift */; };
E226F78C2AB1CE2E0059D594 /* BridgeComponent+App.swift in Sources */ = {isa = PBXBuildFile; fileRef = E226F78B2AB1CE2E0059D594 /* BridgeComponent+App.swift */; };
E226F78E2AB1D2C20059D594 /* MenuComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E226F78D2AB1D2C20059D594 /* MenuComponent.swift */; };
E226F7902AB1D7260059D594 /* OverflowMenuComponent.swift in Sources */ = {isa = PBXBuildFile; fileRef = E226F78F2AB1D7260059D594 /* OverflowMenuComponent.swift */; };
/* End PBXBuildFile section */

/* Begin PBXCopyFilesBuildPhase section */
Expand All @@ -38,7 +44,6 @@
84ACD72F2AAE733C00234C57 /* turbo-ios */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = "turbo-ios"; path = ..; sourceTree = "<group>"; };
C106CBE2257FF87700498F6F /* ErrorPresenter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ErrorPresenter.swift; sourceTree = "<group>"; };
C10DF227257AB81D009412E7 /* path-configuration.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "path-configuration.json"; sourceTree = "<group>"; };
C10DF241257AD845009412E7 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; };
C153F0042578057900926D30 /* Turbo Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Turbo Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
C153F0072578057900926D30 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
C153F0092578057900926D30 /* SceneController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneController.swift; sourceTree = "<group>"; };
Expand All @@ -50,6 +55,12 @@
C153F03425784BEA00926D30 /* NumbersViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NumbersViewController.swift; sourceTree = "<group>"; };
C175FE772579905300C8DF50 /* Demo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Demo.swift; sourceTree = "<group>"; };
CB4FB650273AE23B00119FD3 /* TurboNavigationController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurboNavigationController.swift; sourceTree = "<group>"; };
E226F7832AB1BBF30059D594 /* TurboWebViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurboWebViewController.swift; sourceTree = "<group>"; };
E226F7862AB1BE030059D594 /* WKWebViewConfiguration+App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WKWebViewConfiguration+App.swift"; sourceTree = "<group>"; };
E226F7892AB1BF880059D594 /* FormComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormComponent.swift; sourceTree = "<group>"; };
E226F78B2AB1CE2E0059D594 /* BridgeComponent+App.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BridgeComponent+App.swift"; sourceTree = "<group>"; };
E226F78D2AB1D2C20059D594 /* MenuComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuComponent.swift; sourceTree = "<group>"; };
E226F78F2AB1D7260059D594 /* OverflowMenuComponent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverflowMenuComponent.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand All @@ -58,6 +69,7 @@
buildActionMask = 2147483647;
files = (
84ACD7322AAE743300234C57 /* Turbo in Frameworks */,
E226F7822AB1B7F20059D594 /* Strada in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -100,11 +112,13 @@
C153F0062578057900926D30 /* Demo */ = {
isa = PBXGroup;
children = (
E226F7882AB1BF210059D594 /* Strada */,
E226F7852AB1BDF10059D594 /* Web */,
CB4FB64F273AE22800119FD3 /* Navigation */,
C175FE772579905300C8DF50 /* Demo.swift */,
C153F0072578057900926D30 /* AppDelegate.swift */,
C153F0092578057900926D30 /* SceneController.swift */,
C10DF241257AD845009412E7 /* ViewController.swift */,
E226F7832AB1BBF30059D594 /* TurboWebViewController.swift */,
C153F03425784BEA00926D30 /* NumbersViewController.swift */,
C106CBE2257FF87700498F6F /* ErrorPresenter.swift */,
C153F0102578057A00926D30 /* Assets.xcassets */,
Expand All @@ -125,6 +139,25 @@
path = Navigation;
sourceTree = "<group>";
};
E226F7852AB1BDF10059D594 /* Web */ = {
isa = PBXGroup;
children = (
E226F7862AB1BE030059D594 /* WKWebViewConfiguration+App.swift */,
);
path = Web;
sourceTree = "<group>";
};
E226F7882AB1BF210059D594 /* Strada */ = {
isa = PBXGroup;
children = (
E226F78B2AB1CE2E0059D594 /* BridgeComponent+App.swift */,
E226F7892AB1BF880059D594 /* FormComponent.swift */,
E226F78D2AB1D2C20059D594 /* MenuComponent.swift */,
E226F78F2AB1D7260059D594 /* OverflowMenuComponent.swift */,
);
path = Strada;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand All @@ -144,6 +177,7 @@
name = Demo;
packageProductDependencies = (
84ACD7312AAE743300234C57 /* Turbo */,
E226F7812AB1B7F20059D594 /* Strada */,
);
productName = Demo;
productReference = C153F0042578057900926D30 /* Turbo Demo.app */;
Expand Down Expand Up @@ -172,6 +206,9 @@
Base,
);
mainGroup = C153EFFB2578057900926D30;
packageReferences = (
E226F7802AB1B7F20059D594 /* XCRemoteSwiftPackageReference "strada-ios" */,
);
productRefGroup = C153F0052578057900926D30 /* Products */;
projectDirPath = "";
projectRoot = "";
Expand Down Expand Up @@ -200,12 +237,17 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
C10DF242257AD845009412E7 /* ViewController.swift in Sources */,
E226F7842AB1BBF30059D594 /* TurboWebViewController.swift in Sources */,
C153F03525784BEA00926D30 /* NumbersViewController.swift in Sources */,
C153F0082578057900926D30 /* AppDelegate.swift in Sources */,
E226F78A2AB1BF880059D594 /* FormComponent.swift in Sources */,
E226F78C2AB1CE2E0059D594 /* BridgeComponent+App.swift in Sources */,
CB4FB651273AE23B00119FD3 /* TurboNavigationController.swift in Sources */,
E226F7872AB1BE030059D594 /* WKWebViewConfiguration+App.swift in Sources */,
C175FE782579905300C8DF50 /* Demo.swift in Sources */,
C153F00A2578057900926D30 /* SceneController.swift in Sources */,
E226F78E2AB1D2C20059D594 /* MenuComponent.swift in Sources */,
E226F7902AB1D7260059D594 /* OverflowMenuComponent.swift in Sources */,
C106CBE3257FF87700498F6F /* ErrorPresenter.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
Expand Down Expand Up @@ -417,11 +459,27 @@
};
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */
E226F7802AB1B7F20059D594 /* XCRemoteSwiftPackageReference "strada-ios" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/hotwired/strada-ios.git";
requirement = {
branch = main;
kind = branch;
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
84ACD7312AAE743300234C57 /* Turbo */ = {
isa = XCSwiftPackageProductDependency;
productName = Turbo;
};
E226F7812AB1B7F20059D594 /* Strada */ = {
isa = XCSwiftPackageProductDependency;
package = E226F7802AB1B7F20059D594 /* XCRemoteSwiftPackageReference "strada-ios" */;
productName = Strada;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = C153EFFC2578057900926D30 /* Project object */;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
{
"pins" : [
{
"identity" : "cwlcatchexception",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mattgallagher/CwlCatchException.git",
"state" : {
"revision" : "3b123999de19bf04905bc1dfdb76f817b0f2cc00",
"version" : "2.1.2"
}
},
{
"identity" : "cwlpreconditiontesting",
"kind" : "remoteSourceControl",
"location" : "https://github.com/mattgallagher/CwlPreconditionTesting.git",
"state" : {
"revision" : "a23ded2c91df9156628a6996ab4f347526f17b6b",
"version" : "2.1.2"
}
},
{
"identity" : "nimble",
"kind" : "remoteSourceControl",
"location" : "https://github.com/quick/nimble",
"state" : {
"revision" : "1f3bde57bde12f5e7b07909848c071e9b73d6edc",
"version" : "10.0.0"
}
},
{
"identity" : "ohhttpstubs",
"kind" : "remoteSourceControl",
"location" : "https://github.com/AliSoftware/OHHTTPStubs",
"state" : {
"revision" : "12f19662426d0434d6c330c6974d53e2eb10ecd9",
"version" : "9.1.0"
}
},
{
"identity" : "quick",
"kind" : "remoteSourceControl",
"location" : "https://github.com/quick/quick",
"state" : {
"revision" : "f9d519828bb03dfc8125467d8f7b93131951124c",
"version" : "5.0.1"
}
},
{
"identity" : "strada-ios",
"kind" : "remoteSourceControl",
"location" : "https://github.com/hotwired/strada-ios.git",
"state" : {
"branch" : "main",
"revision" : "3f8e6a0a07d2361bb3a64a6e6a945124eed20ccf"
}
},
{
"identity" : "swifter",
"kind" : "remoteSourceControl",
"location" : "https://github.com/httpswift/swifter.git",
"state" : {
"revision" : "9483a5d459b45c3ffd059f7b55f9638e268632fd",
"version" : "1.5.0"
}
}
],
"version" : 2
}
4 changes: 2 additions & 2 deletions Demo/Navigation/TurboNavigationController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import Foundation
import UIKit
import Turbo
import Strada

class TurboNavigationController : UINavigationController {

Expand Down Expand Up @@ -76,7 +77,7 @@ extension TurboNavigationController {
}
}

return ViewController(url: url)
return TurboWebViewController(url: url)
}

private func navigate(to viewController: UIViewController, action: VisitAction, properties: PathProperties = [:], animated: Bool = true) {
Expand All @@ -99,7 +100,6 @@ extension TurboNavigationController {

private func visit(viewController: UIViewController, with options: VisitOptions, modal: Bool = false) {
guard let visitable = viewController as? Visitable else { return }

// Each Session corresponds to a single web view. A good rule of thumb
// is to use a session per navigation stack. Here we're using a different session
// when presenting a modal. We keep that around for any modal presentations so
Expand Down
12 changes: 7 additions & 5 deletions Demo/SceneController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import UIKit
import WebKit
import SafariServices
import Turbo
import Strada

final class SceneController: UIResponder {
private static var sharedProcessPool = WKProcessPool()
Expand Down Expand Up @@ -46,14 +47,15 @@ final class SceneController: UIResponder {
private lazy var modalSession = makeSession()

private func makeSession() -> Session {
let configuration = WKWebViewConfiguration()
configuration.applicationNameForUserAgent = "Turbo Native iOS"
configuration.processPool = Self.sharedProcessPool

let webView = WKWebView(frame: .zero, configuration: configuration)
let webView = WKWebView(frame: .zero,
configuration: .appConfiguration)
if #available(iOS 16.4, *) {
webView.isInspectable = true
}

// Initialize Strada bridge.
Bridge.initialize(webView)

let session = Session(webView: webView)
session.delegate = self
session.pathConfiguration = pathConfiguration
Expand Down
12 changes: 12 additions & 0 deletions Demo/Strada/BridgeComponent+App.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import Foundation
import Strada

extension BridgeComponent {
static var allTypes: [BridgeComponent.Type] {
[
FormComponent.self,
MenuComponent.self,
OverflowMenuComponent.self
]
}
}
79 changes: 79 additions & 0 deletions Demo/Strada/FormComponent.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import Foundation
import Strada
import UIKit

/// Bridge component to display a submit button in the native toolbar,
/// which will submit the form on the page when tapped.
final class FormComponent: BridgeComponent {
override class var name: String { "form" }

override func onReceive(message: Message) {
guard let event = Event(rawValue: message.event) else {
return
}

switch event {
case .connect:
handleConnectEvent(message: message)
case .submitEnabled:
handleSubmitEnabled()
case .submitDisabled:
handleSubmitDisabled()
}
}

@objc func performAction() {
reply(to: Event.connect.rawValue)
}

// MARK: Private

private weak var submitBarButtonItem: UIBarButtonItem?
private var viewController: UIViewController? {
delegate.destination as? UIViewController
}

private func handleConnectEvent(message: Message) {
guard let data: MessageData = message.data() else { return }
configureBarButton(with: data.submitTitle)
}

private func handleSubmitEnabled() {
submitBarButtonItem?.isEnabled = true
}

private func handleSubmitDisabled() {
submitBarButtonItem?.isEnabled = false
}

private func configureBarButton(with title: String) {
guard let viewController else { return }

let item = UIBarButtonItem(title: title,
style: .plain,
target: self,
action: #selector(performAction))

viewController.navigationItem.rightBarButtonItem = item
submitBarButtonItem = item
}
}

// MARK: Events

private extension FormComponent {
enum Event: String {
case connect
case submitEnabled
case submitDisabled
}
}

// MARK: Message data

private extension FormComponent {
struct MessageData: Decodable {
let submitTitle: String
}
}

Loading

0 comments on commit c476bac

Please sign in to comment.