-
Notifications
You must be signed in to change notification settings - Fork 25
Navigator
Facade type erasing the type of the underlying datasource
public struct Navigator
Testing helper
typealias DismissSuccessorInvocation = DismissInvocation
var invocations = [Navigator.DismissInvocation]()
let expectectedInvocations = [
Navigator.DismissInvocation(id: .id(expectedID))
]
let sut = Navigator.mock(
path: { self.path },
dismissSuccessor: { id in
invocations.append(.init(id: id))
}
)
sut.dismissSuccessor(of: expectedID) // invoke code that invokes dismissSuccessor(of:)
XCTAssertEqual(expectectedInvocations, invocations)
init(path:go:goToOnScreen:goToPath:goToPathOnScreen:goBack:goBackToID:replace:dismiss:dismissScreen:dismissSuccessor:dismissSuccessorOfScreen:replaceContent:replaceScreen:didAppear:)
public init(
path: @escaping () -> PathUpdate,
go: @escaping (AnyScreen, ScreenID) -> Void,
goToOnScreen: @escaping (AnyScreen, AnyScreen) -> Void,
goToPath: @escaping ([AnyScreen], ScreenID) -> Void,
goToPathOnScreen: @escaping ([AnyScreen], AnyScreen) -> Void,
goBack: @escaping (AnyScreen) -> Void,
goBackToID: @escaping (ScreenID) -> Void,
replace: @escaping ([AnyScreen]) -> Void,
dismiss: @escaping (ScreenID) -> Void,
dismissScreen: @escaping (AnyScreen) -> Void,
dismissSuccessor: @escaping (ScreenID) -> Void,
dismissSuccessorOfScreen: @escaping (AnyScreen) -> Void,
replaceContent: @escaping (ScreenID, AnyScreen) -> Void,
replaceScreen: @escaping (AnyScreen, AnyScreen) -> Void,
didAppear: @escaping (ScreenID) -> Void
)
Initialises a Navigator wrapping a Datasource object
init(dataSource: Navigator.Datasource)
- dataSource: The wrapped data source
static let stub
Enable logging received function calls and path changes.
func debug(
log: @escaping (String) -> Void = { print($0) },
dumpPath: @escaping (PathUpdate) -> Void = { dump($0) }
) -> Navigator
mock(path:go:goToOnScreen:goToPath:goToPathOnScreen:goBack:goBackToID:replace:dismiss:dismissScreen:dismissSuccessor:dismissSuccessorOfScreen:replaceContent:replaceScreen:didAppear:)
static func mock(
path: @escaping () -> PathUpdate = {
fatalError("path() unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
go: @escaping (AnyScreen, ScreenID) -> Void = { _, _ in
fatalError("go(to:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
goToOnScreen: @escaping (AnyScreen, AnyScreen) -> Void = { _, _ in
fatalError("go(to:, on screen:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
goToPath: @escaping ([AnyScreen], ScreenID) -> Void = { _, _ in
fatalError("goTo(path:, to:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
goToPathOnScreen: @escaping ([AnyScreen], AnyScreen) -> Void = { _, _ in
fatalError("goTo(path:, to:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
goBack: @escaping (AnyScreen) -> Void = { _ in
fatalError("goBack(to:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
goBackToID: @escaping (ScreenID) -> Void = { _ in
fatalError("goBack(to:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
replace: @escaping ([AnyScreen]) -> Void = { _ in
fatalError("replace(path:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
dismiss: @escaping (ScreenID) -> Void = { _ in
fatalError("dismiss(id:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
dismissScreen: @escaping (AnyScreen) -> Void = { _ in
fatalError("dismiss(screen:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
dismissSuccessor: @escaping (ScreenID) -> Void = { _ in
fatalError("dismissSuccessor(of:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
dismissSuccessorOfScreen: @escaping (AnyScreen) -> Void = { _ in
fatalError("dismissSuccessor(of:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
replaceContent: @escaping (ScreenID, AnyScreen) -> Void = { _, _ in
fatalError("replaceContent(of id:, with:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
replaceScreen: @escaping (AnyScreen, AnyScreen) -> Void = { _, _ in
fatalError("replace(screen:, with:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
didAppear: @escaping (ScreenID) -> Void = { _ in
fatalError("didAppear(id:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
}
) -> Navigator
mock(path:goToInvoked:goToPathInvoked:goBackToInvoked:replacePathInvoked:dismissInvoked:dismissSuccessorInvoked:replaceContentInvoked:replaceScreenInvoked:didAppearInvoked:)
static func mock(
path: @escaping () -> PathUpdate = {
fatalError("path() unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
goToInvoked: @escaping (Navigator.GoToInvocation) -> Void = { _ in
fatalError("go(to screen:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
goToPathInvoked: @escaping (Navigator.GoToPathInvocation) -> Void = { _ in
fatalError("go(to path:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
goBackToInvoked: @escaping (Navigator.GoBackToInvocation) -> Void = { _ in
fatalError("goBack(to:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
replacePathInvoked: @escaping (Navigator.ReplacePathInvocation) -> Void = { _ in
fatalError("replace(path:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
dismissInvoked: @escaping (Navigator.DismissInvocation) -> Void = { _ in
fatalError("dismiss(id:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
dismissSuccessorInvoked: @escaping (Navigator.DismissSuccessorInvocation) -> Void = { _ in
fatalError("dismissSuccessor(of:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
replaceContentInvoked: @escaping (Navigator.ReplaceContentInvocation) -> Void = { _ in
fatalError("replaceContent(of id:, with:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
replaceScreenInvoked: @escaping (Navigator.ReplaceScreenInvocation) -> Void = { _ in
fatalError("replace(screen:, with:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
},
didAppearInvoked: @escaping (Navigator.DidAppearInvocation) -> Void = { _ in
fatalError("didAppear(id:) unimplemented in stub. Make sure to wrap your application in a Root view or inject Navigator via .environment(\\.navigator, navigator) for testing purposes.")
}
) -> Navigator
Append a screen after a given ScreenID
.
public func go<S: Screen>(to screen: S, on id: ScreenID)
go(to:, on:)
appends the given screen after the screen associated with the passed ScreenID
. If you call go(to:, on:)
for a ScreenID
that is not associated with the last screen in the current navigation path, the navigation path after the ScreenID
is replaced with [screen]
and therefore cut off.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1)]
navigator.go(to: C(), on: 1)
// New path
// [(A, 0), (B, 1)], (C, 2)]
- screen: Destination
- id:
ScreenID
used to identify where the destination should be appended
Append a screen after a given Screen
.
public func go<S: Screen, Parent: Screen>(to screen: S, on parent: Parent)
go(to:, on:)
appends the given screen after the last occurrence of the passed Parent
screen object.
If you call go(to:, on:)
for a Screen
that is not associated with the last screen in the current navigation path, the navigation path after the Parent
is replaced with [screen]
and therefore cut off.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1)]
navigator.go(to: C(), on: B())
// New path
// [(A, 0), (B, 1)], (C, 2)]
- screen: Destination
- parent:
Parent
screen object used to identify where the destination should be appended
Replace the path after a given ScreenID
with the passed path.
public func go(to path: [AnyScreen], on id: ScreenID)
go(to:, on:)
appends the given path after the screen associated with the passed ScreenID
. If you call go(to:, on:)
for a ScreenID
that is not associated with the last screen in the current navigation path, the navigation path after the ScreenID
is replaced with path
and potentially cut off.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1)]
navigator.go(
to: [C().eraseToAnyScreen(), D().eraseToAnyScreen()],
on: 0
)
// New path
// [(A, 0), (C, 2), (D, 3)]
- path: New path after
id
- id:
ScreenID
used to identify where the path should be appended
Replace the path after the last occurrence of a given Parent
with the passed path.
public func go<Parent: Screen>(to path: [AnyScreen], on parent: Parent)
go(to:, on:)
appends the given path after the last occurrence of the passed Parent
Screen
object. If you call go(to:, on:)
for a Parent
screen that is not associated with the last screen in the current navigation path, the navigation path after the ScreenID
is replaced with path
and potentially cut off.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1)]
navigator.go(
to: [C().eraseToAnyScreen(), D().eraseToAnyScreen()],
on: A()
)
// New path
// [(A, 0), (C, 2), (D, 3)]
- path: New path after
Parent
- parent:
Screen
used to identify where the path should be appended
Go back to the last occurrence of the screen instance in the navigation path.
public func goBack<S: Screen>(to screen: S)
goBack(to:)
trims the navigation path to up to the last occurrence of the passed screen.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1), (C, 2)]
navigator.goBack(to: A())
// New path
// [(A, 0)]
- screen: Destination
Go back to the specified ScreenID
in the navigation path.
public func goBack(to id: ScreenID)
goBack(to:)
trims the navigation path to up to the last occurrence of the passed screen.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1), (C, 2)]
navigator.goBack(to: 0)
// New path
// [(A, 0)]
- id: Destination ID
Replace the current navigation path with a new navigation path.
public func replace(path: AnyScreen...)
Example
// Curent path [(Content, ID)]
// [(A, 0), (B, 1)]
navigator.replace(
path: C().eraseToAnyScreen(), D().eraseToAnyScreen()
)
// New path
// [(C, 0), (D, 1)]
- path: The new navigation path
Replace the current navigation path with a new navigation path.
public func replace(path: [AnyScreen])
replace(path:)
checks if a prefix of the new path was already part of the replaced navigation path and makes sure to keep the IDs and hasAppeared state intact.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1)]
navigator.replace(
path: [
C().eraseToAnyScreen(),
D().eraseToAnyScreen()
]
)
// New path
// [(C, 0), (D, 1)]
- path: The new navigation path
Removes the screen associated with the passed screenID from the navigation path.
public func dismiss(id: ScreenID)
dismiss(id:)
does not care take the screen's presentation style into account and cuts the navigation path up to the passed id.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1), (C, 2), (D,3)]
navigator.dismiss(id: 2)
// New path
// [(A, 0), (B, 1)]
- id: The id identifying the screen that needs to be dismissed
Removes the last occurrence screen from the navigation path.
public func dismiss<S: Screen>(screen: S)
dismiss(screen:)
does not care take the screen's presentation style into account and cuts the navigation path up to the passed id.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1), (C, 2), (D,3)]
navigator.dismiss(screen: C())
// New path
// [(A, 0), (B, 1)]
- screen: The screen that needs to be dismissed
Removes the screen successors from the navigation path.
public func dismissSuccessor(of id: ScreenID)
dismissSuccessor(of id:)
does not care take the screen's presentation style into account and cuts the navigation path after the passed id.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1), (C, 2), (D,3)]
navigator.dismissSuccessor(of id: 2)
// New path
// [(A, 0), (B, 1), (C, 2)]
- id: The id identifying the screen that needs to be dismissed
Removes successors of the last occurrence of the passed screen from the navigation path.
public func dismissSuccessor<S: Screen>(of screen: S)
dismissSuccessor(of screen:)
does not care take the screen's presentation style into account and cuts the navigation path after the passed id.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1), (C, 2), (D,3)]
navigator.dismissSuccessor(of: C())
// New path
// [(A, 0), (B, 1), (C, 2)]
- screen: The screen that needs to be dismissed
Replace the Screen
associated with an id with a new Screen
public func replaceContent<NewContent: Screen>(of id: ScreenID, with newContent: NewContent)
replaceContent(of id:, with:)
replaces the content associated with the passed ScreenID
and will not assign a new ScreenID
to the changed path element.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1), (C, 2), (D,3)]
navigator.replaceContent(of: 0, with: E())
// New path
// [(E, 0), (B, 1), (C, 2), (D,3)]
- id:
ScreenID
used to identify the screen that needs to be replaced - newContent: The new screen that will replace the screen associated with the passed
ScreenID
Replace the last occurence of a Screen
with a new Screen
public func replace<OldContent: Screen, NewContent: Screen>(
screen: OldContent,
with newContent: NewContent
)
replace(screen:, with:)
replaces the last occurence of the passed Screen
with the passed newContent Screen
and will not assign a new ScreenID
to the changed path element.
// Curent path [(Content, ID)]
// [(A, 0), (B, 1), (C, 2), (D,3)]
navigator.replace(screen: A(), with: E())
// New path
// [(E, 0), (B, 1), (C, 2), (D,3)]
- screen:
Screen
getting replaced - newContent: The new screen that will replace the screen associated with the passed
ScreenID
Generated at 2021-04-29T07:59:04+0000 using swift-doc 1.0.0-beta.6.
Types
- AnyPathBuilder
- AnyScreen
- Deeplink
- DeeplinkComponent
- DeeplinkComponent.Argument
- DeeplinkHandler
- DeeplinkParser
- EitherAB
- EitherABC
- EitherABCD
- EitherABCDE
- EitherABCDEF
- EitherABCDEFG
- EitherABCDEFGH
- EitherABCDEFGHI
- EitherABCDEFGHIJ
- IdentifiedScreen
- NavigationNode
- NavigationTreeBuilder
- Navigator
- Navigator.Datasource
- Navigator.DidAppearInvocation
- Navigator.DismissInvocation
- Navigator.GoBackToInvocation
- Navigator.GoToInvocation
- Navigator.GoToPathInvocation
- Navigator.NavigationIdentifier
- Navigator.ReplaceContentInvocation
- Navigator.ReplacePathInvocation
- Navigator.ReplaceScreenInvocation
- NavigatorKey
- OnDismissView
- PathBuilders
- PathBuilders.EmptyBuilder
- PathBuilders.WildcardView
- PathComponentUpdate
- PathUpdate
- Root
- ScreenPresentationStyle
- TreatSheetDismissAsAppearInPresenterKey
- _PathBuilder