Skip to content

Commit

Permalink
Pick Transition (#27)
Browse files Browse the repository at this point in the history
  • Loading branch information
davdroman authored Nov 9, 2022
1 parent 43a29c4 commit 0ac3c1a
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 107 deletions.
Original file line number Diff line number Diff line change
@@ -1,41 +1,5 @@
import class UIKit.UIView

/// A composite transition that uses a different transition for push versus pop.
public struct Asymmetric<InsertionTransition: AtomicTransition, RemovalTransition: AtomicTransition>: AtomicTransition {
private let insertion: InsertionTransition
private let removal: RemovalTransition

private init(insertion: InsertionTransition, removal: RemovalTransition) {
self.insertion = insertion
self.removal = removal
}

public init(
@AtomicTransitionBuilder insertion: () -> InsertionTransition,
@AtomicTransitionBuilder removal: () -> RemovalTransition
) {
self.init(insertion: insertion(), removal: removal())
}

public func transition(_ view: TransientView, for operation: TransitionOperation, in container: Container) {
switch operation {
case .insertion:
insertion.transition(view, for: operation, in: container)
case .removal:
removal.transition(view, for: operation, in: container)
}
}
}

extension Asymmetric: MirrorableAtomicTransition where InsertionTransition: MirrorableAtomicTransition, RemovalTransition: MirrorableAtomicTransition {
public func mirrored() -> Asymmetric<InsertionTransition.Mirrored, RemovalTransition.Mirrored> {
return .init(insertion: insertion.mirrored(), removal: removal.mirrored())
}
}

extension Asymmetric: Equatable where InsertionTransition: Equatable, RemovalTransition: Equatable {}
extension Asymmetric: Hashable where InsertionTransition: Hashable, RemovalTransition: Hashable {}

/// A transition that executes only on insertion.
public struct OnInsertion<Transition: AtomicTransition>: AtomicTransition {
private let transition: Transition
Expand Down
8 changes: 8 additions & 0 deletions Sources/NavigationTransition/Combined.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,14 @@ extension AnyNavigationTransition {
public func combined(with other: Self) -> Self {
switch (self.handler, other.handler) {
case (.transient(let lhsHandler), .transient(let rhsHandler)):
struct Erased: NavigationTransition {
let handler: AnyNavigationTransition.TransientHandler

@inlinable
func transition(from fromView: TransientView, to toView: TransientView, for operation: TransitionOperation, in container: Container) {
handler(fromView, toView, operation, container)
}
}
return AnyNavigationTransition(
Combined(Erased(handler: lhsHandler), Erased(handler: rhsHandler))
)
Expand Down
18 changes: 0 additions & 18 deletions Sources/NavigationTransition/Erased.swift

This file was deleted.

6 changes: 6 additions & 0 deletions Sources/NavigationTransition/Mirror.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ public struct MirrorPush<Transition: MirrorableAtomicTransition>: NavigationTran
}
}

extension MirrorPush: Equatable where Transition: Equatable {}
extension MirrorPush: Hashable where Transition: Hashable {}

/// Used to define a transition that executes on pop, and executes the mirrored version of said transition on push.
public struct MirrorPop<Transition: MirrorableAtomicTransition>: NavigationTransition {
private let transition: Transition
Expand All @@ -35,3 +38,6 @@ public struct MirrorPop<Transition: MirrorableAtomicTransition>: NavigationTrans
}
}
}

extension MirrorPop: Equatable where Transition: Equatable {}
extension MirrorPop: Hashable where Transition: Hashable {}
Original file line number Diff line number Diff line change
@@ -1,36 +1,5 @@
import AtomicTransition

/// A composite transition that uses a different transition for push versus pop.
public struct Asymmetric<PushTransition: NavigationTransition, PopTransition: NavigationTransition>: NavigationTransition {
private let push: PushTransition
private let pop: PopTransition

public init(
@AtomicTransitionBuilder push: () -> PushTransition,
@AtomicTransitionBuilder pop: () -> PopTransition
) {
self.push = push()
self.pop = pop()
}

public func transition(
from fromView: TransientView,
to toView: TransientView,
for operation: TransitionOperation,
in container: Container
) {
switch operation {
case .push:
push.transition(from: fromView, to: toView, for: operation, in: container)
case .pop:
pop.transition(from: fromView, to: toView, for: operation, in: container)
}
}
}

extension Asymmetric: Equatable where PushTransition: Equatable, PopTransition: Equatable {}
extension Asymmetric: Hashable where PushTransition: Hashable, PopTransition: Hashable {}

/// Used to define a transition that executes only on push.
public struct OnPush<Transition: AtomicTransition>: NavigationTransition {
private let transition: Transition
Expand Down
51 changes: 51 additions & 0 deletions Sources/NavigationTransition/Pick.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/// Used to isolate the push portion of a full `NavigationTransition` and execute it on push, ignoring the pop portion.
public struct PickPush<Transition: NavigationTransition>: NavigationTransition {
private let transition: Transition

public init(@NavigationTransitionBuilder transition: () -> Transition) {
self.transition = transition()
}

public func transition(
from fromView: TransientView,
to toView: TransientView,
for operation: TransitionOperation,
in container: Container
) {
switch operation {
case .push:
transition.transition(from: fromView, to: toView, for: operation, in: container)
case .pop:
return
}
}
}

extension PickPush: Equatable where Transition: Equatable {}
extension PickPush: Hashable where Transition: Hashable {}

/// Used to isolate the pop portion of a full `NavigationTransition` and execute it on pop, ignoring the push portion.
public struct PickPop<Transition: NavigationTransition>: NavigationTransition {
private let transition: Transition

public init(@NavigationTransitionBuilder transition: () -> Transition) {
self.transition = transition()
}

public func transition(
from fromView: TransientView,
to toView: TransientView,
for operation: TransitionOperation,
in container: Container
) {
switch operation {
case .push:
return
case .pop:
transition.transition(from: fromView, to: toView, for: operation, in: container)
}
}
}

extension PickPop: Equatable where Transition: Equatable {}
extension PickPop: Hashable where Transition: Hashable {}
Original file line number Diff line number Diff line change
@@ -1,28 +1,6 @@
@_spi(package) import AtomicTransition
import TestUtils

final class AsymmetricTests: XCTestCase {
func testInsertion() {
let expectation = expectation(description: "Handler called")
let sut = Asymmetric(
insertion: { Spy { expectation.fulfill() } },
removal: { Spy { XCTFail() } }
)
sut.transition(.unimplemented, for: .insertion, in: .unimplemented)
wait(for: [expectation], timeout: 0)
}

func testRemoval() {
let expectation = expectation(description: "Handler called")
let sut = Asymmetric(
insertion: { Spy { XCTFail() } },
removal: { Spy { expectation.fulfill() } }
)
sut.transition(.unimplemented, for: .removal, in: .unimplemented)
wait(for: [expectation], timeout: 0)
}
}

final class OnInsertionTests: XCTestCase {
func testInsertion() {
let expectation = expectation(description: "Handler called")
Expand Down

0 comments on commit 0ac3c1a

Please sign in to comment.