From 873d849390a2dc50f7eb74af3f5fa5120bed5699 Mon Sep 17 00:00:00 2001 From: felilo <10853689+felilo@users.noreply.github.com> Date: Wed, 18 Dec 2024 18:35:37 -0500 Subject: [PATCH] Update readme and clean code (#44) * Improves TabBarCoordinator and clean code (#39) --- .../CustomTabbar/CustomTabbarView.swift | 2 +- README.md | 14 ++++----- .../CoordinatorType+Helpers.swift | 15 +++++++--- .../CoordinatorType+Navigation.swift | 6 ++-- .../SUICoordinator/Router/DefaultRoute.swift | 8 +---- Sources/SUICoordinator/Router/RouteType.swift | 13 ++++++++ .../SheetCoordinator/SheetCoordinator.swift | 12 ++++++++ .../SheetCoordinator/SheetItem.swift | 30 +------------------ .../Tabbar/TabbarCoordinatorView.swift | 2 +- 9 files changed, 50 insertions(+), 52 deletions(-) diff --git a/Examples/SUICoordinatorExample/SUICoordinatorExample/Coordinators/CustomTabbar/CustomTabbarView.swift b/Examples/SUICoordinatorExample/SUICoordinatorExample/Coordinators/CustomTabbar/CustomTabbarView.swift index 1214e52..6079073 100644 --- a/Examples/SUICoordinatorExample/SUICoordinatorExample/Coordinators/CustomTabbar/CustomTabbarView.swift +++ b/Examples/SUICoordinatorExample/SUICoordinatorExample/Coordinators/CustomTabbar/CustomTabbarView.swift @@ -25,7 +25,7 @@ import SwiftUI import SUICoordinator -struct CustomTabbarView: View where DataSource.Page: TabbarPage{ +struct CustomTabbarView: View { // --------------------------------------------------------------------- // MARK: Typealias diff --git a/README.md b/README.md index cb28bf0..3629c76 100644 --- a/README.md +++ b/README.md @@ -119,28 +119,28 @@ class ActionListViewModel: ObservableObject { self.coordinator = coordinator } - func navigateToPushView() async { + @MainActor func navigateToFirstView() async { await coordinator.navigateToPushView() } - func presentSheet() async { + @MainActor func presentSheet() async { await coordinator.presentSheet() } - func presentFullscreen() async { + @MainActor func presentFullscreen() async { await coordinator.presentFullscreen() } - func presentDetents() async { + @MainActor func presentDetents() async { await coordinator.presentDetents() } - func presentTabbarCoordinator() async { + @MainActor func presentTabbarCoordinator() async { await coordinator.presentTabbarCoordinator() } - func finsh() async { - await coordinator.finsh() + @MainActor func finish() async { + await coordinator.finish() } } ``` diff --git a/Sources/SUICoordinator/CoordinatorType/CoordinatorType+Helpers.swift b/Sources/SUICoordinator/CoordinatorType/CoordinatorType+Helpers.swift index 251d972..01da72d 100644 --- a/Sources/SUICoordinator/CoordinatorType/CoordinatorType+Helpers.swift +++ b/Sources/SUICoordinator/CoordinatorType/CoordinatorType+Helpers.swift @@ -150,6 +150,8 @@ extension CoordinatorType { /// - withDismiss: A boolean value indicating whether to dismiss the coordinator. /// - Returns: An asynchronous void task representing the finish process. func finish(animated: Bool = true, withDismiss: Bool = true) async -> Void { + guard !isEmptyCoordinator else { return } + guard let parent, withDismiss else { return await emptyCoordinator(animated: animated) } @@ -164,11 +166,16 @@ extension CoordinatorType { } /// Cleans up the coordinator. - func swipedAway() { - guard !isEmptyCoordinator else { return } + func swipedAway(coordinator: TCoordinatorType) { + let sheetCoordinator = router.sheetCoordinator - Task(priority: .low) { [weak self] in - await self?.finish(animated: false, withDismiss: false) + sheetCoordinator.onRemoveItem = { [weak coordinator] id in + if let uuid = coordinator?.uuid, id.contains(uuid) { + Task(priority: .utility) { [weak coordinator] in + await coordinator?.finish(animated: false, withDismiss: false) + sheetCoordinator.onRemoveItem = nil + } + } } } } diff --git a/Sources/SUICoordinator/CoordinatorType/CoordinatorType+Navigation.swift b/Sources/SUICoordinator/CoordinatorType/CoordinatorType+Navigation.swift index c2b38fc..ff07963 100644 --- a/Sources/SUICoordinator/CoordinatorType/CoordinatorType+Navigation.swift +++ b/Sources/SUICoordinator/CoordinatorType/CoordinatorType+Navigation.swift @@ -50,11 +50,11 @@ public extension CoordinatorType { let item = SheetItem( id: "\(coordinator.uuid) - \(presentationStyle.id)", animated: animated, - presentationStyle: (presentationStyle != .push) ? presentationStyle : .sheet, - view: { [weak coordinator] in coordinator?.getView() }, - onFinish: {[weak coordinator] in coordinator?.swipedAway()} + presentationStyle: (presentationStyle != .push) ? presentationStyle : .sheet, + view: { [weak coordinator] in coordinator?.getView() } ) + swipedAway(coordinator: coordinator) router.presentSheet(item: item) } diff --git a/Sources/SUICoordinator/Router/DefaultRoute.swift b/Sources/SUICoordinator/Router/DefaultRoute.swift index 88e4261..d2db979 100644 --- a/Sources/SUICoordinator/Router/DefaultRoute.swift +++ b/Sources/SUICoordinator/Router/DefaultRoute.swift @@ -66,12 +66,6 @@ public struct DefaultRoute: RouteType { /// The view to be presented for the route. public var view: any View { - var view = AnyView(EmptyView()).id(UUID().uuidString) - - if let v = content() { - view = AnyView(v).id(String(describing: v.self)) - } - - return view + getView(from: content) } } diff --git a/Sources/SUICoordinator/Router/RouteType.swift b/Sources/SUICoordinator/Router/RouteType.swift index d9d10ab..796fe85 100644 --- a/Sources/SUICoordinator/Router/RouteType.swift +++ b/Sources/SUICoordinator/Router/RouteType.swift @@ -50,3 +50,16 @@ public protocol RouteType: SCHashable { /// The body of the route, conforming to the View protocol. @ViewBuilder @MainActor var view: Body { get } } + +extension RouteType { + + func getView(from content: () -> (Body?)) -> any View { + var view = AnyView(EmptyView()).id(UUID().uuidString) + + if let v = content() { + view = AnyView(v).id(String(describing: v.self)) + } + + return view + } +} diff --git a/Sources/SUICoordinator/SheetCoordinator/SheetCoordinator.swift b/Sources/SUICoordinator/SheetCoordinator/SheetCoordinator.swift index 877dffe..30f9675 100644 --- a/Sources/SUICoordinator/SheetCoordinator/SheetCoordinator.swift +++ b/Sources/SUICoordinator/SheetCoordinator/SheetCoordinator.swift @@ -49,6 +49,10 @@ final public class SheetCoordinator: ObservableObject { /// The presentation style of the last presented sheet. public private(set) var animated: Bool? + private var backUpItems: [Int: String] = [:] + + var onRemoveItem: ((String) -> Void)? + // --------------------------------------------------------- // MARK: Constructor // --------------------------------------------------------- @@ -87,6 +91,7 @@ final public class SheetCoordinator: ObservableObject { animated = sheet.animated lastPresentationStyle = sheet.presentationStyle items.append(sheet) + backUpItems[totalItems - 1] = sheet.id } /// Removes the last presented sheet. @@ -106,6 +111,12 @@ final public class SheetCoordinator: ObservableObject { /// - index: The index of the item to remove. @MainActor func remove(at index: Int) { guard isValidIndex(index) else { return } + + if let id = backUpItems[index] { + onRemoveItem?(id) + backUpItems.removeValue(forKey: index) + } + items.remove(at: index) } @@ -117,6 +128,7 @@ final public class SheetCoordinator: ObservableObject { await makeNilItem(at: 0) lastPresentationStyle = nil items.removeAll() + backUpItems.removeAll() } // --------------------------------------------------------- diff --git a/Sources/SUICoordinator/SheetCoordinator/SheetItem.swift b/Sources/SUICoordinator/SheetCoordinator/SheetItem.swift index bf767bf..ba93e52 100644 --- a/Sources/SUICoordinator/SheetCoordinator/SheetItem.swift +++ b/Sources/SUICoordinator/SheetCoordinator/SheetItem.swift @@ -45,8 +45,6 @@ public struct SheetItem:SCHashable, SheetItemType { /// The transition presentation style for presenting the sheet item. let presentationStyle: TransitionPresentationStyle - private var itemDeallocate: SheetItemDeallocator? - // --------------------------------------------------------- // MARK: Constructor // --------------------------------------------------------- @@ -62,15 +60,12 @@ public struct SheetItem:SCHashable, SheetItemType { id: String, animated: Bool, presentationStyle: TransitionPresentationStyle, - view: @escaping () -> T?, - onFinish: (() -> Void)? = nil + view: @escaping () -> T? ) { self.view = view self.animated = animated self.presentationStyle = presentationStyle self.id = id - - itemDeallocate = .init(onFinish: onFinish) } // --------------------------------------------------------- @@ -86,26 +81,3 @@ public struct SheetItem:SCHashable, SheetItemType { animated } } - - -/// A utility class to handle deallocation of sheet items, providing a callback -/// that is executed upon deinitialization of the object. -class SheetItemDeallocator { - - /// A closure that is invoked when the instance is deallocated. - var onFinish: (() -> Void)? - - /// Initializes a new `SheetItemDeallocator` instance. - /// - /// - Parameter onFinish: A closure to be executed when the instance is deallocated. Defaults to `nil`. - init(onFinish: (() -> Void)? = nil ) { - self.onFinish = onFinish - } - - /// Deinitializes the instance, invoking the `onFinish` closure if set, and - /// cleans up the closure reference to avoid potential memory leaks. - deinit { - onFinish?() - onFinish = nil - } -} diff --git a/Sources/SUICoordinator/Tabbar/TabbarCoordinatorView.swift b/Sources/SUICoordinator/Tabbar/TabbarCoordinatorView.swift index ae21cbd..632284a 100644 --- a/Sources/SUICoordinator/Tabbar/TabbarCoordinatorView.swift +++ b/Sources/SUICoordinator/Tabbar/TabbarCoordinatorView.swift @@ -25,7 +25,7 @@ import SwiftUI import Foundation -struct TabbarCoordinatorView: View where DataSource.Page: TabbarPage { +struct TabbarCoordinatorView: View { typealias Page = DataSource.Page typealias BadgeItem = DataSource.BadgeItem