Skip to content
This repository has been archived by the owner on Jun 1, 2024. It is now read-only.

Commit

Permalink
feat: iOS - Support multiple navigations in Beagle (#840)
Browse files Browse the repository at this point in the history
* Adding support for multiple BeagleNavigationControllers

* Fix Unit tests for Navigate

* Fixing code smells

* Adding new tests to BeagleNavigatorTests and BeagleScreenViewControllerTests

* Fixing code smells

* SwiftLint fixes

* just removing unnecessary files

* Pull request corrections

* change Navigation to use builder pattern and deprecations

* Removing unnecessary public declarations

Signed-off-by: Caio Ortu <[email protected]>

Co-authored-by: theffc <[email protected]>
  • Loading branch information
Caio Ortu and theffc authored Aug 28, 2020
1 parent cdf7277 commit f69e0e5
Show file tree
Hide file tree
Showing 24 changed files with 316 additions and 66 deletions.
14 changes: 11 additions & 3 deletions iOS/Example/BeagleDemo/BeagleDemo.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@
932925B92327E0E400A61F01 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 932925B72327E0E400A61F01 /* Main.storyboard */; };
932925BB2327E0E500A61F01 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 932925BA2327E0E500A61F01 /* Assets.xcassets */; };
932925BE2327E0E500A61F01 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 932925BC2327E0E500A61F01 /* LaunchScreen.storyboard */; };
93A2EE1A24EC49E90085B3CF /* AddChildrenScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93A2EE1924EC49E90085B3CF /* AddChildrenScreen.swift */; };
93A2EE1624E57E120085B3CF /* OperationsScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93A2EE1524E57E120085B3CF /* OperationsScreen.swift */; };
93A2EE1A24EC49E90085B3CF /* AddChildrenScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93A2EE1924EC49E90085B3CF /* AddChildrenScreen.swift */; };
93D8DC0D248965D10070CB41 /* ComponentInteractionScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93D8DC0C248965D10070CB41 /* ComponentInteractionScreen.swift */; };
93EAFA4C24083C7B00B73522 /* ListViewScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 93EAFA4B24083C7B00B73522 /* ListViewScreen.swift */; };
98A7F36C23A926C600E88C70 /* TabViewScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 98A7F36B23A926C600E88C70 /* TabViewScreen.swift */; };
Expand Down Expand Up @@ -101,8 +101,8 @@
932925BA2327E0E500A61F01 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
932925BD2327E0E500A61F01 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
932925BF2327E0E500A61F01 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
93A2EE1924EC49E90085B3CF /* AddChildrenScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddChildrenScreen.swift; sourceTree = "<group>"; };
93A2EE1524E57E120085B3CF /* OperationsScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OperationsScreen.swift; sourceTree = "<group>"; };
93A2EE1924EC49E90085B3CF /* AddChildrenScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddChildrenScreen.swift; sourceTree = "<group>"; };
93D8DC0C248965D10070CB41 /* ComponentInteractionScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComponentInteractionScreen.swift; sourceTree = "<group>"; };
93EAFA4B24083C7B00B73522 /* ListViewScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListViewScreen.swift; sourceTree = "<group>"; };
98A7F36B23A926C600E88C70 /* TabViewScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabViewScreen.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -166,6 +166,14 @@
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
25B7472E24F6D84E00AFE60A /* NavigationControllers */ = {
isa = PBXGroup;
children = (
A057D59924CA1DE7001F6835 /* CustomBeagleNavigationController.swift */,
);
path = NavigationControllers;
sourceTree = "<group>";
};
6E2C784B241984F800448728 /* Constants */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -208,7 +216,6 @@
932925BA2327E0E500A61F01 /* Assets.xcassets */,
932925BF2327E0E500A61F01 /* Info.plist */,
6ED5B09D240464520070CB9D /* BeagleStyle.swift */,
A057D59924CA1DE7001F6835 /* CustomBeagleNavigationController.swift */,
);
path = BeagleDemo;
sourceTree = "<group>";
Expand Down Expand Up @@ -320,6 +327,7 @@
E75619862408363E0025E0A9 /* DesignSystem */ = {
isa = PBXGroup;
children = (
25B7472E24F6D84E00AFE60A /* NavigationControllers */,
C09F40FC249AAAC2002605EE /* GenerationTests */,
E75619872408364A0025E0A9 /* DSCollection */,
C80AF1332493F0950097D200 /* OtherComponent.swift */,
Expand Down
7 changes: 6 additions & 1 deletion iOS/Example/BeagleDemo/BeagleDemo/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
dependencies.validatorProvider = validator
dependencies.analytics = AnalyticsMock()
dependencies.isLoggingEnabled = true
dependencies.navigationControllerType = CustomBeagleNavigationController.self

registerCustomComponents(in: dependencies)
registerCustomControllers(in: dependencies)

Beagle.dependencies = dependencies

Expand All @@ -67,4 +67,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
dependencies.decoder.register(action: CustomConsoleLogAction.self)
dependencies.decoder.register(component: DemoTextField.self, named: "SampleTextField")
}

private func registerCustomControllers(in dependencies: BeagleDependencies) {
dependencies.navigation.registerNavigationController(builder: CustomBeagleNavigationController.init, forId: "CustomBeagleNavigation")
dependencies.navigation.registerNavigationController(builder: CustomPushStackNavigationController.init, forId: "PushStackNavigation")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,5 +52,14 @@ class CustomBeagleNavigationController: BeagleNavigationController {
errorView.addRetry(retry)
}
}

}

