Skip to content

Commit

Permalink
1.7.0
Browse files Browse the repository at this point in the history
  • Loading branch information
nathantannar4 committed Dec 10, 2024
1 parent 551fc4a commit 6e9a482
Show file tree
Hide file tree
Showing 9 changed files with 538 additions and 431 deletions.
608 changes: 318 additions & 290 deletions Example/Example/ContentView.swift

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion Example/Example/ExampleApp.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import SwiftUI
struct ExampleApp: App {
var body: some Scene {
WindowGroup {
ContentView()
NavigationView {
ContentView()
}
.navigationViewStyle(.stack)
}
}
}
64 changes: 32 additions & 32 deletions Sources/Transmission/Sources/DestinationCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,23 +19,43 @@ public struct DestinationCoordinator {
public var isPresented: Bool

@usableFromInline
var dismissBlock: () -> Void
var dismissBlock: (Int, Transaction) -> Void

/// Dismisses all presented views with an optional animation
@inlinable
public func popToRoot(animation: Animation? = .default) {
pop(count: .max, animation: animation)
}

/// Dismisses all presented views with the transaction
@inlinable
public func popToRoot(transaction: Transaction) {
pop(count: .max, transaction: transaction)
}

/// Dismisses the presented view with an optional animation
@inlinable
public func pop(animation: Animation? = .default) {
pop(transaction: Transaction(animation: animation))
pop(count: 1, animation: animation)
}

/// Dismisses the presented view with the transaction
@inlinable
public func pop(transaction: Transaction) {
DestinationCoordinator.transaction = transaction
withTransaction(transaction, dismissBlock)
pop(count: 1, transaction: transaction)
}

@usableFromInline
static var transaction: Transaction?
/// Dismisses the presented view with an optional animation
@inlinable
public func pop(count: Int, animation: Animation? = .default) {
pop(count: count, transaction: Transaction(animation: animation))
}

/// Dismisses the presented view with the transaction
@inlinable
public func pop(count: Int, transaction: Transaction) {
dismissBlock(count, transaction)
}
}

@available(iOS 14.0, *)
Expand All @@ -47,49 +67,29 @@ enum DestinationCoordinatorKey: EnvironmentKey {
extension EnvironmentValues {

/// A coordinator that can be used to programatically dismiss a view
///
/// If a `PresentationLink` or `WindowLink` was not used to present
/// the view, a coordinator will be created that wraps SwiftUI's `DismissAction`.
///
public var destinationCoordinator: DestinationCoordinator {
get {
if let coordinator = self[DestinationCoordinatorKey.self] {
return coordinator
}
if #available(iOS 15.0, *) {
return DestinationCoordinator(
isPresented: isPresented,
dismissBlock: dismiss.callAsFunction
)
} else {
let presentationMode = presentationMode
return DestinationCoordinator(
isPresented: presentationMode.wrappedValue.isPresented
) {
presentationMode.wrappedValue.dismiss()
}
}
return DestinationCoordinator(
isPresented: false,
dismissBlock: { _, _ in }
)
}
set { self[DestinationCoordinatorKey.self] = newValue }
}
}

@available(iOS 14.0, *)
struct DestinationBridgeAdapter: ViewModifier {
var isPresented: Binding<Bool>
var destinationCoordinator: DestinationCoordinator
@State var didAppear = false

func body(content: Content) -> some View {
content
.modifier(_ViewInputsBridgeModifier())
.environment(
\.destinationCoordinator,
DestinationCoordinator(
isPresented: isPresented.wrappedValue,
dismissBlock: {
isPresented.wrappedValue = false
})
)
.environment(\.destinationCoordinator, destinationCoordinator)
.onAppear {
// Need to trigger a render update during presentation to fix DatePicker
withCATransaction {
Expand Down
76 changes: 39 additions & 37 deletions Sources/Transmission/Sources/DestinationLinkModifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -158,14 +158,16 @@ private struct DestinationLinkModifierBody<
if let adapter = context.coordinator.adapter {
adapter.update(
destination: destination,
context: context
context: context,
isPresented: isPresented
)
} else if let navigationController = presentingViewController.navigationController {

let adapter = DestinationLinkDestinationViewControllerAdapter(
destination: destination,
transition: transition.value,
context: context
context: context,
isPresented: isPresented
)
context.coordinator.adapter = adapter
switch adapter.transition {
Expand All @@ -190,17 +192,12 @@ private struct DestinationLinkModifierBody<
let viewController = adapter.viewController!
let isAnimated = context.transaction.isAnimated
|| viewController.transitionCoordinator?.isAnimated == true
|| DestinationCoordinator.transaction.isAnimated
if let presented = viewController.presentedViewController {
presented.dismiss(animated: isAnimated) {
viewController._popViewController(animated: isAnimated) {
DestinationCoordinator.transaction = nil
}
viewController._popViewController(animated: isAnimated)
}
} else {
viewController._popViewController(animated: isAnimated) {
DestinationCoordinator.transaction = nil
}
viewController._popViewController(animated: isAnimated)
}
context.coordinator.adapter = nil
}
Expand Down Expand Up @@ -242,10 +239,11 @@ private struct DestinationLinkModifierBody<
animated: Bool
) {
if let viewController = adapter?.viewController,
!navigationController.viewControllers.contains(viewController)
!navigationController.viewControllers.contains(viewController),
isPresented.wrappedValue
{
withCATransaction {
var transaction = Transaction()
var transaction = Transaction(animation: animated ? .default : nil)
transaction.disablesAnimations = true
withTransaction(transaction) {
self.isPresented.wrappedValue = false
Expand Down Expand Up @@ -546,44 +544,33 @@ private class DestinationLinkDestinationViewControllerAdapter<Destination: View>

var transition: DestinationLinkTransition.Value
var environment: EnvironmentValues
var isPresented: Binding<Bool>
var conformance: ProtocolConformance<UIViewControllerRepresentableProtocolDescriptor>? = nil

var isPresented: Binding<Bool> {
Binding<Bool>(
get: { true },
set: { [weak self] newValue, transaction in
MainActor.assumeIsolated {
if !newValue, let viewController = self?.viewController {
let isAnimated = transaction.isAnimated
|| viewController.transitionCoordinator?.isAnimated == true
|| DestinationCoordinator.transaction.isAnimated
viewController._popViewController(animated: isAnimated) {
DestinationCoordinator.transaction = nil
}
}
}
}
)
}

init(
destination: Destination,
transition: DestinationLinkTransition.Value,
context: DestinationLinkModifierBody<Destination>.Context
context: DestinationLinkModifierBody<Destination>.Context,
isPresented: Binding<Bool>
) {
self.transition = transition
self.environment = context.environment
self.isPresented = isPresented
if let conformance = UIViewControllerRepresentableProtocolDescriptor.conformance(of: Destination.self) {
self.conformance = conformance
update(
destination: destination,
context: context
context: context,
isPresented: isPresented
)
} else {
let viewController = DestinationController(
content: destination.modifier(
DestinationBridgeAdapter(
isPresented: isPresented
destinationCoordinator: DestinationCoordinator(
isPresented: isPresented.wrappedValue,
dismissBlock: { [weak self] in self?.pop($0, $1) }
)
)
)
)
Expand All @@ -606,9 +593,11 @@ private class DestinationLinkDestinationViewControllerAdapter<Destination: View>

func update(
destination: Destination,
context: DestinationLinkModifierBody<Destination>.Context
context: DestinationLinkModifierBody<Destination>.Context,
isPresented: Binding<Bool>
) {
environment = context.environment
self.isPresented = isPresented
if let conformance = conformance {
var visitor = Visitor(
destination: destination,
Expand All @@ -621,13 +610,27 @@ private class DestinationLinkDestinationViewControllerAdapter<Destination: View>
let viewController = viewController as! DestinationController
viewController.content = destination.modifier(
DestinationBridgeAdapter(
isPresented: isPresented
destinationCoordinator: DestinationCoordinator(
isPresented: isPresented.wrappedValue,
dismissBlock: { [weak self] in self?.pop($0, $1) }
)
)
)
transition.update(viewController)
}
}

func pop(_ count: Int, _ transaction: Transaction) {
guard let viewController else { return }
let isAnimated = transaction.isAnimated
|| viewController.transitionCoordinator?.isAnimated == true
viewController._popViewController(count: count, animated: isAnimated) {
withTransaction(transaction) {
self.isPresented.wrappedValue = false
}
}
}

private struct Context<Coordinator> {
// Only `UIViewRepresentable` uses V4
struct V4 {
Expand Down Expand Up @@ -710,11 +713,10 @@ private class DestinationLinkDestinationViewControllerAdapter<Destination: View>
adapter.context = unsafeBitCast(context, to: Content.Context.self)
}
func project<T>(_ value: T) -> Content.Context {
let isPresented = self.isPresented
let destinationCoordinator = DestinationCoordinator(
isPresented: isPresented.wrappedValue,
dismissBlock: {
isPresented.wrappedValue = false
dismissBlock: { [weak adapter] in
adapter?.pop($0, $1)
}
)
var ctx = unsafeBitCast(value, to: Context<Content.Coordinator>.V1.self)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,11 @@ import UIKit

extension UIViewController {

func _popViewController(animated: Bool, completion: (() -> Void)? = nil) {
func _popViewController(
count: Int = 1,
animated: Bool,
completion: (() -> Void)? = nil
) {
guard let navigationController = navigationController,
let index = navigationController.viewControllers.firstIndex(of: self),
index > 0
Expand All @@ -21,7 +25,8 @@ extension UIViewController {
CATransaction.begin()
CATransaction.setCompletionBlock(completion)
}
navigationController.popToViewController(navigationController.viewControllers[index - 1], animated: animated)
let toIndex = max(index - count, 0)
navigationController.popToViewController(navigationController.viewControllers[toIndex], animated: animated)
if animated {
CATransaction.commit()
} else {
Expand Down
Loading

0 comments on commit 6e9a482

Please sign in to comment.