// MARK: PushStack

class CustomPushStackNavigationController: BeagleNavigationController {

override func viewDidLoad() {
super.viewDidLoad()
navigationBar.barTintColor = .systemRed
}
}
3 changes: 2 additions & 1 deletion iOS/Example/BeagleDemo/BeagleDemo/Screens/MainScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ struct MainScreen: DeeplinkScreen {
child: buildChild()
)

return BeagleScreenViewController(.declarative(screen))
return BeagleScreenViewController(.declarative(screen),
controllerId: "CustomBeagleNavigation")
}

private func buildChild() -> ScrollView {
Expand Down
19 changes: 11 additions & 8 deletions iOS/Example/BeagleDemo/BeagleDemo/Screens/NavigateTypeScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,16 @@ struct NavigateStep2Screen: DeeplinkScreen {
}

private var step2Screen: Screen =
Screen(navigationBar: NavigationBar(title: "Step 2")) {
Container {
createButton(text: "PopView", action: Navigate.popView, backgroundColor: .blueButton)
createButton(text: "PushView (Step 3)", action: Navigate.pushView(.declarative(step3Screen)), backgroundColor: .salmonButton)
createButton(text: "PushStack", action: Navigate.pushStack(.declarative(presentView)), backgroundColor: .lightOrangeButton)
}
}
Screen(navigationBar: NavigationBar(title: "Step 2")) {
Container {
createButton(text: "PopView", action: Navigate.popView, backgroundColor: .blueButton)
createButton(text: "PushView (Step 3)", action: Navigate.pushView(.declarative(step3Screen)), backgroundColor: .salmonButton)
createButton(text: "PushStack", action: Navigate.pushStack(.declarative(presentView)), backgroundColor: .lightOrangeButton)
createButton(text: "Custom PushStack",
action: Navigate.pushStack(.declarative(presentView), controllerId: "PushStackNavigation"),
backgroundColor: .lightOrangeButton)
}
}

static var step3Screen: Screen =
Screen(navigationBar: NavigationBar(title: "Step 3")) {
Expand All @@ -65,7 +68,7 @@ struct NavigateStep2Screen: DeeplinkScreen {
createButton(text: "PushView (Step 1)", action: Navigate.pushView(.declarative(NavigateStep1Screen().step1Screen)), backgroundColor: .redButton)
}
}

static var presentView: Screen =
Screen(navigationBar: NavigationBar(title: "Present")) {
Container {
Expand Down
2 changes: 2 additions & 0 deletions iOS/Schema/BeagleSchema.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@
257FC9F824DCA75300F2157C /* Value.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Value.swift; sourceTree = "<group>"; };
257FC9FA24DDB74300F2157C /* Operation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Operation.swift; sourceTree = "<group>"; };
25CDD46A24E7315E00CC49CB /* __Snapshots__ */ = {isa = PBXFileReference; lastKnownFileType = folder; path = __Snapshots__; sourceTree = "<group>"; };
3D775A4624F933D400BBECCE /* __Snapshots__ */ = {isa = PBXFileReference; lastKnownFileType = folder; path = __Snapshots__; sourceTree = "<group>"; };
3DE08EC324F03C1A00CFDC36 /* __Snapshots__ */ = {isa = PBXFileReference; lastKnownFileType = folder; path = __Snapshots__; sourceTree = "<group>"; };
570434EC24A6753000DAD0D3 /* buttonComponent.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = buttonComponent.json; sourceTree = "<group>"; };
6E71540124B3953C0025B850 /* SimpleFormTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleFormTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -900,6 +901,7 @@
C8BB30A22486FCE9002DD3C1 /* Tests */ = {
isa = PBXGroup;
children = (
3D775A4624F933D400BBECCE /* __Snapshots__ */,
C8BB30A32486FD17002DD3C1 /* NavigateTests.swift */,
C8BB30AF2486FDB1002DD3C1 /* Json */,
);
Expand Down
7 changes: 5 additions & 2 deletions iOS/Schema/Sources/Action/Types/Navigate/Navigate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ public enum Navigate: RawAction {
case resetStack(Route)

/// Presents a new screen that comes from a specified route starting a new flow.
case pushStack(Route)
/// You can specify a controllerId, describing the id of navigation controller used for the new flow.
case pushStack(Route, controllerId: String? = nil)

/// Unstacks the current view stack.
case popStack
Expand Down Expand Up @@ -113,6 +114,7 @@ extension Navigate: Decodable {
case _beagleAction_
case route
case url
case controllerId
}

public init(from decoder: Decoder) throws {
Expand All @@ -128,7 +130,8 @@ extension Navigate: Decodable {
case "beagle:resetstack":
self = .resetStack(try container.decode(Route.self, forKey: .route))
case "beagle:pushstack":
self = .pushStack(try container.decode(Route.self, forKey: .route))
self = .pushStack(try container.decode(Route.self, forKey: .route),
controllerId: try container.decodeIfPresent(String.self, forKey: .controllerId))
case "beagle:popstack":
self = .popStack
case "beagle:pushview":
Expand Down
24 changes: 24 additions & 0 deletions iOS/Schema/Sources/Action/Types/Navigate/Tests/NavigateTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,30 @@ final class NavigateTests: XCTestCase {
assertSnapshot(matching: action, as: .dump)
}

func testDecodingPushStackWithControllerId() throws {
let action: Navigate = try actionFromString("""
{
"_beagleAction_": "beagle:pushStack",
"route": {
"url": "schema://path"
},
"controllerId": "customid"
}
""")

_assertInlineSnapshot(matching: action, as: .dump, with: """
▿ Navigate
▿ pushStack: (2 elements)
▿ .0: Route
▿ remote: NewPath
- fallback: Optional<Screen>.none
- shouldPrefetch: false
- url: "schema://path"
▿ controllerId: Optional<String>
- some: "customid"
""")
}

func test_decoding_popStack() throws {
let action: Navigate = try actionFromString("""
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,22 @@
▿ Navigate
▿ pushStack: Route
▿ declarative: Screen
▿ child: UnknownComponent
- type: "custom:beagleschematestscomponent"
- context: Optional<Context>.none
- id: Optional<String>.none
- navigationBar: Optional<NavigationBar>.none
▿ safeArea: Optional<SafeArea>
▿ some: SafeArea
▿ bottom: Optional<Bool>
- some: true
▿ leading: Optional<Bool>
- some: true
▿ top: Optional<Bool>
- some: true
▿ trailing: Optional<Bool>
- some: true
- screenAnalyticsEvent: Optional<AnalyticsScreen>.none
- style: Optional<Style>.none
▿ pushStack: (2 elements)
▿ .0: Route
▿ declarative: Screen
▿ child: UnknownComponent
- type: "custom:beagleschematestscomponent"
- context: Optional<Context>.none
- id: Optional<String>.none
- navigationBar: Optional<NavigationBar>.none
▿ safeArea: Optional<SafeArea>
▿ some: SafeArea
▿ bottom: Optional<Bool>
- some: true
▿ leading: Optional<Bool>
- some: true
▿ top: Optional<Bool>
- some: true
▿ trailing: Optional<Bool>
- some: true
- screenAnalyticsEvent: Optional<AnalyticsScreen>.none
- style: Optional<Style>.none
- controllerId: Optional<String>.none
8 changes: 4 additions & 4 deletions iOS/Schema/Sources/Common/FunctionBuilders.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,28 +18,28 @@
import Foundation

@_functionBuilder
public final class ChildBuilder {
public struct ChildBuilder {
public static func buildBlock(_ child: RawComponent) -> RawComponent {
return child
}
}

@_functionBuilder
public final class ChildrenBuilder {
public struct ChildrenBuilder {
public static func buildBlock(_ children: RawComponent...) -> [RawComponent] {
return children
}
}

@_functionBuilder
public final class TabItemBuilder {
public struct TabItemBuilder {
public static func buildBlock(_ tabItem: TabItem) -> TabItem {
return tabItem
}
}

@_functionBuilder
public final class TabItemsBuilder {
public struct TabItemsBuilder {
public static func buildBlock(_ tabItems: TabItem...) -> [TabItem] {
return tabItems
}
Expand Down
2 changes: 1 addition & 1 deletion iOS/Sources/Beagle/Sources/Action/Types/Navigate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ extension Navigate {
switch self {
case let .resetApplication(route),
let .resetStack(route),
let .pushStack(route),
let .pushStack(route, _),
let .pushView(route):
return route.path
default:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class NavigateTests: XCTestCase {
.resetApplication(routeMockRemote),
.resetStack(routeMockRemote),
.pushStack(routeMockRemote),
.pushStack(routeMockRemote, controllerId: "customid"),
.pushView(routeMockRemote),
.resetStack(routeMockDeclarative)
]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ final class BeaglePrefetchHelperTests: XCTestCase {
Navigate.pushStack(.declarative(Screen(child: container))),
Navigate.pushStack(.remote(.init(url: path, shouldPrefetch: true))),
Navigate.pushStack(.remote(.init(url: path, shouldPrefetch: false))),

Navigate.pushStack(.declarative(Screen(child: container)), controllerId: "customId"),
Navigate.pushStack(.remote(.init(url: path, shouldPrefetch: true)), controllerId: "customId"),
Navigate.pushStack(.remote(.init(url: path, shouldPrefetch: false)), controllerId: "customId"),

Navigate.pushView(.declarative(Screen(child: container))),
Navigate.pushView(.remote(.init(url: path, shouldPrefetch: true))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,17 @@

resetStack(BeagleSchema.Route.remote(BeagleSchema.Route.NewPath(url: "path", shouldPrefetch: false, fallback: nil))) --> NewPath(url: "path", shouldPrefetch: false, fallback: nil)

pushStack(BeagleSchema.Route.declarative(BeagleSchema.Screen(id: nil, style: nil, safeArea: nil, navigationBar: nil, screenAnalyticsEvent: nil, child: BeagleSchema.Container(children: [], widgetProperties: BeagleSchema.WidgetProperties(id: nil, style: nil, accessibility: nil), onInit: nil, context: nil), context: nil))) --> NULL
pushStack(BeagleSchema.Route.declarative(BeagleSchema.Screen(id: nil, style: nil, safeArea: nil, navigationBar: nil, screenAnalyticsEvent: nil, child: BeagleSchema.Container(children: [], widgetProperties: BeagleSchema.WidgetProperties(id: nil, style: nil, accessibility: nil), onInit: nil, context: nil), context: nil)), controllerId: nil) --> NULL

pushStack(BeagleSchema.Route.remote(BeagleSchema.Route.NewPath(url: "path", shouldPrefetch: true, fallback: nil))) --> NewPath(url: "path", shouldPrefetch: true, fallback: nil)
pushStack(BeagleSchema.Route.remote(BeagleSchema.Route.NewPath(url: "path", shouldPrefetch: true, fallback: nil)), controllerId: nil) --> NewPath(url: "path", shouldPrefetch: true, fallback: nil)

pushStack(BeagleSchema.Route.remote(BeagleSchema.Route.NewPath(url: "path", shouldPrefetch: false, fallback: nil))) --> NewPath(url: "path", shouldPrefetch: false, fallback: nil)
pushStack(BeagleSchema.Route.remote(BeagleSchema.Route.NewPath(url: "path", shouldPrefetch: false, fallback: nil)), controllerId: nil) --> NewPath(url: "path", shouldPrefetch: false, fallback: nil)

pushStack(BeagleSchema.Route.declarative(BeagleSchema.Screen(id: nil, style: nil, safeArea: nil, navigationBar: nil, screenAnalyticsEvent: nil, child: BeagleSchema.Container(children: [], widgetProperties: BeagleSchema.WidgetProperties(id: nil, style: nil, accessibility: nil), onInit: nil, context: nil), context: nil)), controllerId: Optional("customId")) --> NULL

pushStack(BeagleSchema.Route.remote(BeagleSchema.Route.NewPath(url: "path", shouldPrefetch: true, fallback: nil)), controllerId: Optional("customId")) --> NewPath(url: "path", shouldPrefetch: true, fallback: nil)

pushStack(BeagleSchema.Route.remote(BeagleSchema.Route.NewPath(url: "path", shouldPrefetch: false, fallback: nil)), controllerId: Optional("customId")) --> NewPath(url: "path", shouldPrefetch: false, fallback: nil)

pushView(BeagleSchema.Route.declarative(BeagleSchema.Screen(id: nil, style: nil, safeArea: nil, navigationBar: nil, screenAnalyticsEvent: nil, child: BeagleSchema.Container(children: [], widgetProperties: BeagleSchema.WidgetProperties(id: nil, style: nil, accessibility: nil), onInit: nil, context: nil), context: nil))) --> NULL

Expand Down
Loading

0 comments on commit f69e0e5

Please sign in to comment.