From 473dbd2833c0bf84c0d25c5043ce7374ed00e5dc Mon Sep 17 00:00:00 2001 From: Alexander Khodko Date: Fri, 27 Sep 2024 11:57:25 +0300 Subject: [PATCH 01/10] t --- .swift-version | 2 +- .xcode-version | 2 +- .../NivelirExample.xcodeproj/project.pbxproj | 8 +- .../NivelirExample/Dependencies/Screens.swift | 1 + .../Dependencies/Services.swift | 3 + .../ScreenAuthorizeActionScreens.swift | 1 + .../Routing/Deeplinks/ChatDeeplink.swift | 1 + .../Routing/Extensions/Alert+Extensions.swift | 1 + Example/NivelirExample/SceneDelegate.swift | 4 +- .../Authorization/AuthorizationObserver.swift | 1 + .../AuthorizationViewController.swift | 6 +- .../Authorization/AuthorizationService.swift | 3 +- .../Profile/DefaultProfileService.swift | 81 +++++++++---------- .../Services/Profile/ProfileService.swift | 5 +- Nivelir.xcodeproj/project.pbxproj | 8 +- Sources/Addons/Alert/AlertTextField.swift | 4 +- .../Addons/Alert/AlertTextFieldsManager.swift | 1 + .../InvalidBottomSheetContainerError.swift | 14 +--- .../BottomSheetAnimationOptions.swift | 2 +- .../BottomSheetDismissAnimation.swift | 1 + .../BottomSheetPresentAnimation.swift | 1 + Sources/Addons/BottomSheet/BottomSheet.swift | 33 ++++---- .../BottomSheet/BottomSheetBorder.swift | 2 +- .../Addons/BottomSheet/BottomSheetCard.swift | 2 +- .../BottomSheet/BottomSheetController.swift | 6 +- .../BottomSheet/BottomSheetGrabber.swift | 2 +- .../BottomSheetRubberBandEffect.swift | 6 +- .../BottomSheet/BottomSheetShadow.swift | 2 +- .../ScreenBottomSheetDecorator.swift | 6 +- .../ScreenBottomSheetStackDecorator.swift | 7 +- .../BottomSheetDetentionController.swift | 13 ++- .../BottomSheetDetentionDelegate.swift | 1 + .../Detention/Detent/BottomSheetDetent.swift | 5 +- .../Detent/BottomSheetDetentContext.swift | 1 + .../Detent/BottomSheetDetentKey.swift | 2 +- .../Dimming/BottomSheetDimming.swift | 2 +- .../BottomSheetInteractionController.swift | 5 +- .../Interactions/BottomSheetInteraction.swift | 1 + .../DocumentPreview/DocumentPreview.swift | 6 +- .../DocumentPreviewAnchor.swift | 1 + .../DocumentPreviewManager.swift | 18 +++-- .../Addons/HUD/Animation/HUDAnimation.swift | 1 + .../HUD/Animation/HUDCustomAnimation.swift | 1 + Sources/Addons/HUD/HUD.swift | 6 +- Sources/Addons/HUD/HUDStyle.swift | 2 +- Sources/Addons/HUD/HUDView.swift | 4 +- .../Animation/ProgressAnimation.swift | 1 + .../Animation/ProgressCustomAnimation.swift | 1 + .../Progress/Content/AnyProgressContent.swift | 1 + .../Progress/Content/ProgressContent.swift | 1 + .../ProgressPercentageIndicator.swift | 6 +- Sources/Addons/HUD/Progress/Progress.swift | 30 +++---- .../MediaPickerSourceAccessDeniedError.swift | 12 +-- .../UnavailableMediaPickerSourceError.swift | 12 +-- .../UnavailableMediaPickerTypesError.swift | 12 +-- Sources/Addons/MediaPicker/MediaPicker.swift | 8 +- .../MediaPickerCameraSettings.swift | 2 +- .../MediaPicker/MediaPickerSource.swift | 3 +- .../Addons/Safari/InvalidSafariURLError.swift | 12 +-- Sources/Addons/Safari/SafariManager.swift | 1 + .../Sharing/Activity/SharingActivity.swift | 3 +- .../Activity/SharingActivityManager.swift | 5 +- .../Activity/SharingCustomActivity.swift | 1 + .../Activity/SharingSilentActivity.swift | 1 + .../InvalidStoreProductIDError.swift | 12 +-- .../Addons/StoreProduct/StoreProduct.swift | 5 +- .../URL/Call/InvalidCallParametersError.swift | 12 +-- Sources/Addons/URL/FailedToOpenURLError.swift | 16 ++-- .../URL/Mail/InvalidMailParametersError.swift | 12 +-- .../InvalidOpenSettingsURLError.swift | 12 +-- .../URL/StoreApp/InvalidStoreAppIDError.swift | 12 +-- Sources/Deeplink/AnyDeeplink.swift | 1 + Sources/Deeplink/Deeplink.swift | 2 + Sources/Deeplink/DeeplinkHandler.swift | 1 + Sources/Deeplink/DeeplinkManager.swift | 4 +- Sources/Deeplink/DeeplinkScope.swift | 2 +- .../Errors/DeeplinkDecodingError.swift | 17 ++-- .../Errors/DeeplinkInvalidContextError.swift | 23 ++---- .../Errors/DeeplinkInvalidScreensError.swift | 23 ++---- ...ficationDeeplinkInvalidUserInfoError.swift | 19 ++--- .../URLDeeplinkInvalidComponentsError.swift | 19 ++--- .../Screen/Actions/Any/AnyScreenAction.swift | 7 +- .../Actions/Any/AnyScreenActionBaseBox.swift | 2 +- .../Actions/Any/AnyScreenActionBox.swift | 4 +- .../Generic/Find/ScreenPredicate.swift | 1 + .../Refresh/ScreenRefreshableContainer.swift | 2 + .../Generic/Try/ScreenTryResolution.swift | 1 + Sources/Screen/Actions/ScreenAction.swift | 1 + .../Animations/ScreenStackAnimation.swift | 3 +- .../ScreenStackCustomAnimation.swift | 2 + .../ScreenStackTransitionAnimation.swift | 2 +- .../Pop/ScreenStackPopModifier.swift | 5 +- .../Pop/ScreenStackPopPredicate.swift | 1 + .../Modifiers/ScreenStackClearModifier.swift | 8 +- .../Modifiers/ScreenStackModifier.swift | 2 + .../Modifiers/ScreenStackPushModifier.swift | 5 +- .../ScreenStackReplaceModifier.swift | 5 +- .../Animations/ScreenTabAnimation.swift | 1 + .../Animations/ScreenTabCustomAnimation.swift | 2 + .../Tabs/SelectTab/ScreenTabPredicate.swift | 1 + .../Animations/ScreenRootAnimation.swift | 1 + .../ScreenRootCustomAnimation.swift | 1 + .../Screen/Any/Aliases/AnyModalScreen.swift | 2 + .../Screen/Any/Aliases/AnyStackScreen.swift | 2 + .../Screen/Any/Aliases/AnyTabsScreen.swift | 2 + Sources/Screen/Any/AnyScreen.swift | 7 +- Sources/Screen/Any/AnyScreenBaseBox.swift | 2 +- Sources/Screen/Any/AnyScreenBox.swift | 4 +- .../Container/ScreenIterableContainer.swift | 1 + .../Container/ScreenKeyedContainer.swift | 1 + .../Container/ScreenVisibleContainer.swift | 1 + .../ScreenModalStyleDecorator.swift | 9 ++- .../ScreenPopoverPresentationAnchor.swift | 1 + .../ScreenPopoverPresentationDecorator.swift | 6 +- .../Modal/ScreenLeftBarButtonDecorator.swift | 6 +- .../Modal/ScreenRightBarButtonDecorator.swift | 6 +- .../Modal/ScreenStackContainerDecorator.swift | 10 ++- .../Modal/ScreenTabBarItemDecorator.swift | 6 +- .../Screen/Decorators/ScreenDecorator.swift | 2 + .../Stack/ScreenStackDecorator.swift | 12 ++- .../Decorators/Tabs/ScreenTabsDecorator.swift | 12 ++- .../Screen/Errors/ScreenCanceledError.swift | 15 ++-- ...creenContainerAlreadyPresentingError.swift | 19 ++--- .../Errors/ScreenContainerNotFoundError.swift | 19 ++--- .../ScreenContainerNotSupportedError.swift | 19 ++--- .../ScreenContainerTypeMismatchError.swift | 23 ++---- .../Navigator/Iterator/ScreenIterator.swift | 1 + .../Observatory/ScreenObservatory.swift | 1 + .../Screen/Navigator/ScreenNavigator.swift | 29 +++---- .../WindowProvider/ScreenWindowProvider.swift | 1 + .../Observation/ScreenObserverPredicate.swift | 1 + .../Storage/ScreenObserverStorage.swift | 1 + .../Payload/ScreenPayloadedContainer.swift | 1 + .../Screen/Route/ScreenRouteConvertible.swift | 1 + Sources/Screen/Route/ScreenThenable.swift | 1 + Sources/Screen/Screen.swift | 4 + Sources/Screen/ScreenKey.swift | 14 ++-- .../DictionaryDecoder/DictionaryDecoder.swift | 1 + Sources/Tools/KeyboardHandler.swift | 19 +++-- Sources/Tools/NotificationObserver.swift | 8 +- Sources/Tools/ObjectAssociation.swift | 2 +- .../URLQueryDecoder/URLQueryDecoder.swift | 1 + 142 files changed, 451 insertions(+), 468 deletions(-) diff --git a/.swift-version b/.swift-version index 760606e1..e0ea36fe 100644 --- a/.swift-version +++ b/.swift-version @@ -1 +1 @@ -5.7 +6.0 diff --git a/.xcode-version b/.xcode-version index dafb659a..0d68f8a0 100644 --- a/.xcode-version +++ b/.xcode-version @@ -1 +1 @@ -15.2 +16.0 diff --git a/Example/NivelirExample.xcodeproj/project.pbxproj b/Example/NivelirExample.xcodeproj/project.pbxproj index a81c16f1..43b5d3c8 100644 --- a/Example/NivelirExample.xcodeproj/project.pbxproj +++ b/Example/NivelirExample.xcodeproj/project.pbxproj @@ -1053,7 +1053,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 7VKZYG8P42; INFOPLIST_FILE = NivelirExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1061,7 +1061,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "ru.hh.Nivelir-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -1072,7 +1072,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; + DEVELOPMENT_TEAM = 7VKZYG8P42; INFOPLIST_FILE = NivelirExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1080,7 +1080,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "ru.hh.Nivelir-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/Example/NivelirExample/Dependencies/Screens.swift b/Example/NivelirExample/Dependencies/Screens.swift index 5daa4e73..b4e66332 100644 --- a/Example/NivelirExample/Dependencies/Screens.swift +++ b/Example/NivelirExample/Dependencies/Screens.swift @@ -1,6 +1,7 @@ import Foundation import Nivelir +@MainActor struct Screens { let services: Services diff --git a/Example/NivelirExample/Dependencies/Services.swift b/Example/NivelirExample/Dependencies/Services.swift index fe9580a3..4d4b5fd0 100644 --- a/Example/NivelirExample/Dependencies/Services.swift +++ b/Example/NivelirExample/Dependencies/Services.swift @@ -7,12 +7,14 @@ struct Services { let window: UIWindow + @MainActor func screenNavigator() -> ScreenNavigator { container.shared { ScreenNavigator(window: window) } } + @MainActor func deeplinkManager() -> DeeplinkManager { container.shared { DeeplinkManager( @@ -30,6 +32,7 @@ struct Services { } } + @MainActor func profileService() -> ProfileService { DefaultProfileService(authorizationService: authorizationService()) } diff --git a/Example/NivelirExample/Routing/Authorization/ScreenAuthorizeActionScreens.swift b/Example/NivelirExample/Routing/Authorization/ScreenAuthorizeActionScreens.swift index d9fc8b31..34ff2c05 100644 --- a/Example/NivelirExample/Routing/Authorization/ScreenAuthorizeActionScreens.swift +++ b/Example/NivelirExample/Routing/Authorization/ScreenAuthorizeActionScreens.swift @@ -1,6 +1,7 @@ import Foundation import Nivelir +@MainActor protocol ScreenAuthorizeActionScreens { func showAuthorizationRoute() -> ScreenWindowRoute diff --git a/Example/NivelirExample/Routing/Deeplinks/ChatDeeplink.swift b/Example/NivelirExample/Routing/Deeplinks/ChatDeeplink.swift index dda4bd0e..07b3af6a 100644 --- a/Example/NivelirExample/Routing/Deeplinks/ChatDeeplink.swift +++ b/Example/NivelirExample/Routing/Deeplinks/ChatDeeplink.swift @@ -6,6 +6,7 @@ struct ChatDeeplink { let roomID: Int let chatID: Int + @MainActor func navigate( screens: Screens, navigator: ScreenNavigator, diff --git a/Example/NivelirExample/Routing/Extensions/Alert+Extensions.swift b/Example/NivelirExample/Routing/Extensions/Alert+Extensions.swift index 3377a9e0..fac9b2f4 100644 --- a/Example/NivelirExample/Routing/Extensions/Alert+Extensions.swift +++ b/Example/NivelirExample/Routing/Extensions/Alert+Extensions.swift @@ -1,6 +1,7 @@ import UIKit import Nivelir +@MainActor extension Alert { static let somethingWentWrong = Self( diff --git a/Example/NivelirExample/SceneDelegate.swift b/Example/NivelirExample/SceneDelegate.swift index 00a61d29..858ff01d 100644 --- a/Example/NivelirExample/SceneDelegate.swift +++ b/Example/NivelirExample/SceneDelegate.swift @@ -8,7 +8,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { private var services: Services? private var screens: Screens? - private func setupNotifications() { + private nonisolated func setupNotifications() { #if os(iOS) let notificationCenter = UNUserNotificationCenter.current() @@ -148,7 +148,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } #if os(iOS) -extension SceneDelegate: UNUserNotificationCenterDelegate { +extension SceneDelegate: @preconcurrency UNUserNotificationCenterDelegate { func userNotificationCenter( _ center: UNUserNotificationCenter, diff --git a/Example/NivelirExample/Screens/Authorization/AuthorizationObserver.swift b/Example/NivelirExample/Screens/Authorization/AuthorizationObserver.swift index 10183db7..a4a3d484 100644 --- a/Example/NivelirExample/Screens/Authorization/AuthorizationObserver.swift +++ b/Example/NivelirExample/Screens/Authorization/AuthorizationObserver.swift @@ -1,6 +1,7 @@ import Foundation import Nivelir +@MainActor public protocol AuthorizationObserver: ScreenObserver { func authorizationFinished(isAuthorized: Bool) diff --git a/Example/NivelirExample/Screens/Authorization/AuthorizationViewController.swift b/Example/NivelirExample/Screens/Authorization/AuthorizationViewController.swift index 9e90adab..61e5d957 100644 --- a/Example/NivelirExample/Screens/Authorization/AuthorizationViewController.swift +++ b/Example/NivelirExample/Screens/Authorization/AuthorizationViewController.swift @@ -57,8 +57,8 @@ final class AuthorizationViewController: UIViewController, ScreenKeyedContainer switch result { case .success: - self.screenNavigator.navigate( - from: self.presenting, + screenNavigator.navigate( + from: presenting, to: { route in route .showHUD(.success, duration: 1.0) @@ -73,7 +73,7 @@ final class AuthorizationViewController: UIViewController, ScreenKeyedContainer ) case .failure: - self.screenNavigator.navigate { route in + screenNavigator.navigate { route in route.showHUD(.failure, duration: 1.0) } } diff --git a/Example/NivelirExample/Services/Authorization/AuthorizationService.swift b/Example/NivelirExample/Services/Authorization/AuthorizationService.swift index 7ffb10f8..caefa606 100644 --- a/Example/NivelirExample/Services/Authorization/AuthorizationService.swift +++ b/Example/NivelirExample/Services/Authorization/AuthorizationService.swift @@ -1,9 +1,10 @@ import Foundation -protocol AuthorizationService { +protocol AuthorizationService: Sendable { var isAuthorized: Bool { get } + @MainActor func login( phoneNumber: String, completion: @escaping (_ result: Result) -> Void diff --git a/Example/NivelirExample/Services/Profile/DefaultProfileService.swift b/Example/NivelirExample/Services/Profile/DefaultProfileService.swift index c97fea04..f7db6d8b 100644 --- a/Example/NivelirExample/Services/Profile/DefaultProfileService.swift +++ b/Example/NivelirExample/Services/Profile/DefaultProfileService.swift @@ -1,69 +1,66 @@ import UIKit -final class DefaultProfileService: ProfileService { +final class DefaultProfileService: ProfileService, Sendable { + + private class UncheckedCGFloat: @unchecked Sendable { + var value: CGFloat = .zero + } private let authorizationService: AuthorizationService + private let intervalCount = UncheckedCGFloat() init(authorizationService: AuthorizationService) { self.authorizationService = authorizationService } - private func finishSucceedUploading( - timer: Timer, - progress: @escaping (_ ratio: CGFloat) -> Void, - completion: @escaping (_ result: Result) -> Void - ) { - timer.invalidate() - progress(1.0) - - DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { - completion(.success(Void())) - } - } - - private func finishFailedUploading( - timer: Timer, - completion: @escaping (_ result: Result) -> Void - ) { - timer.invalidate() - - DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { - completion(.failure(ProfileError.unavailable)) - } - } - func uploadPhoto( image: UIImage, - progress: @escaping (_ ratio: CGFloat) -> Void, - completion: @escaping (_ result: Result) -> Void + progress: @MainActor @Sendable @escaping (_ ratio: CGFloat) -> Void, + completion: @MainActor @Sendable @escaping (_ result: Result) -> Void ) { + intervalCount.value = .zero guard authorizationService.isAuthorized else { return completion(.failure(ProfileError.unauthorized)) } - var intervalCount: CGFloat = .zero + Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true) { [weak self] timer in + guard let self else { + return + } + + guard intervalCount.value <= 100 else { + timer.invalidate() + + Task { + await MainActor.run { + progress(1.0) + } + } - Timer.scheduledTimer(withTimeInterval: 0.05, repeats: true) { timer in - guard intervalCount <= 100 else { - return self.finishSucceedUploading( - timer: timer, - progress: progress, - completion: completion - ) + DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { + completion(.success(Void())) + } + return } let random = Int.random(in: 1...1000) - guard random < 997 || intervalCount < 50 else { - return self.finishFailedUploading( - timer: timer, - completion: completion - ) + guard random < 997 || intervalCount.value < 50 else { + timer.invalidate() + + DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) { + completion(.failure(ProfileError.unavailable)) + } + return } - progress(intervalCount * 0.01) + Task { + await MainActor.run { + progress(intervalCount.value * 0.01) + } + } - intervalCount += 1.0 + intervalCount.value += 1.0 } } } diff --git a/Example/NivelirExample/Services/Profile/ProfileService.swift b/Example/NivelirExample/Services/Profile/ProfileService.swift index 8605324a..bbb3160c 100644 --- a/Example/NivelirExample/Services/Profile/ProfileService.swift +++ b/Example/NivelirExample/Services/Profile/ProfileService.swift @@ -1,10 +1,11 @@ import UIKit +@MainActor protocol ProfileService { func uploadPhoto( image: UIImage, - progress: @escaping (_ ratio: CGFloat) -> Void, - completion: @escaping (_ result: Result) -> Void + progress: @MainActor @Sendable @escaping (_ ratio: CGFloat) -> Void, + completion: @MainActor @Sendable @escaping (_ result: Result) -> Void ) } diff --git a/Nivelir.xcodeproj/project.pbxproj b/Nivelir.xcodeproj/project.pbxproj index da48840d..f9fca6b7 100755 --- a/Nivelir.xcodeproj/project.pbxproj +++ b/Nivelir.xcodeproj/project.pbxproj @@ -3291,6 +3291,7 @@ DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_DYNAMIC_NO_PIC = NO; GCC_NO_COMMON_BLOCKS = YES; @@ -3356,6 +3357,7 @@ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; GCC_C_LANGUAGE_STANDARD = gnu11; GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; @@ -3388,6 +3390,7 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -3403,7 +3406,7 @@ SKIP_INSTALL = YES; SKIP_SWIFTLINT = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -3419,6 +3422,7 @@ DYLIB_CURRENT_VERSION = 1; DYLIB_INSTALL_NAME_BASE = "@rpath"; ENABLE_MODULE_VERIFIER = YES; + ENABLE_USER_SCRIPT_SANDBOXING = NO; INFOPLIST_FILE = Sources/Info.plist; INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; LD_RUNPATH_SEARCH_PATHS = ( @@ -3433,7 +3437,7 @@ PRODUCT_NAME = Nivelir; SKIP_INSTALL = YES; SKIP_SWIFTLINT = YES; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; diff --git a/Sources/Addons/Alert/AlertTextField.swift b/Sources/Addons/Alert/AlertTextField.swift index 1cfe8d33..5257e159 100644 --- a/Sources/Addons/Alert/AlertTextField.swift +++ b/Sources/Addons/Alert/AlertTextField.swift @@ -2,7 +2,7 @@ import UIKit /// Types of text fields added to the alert. -public enum AlertTextField { +public enum AlertTextField: Sendable { /// A text field, with text and placeholder customization. case standard( @@ -13,7 +13,7 @@ public enum AlertTextField { /// A text field, customizable via block for configuring the text field prior to displaying the alert. /// This block has no return value and takes a single parameter corresponding to the text field object. /// Use that parameter to change the text field properties. - case custom(configuration: (UITextField) -> Void) + case custom(configuration: @Sendable (UITextField) -> Void) } extension AlertTextField { diff --git a/Sources/Addons/Alert/AlertTextFieldsManager.swift b/Sources/Addons/Alert/AlertTextFieldsManager.swift index 2d7097e3..4a3c81b7 100644 --- a/Sources/Addons/Alert/AlertTextFieldsManager.swift +++ b/Sources/Addons/Alert/AlertTextFieldsManager.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor internal final class AlertTextFieldsManager: NSObject { private let textFields: [UITextField?] diff --git a/Sources/Addons/BottomSheet/Action/InvalidBottomSheetContainerError.swift b/Sources/Addons/BottomSheet/Action/InvalidBottomSheetContainerError.swift index d4295de3..07b4ef45 100644 --- a/Sources/Addons/BottomSheet/Action/InvalidBottomSheetContainerError.swift +++ b/Sources/Addons/BottomSheet/Action/InvalidBottomSheetContainerError.swift @@ -2,20 +2,14 @@ import Foundation public struct InvalidBottomSheetContainerError: ScreenError { - public var description: String { - """ + public let description: String + + public init(container: ScreenContainer, for trigger: Any) { + description = """ The container \(container) is not presented as a bottom sheet for: \(trigger) """ } - - public let container: ScreenContainer - public let trigger: Any - - public init(container: ScreenContainer, for trigger: Any) { - self.container = container - self.trigger = trigger - } } extension Result where Failure == Error { diff --git a/Sources/Addons/BottomSheet/Animations/BottomSheetAnimationOptions.swift b/Sources/Addons/BottomSheet/Animations/BottomSheetAnimationOptions.swift index 3b9e0f86..329ca497 100644 --- a/Sources/Addons/BottomSheet/Animations/BottomSheetAnimationOptions.swift +++ b/Sources/Addons/BottomSheet/Animations/BottomSheetAnimationOptions.swift @@ -1,7 +1,7 @@ #if canImport(UIKit) import UIKit -public struct BottomSheetAnimationOptions: Equatable { +public struct BottomSheetAnimationOptions: Equatable, Sendable { public static let transition = Self() public static let changes = Self(duration: 0.3) diff --git a/Sources/Addons/BottomSheet/Animations/BottomSheetDismissAnimation.swift b/Sources/Addons/BottomSheet/Animations/BottomSheetDismissAnimation.swift index ce9b5215..63215642 100644 --- a/Sources/Addons/BottomSheet/Animations/BottomSheetDismissAnimation.swift +++ b/Sources/Addons/BottomSheet/Animations/BottomSheetDismissAnimation.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor internal class BottomSheetDismissAnimation: NSObject { private var animator: UIViewImplicitlyAnimating? diff --git a/Sources/Addons/BottomSheet/Animations/BottomSheetPresentAnimation.swift b/Sources/Addons/BottomSheet/Animations/BottomSheetPresentAnimation.swift index 53c7dc5c..cc22e408 100644 --- a/Sources/Addons/BottomSheet/Animations/BottomSheetPresentAnimation.swift +++ b/Sources/Addons/BottomSheet/Animations/BottomSheetPresentAnimation.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor internal class BottomSheetPresentAnimation: NSObject { private var animator: UIViewImplicitlyAnimating? diff --git a/Sources/Addons/BottomSheet/BottomSheet.swift b/Sources/Addons/BottomSheet/BottomSheet.swift index 1847c90f..49f0b17c 100644 --- a/Sources/Addons/BottomSheet/BottomSheet.swift +++ b/Sources/Addons/BottomSheet/BottomSheet.swift @@ -1,9 +1,8 @@ #if canImport(UIKit) import Foundation -public struct BottomSheet { - - public static let `default` = Self() +@MainActor +public struct BottomSheet: Sendable { public let detents: [BottomSheetDetent] public let selectedDetentKey: BottomSheetDetentKey? @@ -23,18 +22,18 @@ public struct BottomSheet { public let presentAnimationOptions: BottomSheetAnimationOptions public let dismissAnimationOptions: BottomSheetAnimationOptions - public let canEndEditing: (() -> Bool)? - public let shouldDismiss: (() -> Bool)? + public let canEndEditing: (@Sendable () -> Bool)? + public let shouldDismiss: (@Sendable () -> Bool)? - public let didAttemptToDismiss: (() -> Void)? + public let didAttemptToDismiss: (@Sendable () -> Void)? - public let willDismiss: (() -> Void)? - public let didDismiss: (() -> Void)? + public let willDismiss: (@Sendable () -> Void)? + public let didDismiss: (@Sendable () -> Void)? - public let didChangeSelectedDetentKey: ((_ detentKey: BottomSheetDetentKey?) -> Void)? + public let didChangeSelectedDetentKey: (@Sendable(_ detentKey: BottomSheetDetentKey?) -> Void)? public init( - detents: [BottomSheetDetent] = [.large], + detents: [BottomSheetDetent]? = nil, selectedDetentKey: BottomSheetDetentKey? = nil, preferredDimming: BottomSheetDimming = .default, preferredCard: BottomSheetCard = .default, @@ -47,14 +46,14 @@ public struct BottomSheet { changesAnimationOptions: BottomSheetAnimationOptions = .changes, presentAnimationOptions: BottomSheetAnimationOptions = .transition, dismissAnimationOptions: BottomSheetAnimationOptions = .transition, - canEndEditing: (() -> Bool)? = nil, - shouldDismiss: (() -> Bool)? = nil, - didAttemptToDismiss: (() -> Void)? = nil, - willDismiss: (() -> Void)? = nil, - didDismiss: (() -> Void)? = nil, - didChangeSelectedDetentKey: ((_ detentKey: BottomSheetDetentKey?) -> Void)? = nil + canEndEditing: (@Sendable () -> Bool)? = nil, + shouldDismiss: (@Sendable () -> Bool)? = nil, + didAttemptToDismiss: (@Sendable () -> Void)? = nil, + willDismiss: (@Sendable () -> Void)? = nil, + didDismiss: (@Sendable () -> Void)? = nil, + didChangeSelectedDetentKey: (@Sendable (_ detentKey: BottomSheetDetentKey?) -> Void)? = nil ) { - self.detents = detents + self.detents = detents ?? [.large] self.selectedDetentKey = selectedDetentKey self.preferredDimming = preferredDimming diff --git a/Sources/Addons/BottomSheet/BottomSheetBorder.swift b/Sources/Addons/BottomSheet/BottomSheetBorder.swift index f1182810..a5f3c720 100644 --- a/Sources/Addons/BottomSheet/BottomSheetBorder.swift +++ b/Sources/Addons/BottomSheet/BottomSheetBorder.swift @@ -1,7 +1,7 @@ #if canImport(UIKit) import UIKit -public struct BottomSheetBorder: Equatable { +public struct BottomSheetBorder: Equatable, Sendable { public static let `default` = Self() diff --git a/Sources/Addons/BottomSheet/BottomSheetCard.swift b/Sources/Addons/BottomSheet/BottomSheetCard.swift index d729b72e..a3297c13 100644 --- a/Sources/Addons/BottomSheet/BottomSheetCard.swift +++ b/Sources/Addons/BottomSheet/BottomSheetCard.swift @@ -1,7 +1,7 @@ #if canImport(UIKit) import UIKit -public struct BottomSheetCard: Equatable { +public struct BottomSheetCard: Equatable, Sendable { public static let `default` = Self() diff --git a/Sources/Addons/BottomSheet/BottomSheetController.swift b/Sources/Addons/BottomSheet/BottomSheetController.swift index 11f00412..31784ca9 100644 --- a/Sources/Addons/BottomSheet/BottomSheetController.swift +++ b/Sources/Addons/BottomSheet/BottomSheetController.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor public class BottomSheetController: NSObject { private weak var presentation: BottomSheetPresentationController? @@ -102,7 +103,10 @@ public class BottomSheetController: NSObject { public var didChangeSelectedDetentKey: ((_ detentKey: BottomSheetDetentKey?) -> Void)? - public init(bottomSheet: BottomSheet = .default) { + /// Optional init required because of complier crash with not-nil default value. + /// Reprodused in Xcode 16.0 with Swift 6.0 + public init(bottomSheet: BottomSheet? = nil) { + let bottomSheet = bottomSheet ?? BottomSheet() self.detents = bottomSheet.detents self.selectedDetentKey = bottomSheet.selectedDetentKey diff --git a/Sources/Addons/BottomSheet/BottomSheetGrabber.swift b/Sources/Addons/BottomSheet/BottomSheetGrabber.swift index 4119aa10..fe404d36 100644 --- a/Sources/Addons/BottomSheet/BottomSheetGrabber.swift +++ b/Sources/Addons/BottomSheet/BottomSheetGrabber.swift @@ -1,7 +1,7 @@ #if canImport(UIKit) import UIKit -public struct BottomSheetGrabber: Equatable { +public struct BottomSheetGrabber: Equatable, Sendable { public static let `default` = Self() diff --git a/Sources/Addons/BottomSheet/BottomSheetRubberBandEffect.swift b/Sources/Addons/BottomSheet/BottomSheetRubberBandEffect.swift index 1b27aba4..713f4349 100644 --- a/Sources/Addons/BottomSheet/BottomSheetRubberBandEffect.swift +++ b/Sources/Addons/BottomSheet/BottomSheetRubberBandEffect.swift @@ -1,11 +1,11 @@ #if canImport(UIKit) import UIKit -public struct BottomSheetRubberBandEffect { +public struct BottomSheetRubberBandEffect: Sendable { - public let handler: (_ delta: CGFloat) -> CGFloat + public let handler: @Sendable (_ delta: CGFloat) -> CGFloat - public init(handler: @escaping (_ delta: CGFloat) -> CGFloat) { + public init(handler: @escaping @Sendable (_ delta: CGFloat) -> CGFloat) { self.handler = handler } diff --git a/Sources/Addons/BottomSheet/BottomSheetShadow.swift b/Sources/Addons/BottomSheet/BottomSheetShadow.swift index 88c9d2b6..fe84e1dd 100644 --- a/Sources/Addons/BottomSheet/BottomSheetShadow.swift +++ b/Sources/Addons/BottomSheet/BottomSheetShadow.swift @@ -1,7 +1,7 @@ #if canImport(UIKit) import UIKit -public struct BottomSheetShadow: Equatable { +public struct BottomSheetShadow: Equatable, Sendable { public static let `default` = Self() diff --git a/Sources/Addons/BottomSheet/Decorators/ScreenBottomSheetDecorator.swift b/Sources/Addons/BottomSheet/Decorators/ScreenBottomSheetDecorator.swift index 9e5d6b89..476489fc 100644 --- a/Sources/Addons/BottomSheet/Decorators/ScreenBottomSheetDecorator.swift +++ b/Sources/Addons/BottomSheet/Decorators/ScreenBottomSheetDecorator.swift @@ -11,13 +11,12 @@ public struct ScreenBottomSheetDecorator: ScreenDec bottomSheetController } - public var description: String { - "BottomSheetDecorator" - } + public let description: String public init(bottomSheet: BottomSheet) { self.bottomSheet = bottomSheet self.bottomSheetController = BottomSheetController(bottomSheet: bottomSheet) + description = "BottomSheetDecorator" } public func build( @@ -35,6 +34,7 @@ public struct ScreenBottomSheetDecorator: ScreenDec extension Screen where Container: UIViewController { + @MainActor public func withBottomSheet(_ bottomSheet: BottomSheet) -> AnyScreen { decorated(by: ScreenBottomSheetDecorator(bottomSheet: bottomSheet)) } diff --git a/Sources/Addons/BottomSheet/Decorators/ScreenBottomSheetStackDecorator.swift b/Sources/Addons/BottomSheet/Decorators/ScreenBottomSheetStackDecorator.swift index 0969361e..990f2c05 100644 --- a/Sources/Addons/BottomSheet/Decorators/ScreenBottomSheetStackDecorator.swift +++ b/Sources/Addons/BottomSheet/Decorators/ScreenBottomSheetStackDecorator.swift @@ -12,12 +12,11 @@ public struct ScreenBottomSheetStackDecorator< nil } - public var description: String { - "ScreenBottomSheetStackDecorator" - } + public let description: String public init(bottomSheet: BottomSheet) { self.bottomSheet = bottomSheet + description = "ScreenBottomSheetStackDecorator" } public func build( @@ -33,6 +32,7 @@ public struct ScreenBottomSheetStackDecorator< extension Screen where Container: UIViewController { + @MainActor public func withBottomSheetStack( _ bottomSheet: BottomSheet, of type: Output.Type @@ -40,6 +40,7 @@ extension Screen where Container: UIViewController { decorated(by: ScreenBottomSheetStackDecorator(bottomSheet: bottomSheet)) } + @MainActor public func withBottomSheetStack(_ bottomSheet: BottomSheet) -> AnyScreen { withBottomSheetStack(bottomSheet, of: BottomSheetStackController.self) } diff --git a/Sources/Addons/BottomSheet/Detention/BottomSheetDetentionController.swift b/Sources/Addons/BottomSheet/Detention/BottomSheetDetentionController.swift index ddce0f27..113a5e8d 100644 --- a/Sources/Addons/BottomSheet/Detention/BottomSheetDetentionController.swift +++ b/Sources/Addons/BottomSheet/Detention/BottomSheetDetentionController.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor internal final class BottomSheetDetentionController { private var cachedDetentValues: [BottomSheetDetentKey: CGFloat?] = [:] @@ -79,7 +80,9 @@ internal final class BottomSheetDetentionController { } let smallestDetentValue = detents - .compactMap(resolveDetentValue(detent:)) + .compactMap { detent in + resolveDetentValue(detent: detent) + } .min() ?? .zero cachedSmallestDetentValueIgnoringKeyboard = smallestDetentValue @@ -93,7 +96,9 @@ internal final class BottomSheetDetentionController { } let smallestDetentValue = detents - .compactMap(resolveDetentValue(detent:)) + .compactMap { detent in + resolveDetentValue(detent: detent) + } .min() .map { min($0 + keyboardHeight, maximumDetentValue) } ?? .zero @@ -108,7 +113,9 @@ internal final class BottomSheetDetentionController { } let largestDetentValue = detents - .compactMap(resolveDetentValue(detent:)) + .compactMap { detent in + resolveDetentValue(detent: detent) + } .max() .map { min($0 + keyboardHeight, maximumDetentValue) } ?? .zero diff --git a/Sources/Addons/BottomSheet/Detention/BottomSheetDetentionDelegate.swift b/Sources/Addons/BottomSheet/Detention/BottomSheetDetentionDelegate.swift index 71e8991b..79b225d8 100644 --- a/Sources/Addons/BottomSheet/Detention/BottomSheetDetentionDelegate.swift +++ b/Sources/Addons/BottomSheet/Detention/BottomSheetDetentionDelegate.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import Foundation +@MainActor internal protocol BottomSheetDetentionDelegate: AnyObject { func bottomSheetCanEndEditing() -> Bool diff --git a/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetent.swift b/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetent.swift index 0459b430..1a27b736 100644 --- a/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetent.swift +++ b/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetent.swift @@ -1,9 +1,10 @@ #if canImport(UIKit) import Foundation -public struct BottomSheetDetent { +@MainActor +public struct BottomSheetDetent: Sendable { - public typealias Resolver = (_ context: BottomSheetDetentContext) -> CGFloat? + public typealias Resolver = @MainActor @Sendable (_ context: BottomSheetDetentContext) -> CGFloat? public let key: BottomSheetDetentKey public let resolver: Resolver diff --git a/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetentContext.swift b/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetentContext.swift index c3b2093d..a59f2d85 100644 --- a/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetentContext.swift +++ b/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetentContext.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor public protocol BottomSheetDetentContext { var presentedViewController: UIViewController { get } diff --git a/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetentKey.swift b/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetentKey.swift index f86f7a7f..f55f2aaa 100644 --- a/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetentKey.swift +++ b/Sources/Addons/BottomSheet/Detention/Detent/BottomSheetDetentKey.swift @@ -1,7 +1,7 @@ #if canImport(UIKit) import Foundation -public struct BottomSheetDetentKey: Hashable, RawRepresentable { +public struct BottomSheetDetentKey: Hashable, RawRepresentable, Sendable { public let rawValue: String diff --git a/Sources/Addons/BottomSheet/Dimming/BottomSheetDimming.swift b/Sources/Addons/BottomSheet/Dimming/BottomSheetDimming.swift index 335b31df..f10f9a35 100644 --- a/Sources/Addons/BottomSheet/Dimming/BottomSheetDimming.swift +++ b/Sources/Addons/BottomSheet/Dimming/BottomSheetDimming.swift @@ -1,7 +1,7 @@ #if canImport(UIKit) import UIKit -public struct BottomSheetDimming: Equatable { +public struct BottomSheetDimming: Equatable, Sendable { public static let `default` = Self() diff --git a/Sources/Addons/BottomSheet/Interaction/BottomSheetInteractionController.swift b/Sources/Addons/BottomSheet/Interaction/BottomSheetInteractionController.swift index 7f9cd7af..b7be9429 100644 --- a/Sources/Addons/BottomSheet/Interaction/BottomSheetInteractionController.swift +++ b/Sources/Addons/BottomSheet/Interaction/BottomSheetInteractionController.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor internal final class BottomSheetInteractionController: NSObject { private var interaction: BottomSheetInteraction = BottomSheetDismissedInteraction() @@ -49,7 +50,9 @@ internal final class BottomSheetInteractionController: NSObject { state = .starting simultaneousScrollObservation = simultaneousScrollView?.observe(\.contentOffset) { [weak self] _, _ in - self?.resetSimultaneousScrollIfNeeded() + Task { + await self?.resetSimultaneousScrollIfNeeded() + } } interaction.start( diff --git a/Sources/Addons/BottomSheet/Interaction/Interactions/BottomSheetInteraction.swift b/Sources/Addons/BottomSheet/Interaction/Interactions/BottomSheetInteraction.swift index 57f36f1d..8856bd96 100644 --- a/Sources/Addons/BottomSheet/Interaction/Interactions/BottomSheetInteraction.swift +++ b/Sources/Addons/BottomSheet/Interaction/Interactions/BottomSheetInteraction.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor internal protocol BottomSheetInteraction { var gestureInitialValue: CGFloat { get } diff --git a/Sources/Addons/DocumentPreview/DocumentPreview.swift b/Sources/Addons/DocumentPreview/DocumentPreview.swift index 34044f67..a845165e 100644 --- a/Sources/Addons/DocumentPreview/DocumentPreview.swift +++ b/Sources/Addons/DocumentPreview/DocumentPreview.swift @@ -31,9 +31,7 @@ public struct DocumentPreview: CustomStringConvertible { /// Called when a document interaction controller’s document has been handed off to the specified application. public let didEndSendingToApplication: ((_ bundleID: String?) -> Void)? - public var description: String { - "DocumentPreview(\"\(url)\")" - } + public let description: String /// Creates and returns a new `DocumentPreview` object. /// - Parameters: @@ -71,6 +69,8 @@ public struct DocumentPreview: CustomStringConvertible { self.willBeginSendingToApplication = willBeginSendingToApplication self.didEndSendingToApplication = didEndSendingToApplication + + description = "DocumentPreview(\"\(url)\")" } } diff --git a/Sources/Addons/DocumentPreview/DocumentPreviewAnchor.swift b/Sources/Addons/DocumentPreview/DocumentPreviewAnchor.swift index 5c9fac78..5afbf63c 100644 --- a/Sources/Addons/DocumentPreview/DocumentPreviewAnchor.swift +++ b/Sources/Addons/DocumentPreview/DocumentPreviewAnchor.swift @@ -2,6 +2,7 @@ import UIKit /// Anchor of the starting point for animating the display of a document preview. +@MainActor public struct DocumentPreviewAnchor { /// The rectangle to use as the starting point for animating diff --git a/Sources/Addons/DocumentPreview/DocumentPreviewManager.swift b/Sources/Addons/DocumentPreview/DocumentPreviewManager.swift index e212c140..e0d0e940 100644 --- a/Sources/Addons/DocumentPreview/DocumentPreviewManager.swift +++ b/Sources/Addons/DocumentPreview/DocumentPreviewManager.swift @@ -26,7 +26,9 @@ internal final class DocumentPreviewManager: _ controller: UIDocumentInteractionController ) -> UIView? { documentPreview.anchor.map { anchor in - anchor.view ?? container.view + MainActor.assumeIsolated { [container] in + anchor.view ?? container.view + } } } @@ -34,12 +36,14 @@ internal final class DocumentPreviewManager: _ controller: UIDocumentInteractionController ) -> CGRect { documentPreview.anchor.map { anchor in - anchor.rect ?? CGRect( - x: container.view.bounds.midX, - y: container.view.bounds.midY, - width: .zero, - height: .zero - ) + MainActor.assumeIsolated { [container] in + anchor.rect ?? CGRect( + x: container.view.bounds.midX, + y: container.view.bounds.midY, + width: .zero, + height: .zero + ) + } } ?? .zero } diff --git a/Sources/Addons/HUD/Animation/HUDAnimation.swift b/Sources/Addons/HUD/Animation/HUDAnimation.swift index 3ca993c9..ffb0904b 100644 --- a/Sources/Addons/HUD/Animation/HUDAnimation.swift +++ b/Sources/Addons/HUD/Animation/HUDAnimation.swift @@ -2,6 +2,7 @@ import UIKit /// The animation type that should be used when the ``HUD`` is shown and hidden. +@MainActor public enum HUDAnimation { /// Custom animation for showing and hiding the HUD. diff --git a/Sources/Addons/HUD/Animation/HUDCustomAnimation.swift b/Sources/Addons/HUD/Animation/HUDCustomAnimation.swift index 8bc8a432..a3efc753 100644 --- a/Sources/Addons/HUD/Animation/HUDCustomAnimation.swift +++ b/Sources/Addons/HUD/Animation/HUDCustomAnimation.swift @@ -4,6 +4,7 @@ import UIKit /// A type describing the animation of showing, updating and hiding the ``HUD``. /// /// See ``HUDDefaultAnimation`` for example. +@MainActor public protocol HUDCustomAnimation { /// Animates the appearance for the specified `view`. diff --git a/Sources/Addons/HUD/HUD.swift b/Sources/Addons/HUD/HUD.swift index 7af8b6a1..6abcb8a5 100644 --- a/Sources/Addons/HUD/HUD.swift +++ b/Sources/Addons/HUD/HUD.swift @@ -6,6 +6,7 @@ import UIKit /// The HUD is displayed on top of the `UIWindow` with a dimmed background and progress in the center of the screen. /// The style and progress of the HUD is fully customizable. /// Use the ``progress`` and ``style`` properties for this. +@MainActor public struct HUD: CustomStringConvertible { /// Creates a HUD with ``HUDStyle/default`` style. @@ -21,9 +22,7 @@ public struct HUD: CustomStringConvertible { /// Configuration the appearance of the HUD. public let style: HUDStyle - public var description: String { - "HUD(\(progress))" - } + public let description: String /// Creates a HUD with progress and style representations. /// - Parameters: @@ -35,6 +34,7 @@ public struct HUD: CustomStringConvertible { ) { self.progress = progress self.style = style + description = "HUD(\(progress))" } } diff --git a/Sources/Addons/HUD/HUDStyle.swift b/Sources/Addons/HUD/HUDStyle.swift index c354b9a5..7f73893f 100644 --- a/Sources/Addons/HUD/HUDStyle.swift +++ b/Sources/Addons/HUD/HUDStyle.swift @@ -2,7 +2,7 @@ import UIKit /// The style that will be applied to the appearance of the HUD. -public struct HUDStyle { +public struct HUDStyle: Sendable { /// Default style. /// diff --git a/Sources/Addons/HUD/HUDView.swift b/Sources/Addons/HUD/HUDView.swift index dfd3f0d6..70027b31 100644 --- a/Sources/Addons/HUD/HUDView.swift +++ b/Sources/Addons/HUD/HUDView.swift @@ -156,7 +156,9 @@ extension HUDView { let timer = duration.map { duration in Timer.scheduledTimer(withTimeInterval: duration, repeats: false) { _ in - hideHUD(in: window, completion: nil) + MainActor.assumeIsolated { + hideHUD(in: window, completion: nil) + } } } diff --git a/Sources/Addons/HUD/Progress/Animation/ProgressAnimation.swift b/Sources/Addons/HUD/Progress/Animation/ProgressAnimation.swift index 1473b01a..4b21a5c4 100644 --- a/Sources/Addons/HUD/Progress/Animation/ProgressAnimation.swift +++ b/Sources/Addons/HUD/Progress/Animation/ProgressAnimation.swift @@ -4,6 +4,7 @@ import UIKit /// The type of progress view animation of the ``HUD``. /// /// An animation is used to update and show the `header`, `indicator` and `footer` parts of the progress view. +@MainActor public enum ProgressAnimation { /// Custom animation for showing progress view of the HUD. diff --git a/Sources/Addons/HUD/Progress/Animation/ProgressCustomAnimation.swift b/Sources/Addons/HUD/Progress/Animation/ProgressCustomAnimation.swift index 0019af2e..637b6c4c 100644 --- a/Sources/Addons/HUD/Progress/Animation/ProgressCustomAnimation.swift +++ b/Sources/Addons/HUD/Progress/Animation/ProgressCustomAnimation.swift @@ -4,6 +4,7 @@ import UIKit /// A type describing the animation of updating progress view of``HUD``. /// /// See ``ProgressDefaultAnimation`` for example. +@MainActor public protocol ProgressCustomAnimation { /// Animates updates of parts of the progress view. diff --git a/Sources/Addons/HUD/Progress/Content/AnyProgressContent.swift b/Sources/Addons/HUD/Progress/Content/AnyProgressContent.swift index 10116d86..29298649 100644 --- a/Sources/Addons/HUD/Progress/Content/AnyProgressContent.swift +++ b/Sources/Addons/HUD/Progress/Content/AnyProgressContent.swift @@ -4,6 +4,7 @@ import UIKit /// Erased protocol type ``ProgressContent``. /// /// - SeeAlso: ``ProgressContent`` +@MainActor public protocol AnyProgressContent { /// A console log representation of `self`. diff --git a/Sources/Addons/HUD/Progress/Content/ProgressContent.swift b/Sources/Addons/HUD/Progress/Content/ProgressContent.swift index 6026df91..a6fb1604 100644 --- a/Sources/Addons/HUD/Progress/Content/ProgressContent.swift +++ b/Sources/Addons/HUD/Progress/Content/ProgressContent.swift @@ -6,6 +6,7 @@ import UIKit /// This protocol provides a blueprint for a content object, which encompasses content for a content view. /// The content encapsulates all of the supported properties and behaviors for content view customization. /// You use the content to create the content view. +@MainActor public protocol ProgressContent: AnyProgressContent, Equatable { /// The view type associated with the content. diff --git a/Sources/Addons/HUD/Progress/Indicator/Percentage/ProgressPercentageIndicator.swift b/Sources/Addons/HUD/Progress/Indicator/Percentage/ProgressPercentageIndicator.swift index 6f7c9986..0b477334 100644 --- a/Sources/Addons/HUD/Progress/Indicator/Percentage/ProgressPercentageIndicator.swift +++ b/Sources/Addons/HUD/Progress/Indicator/Percentage/ProgressPercentageIndicator.swift @@ -23,9 +23,7 @@ public struct ProgressPercentageIndicator: ProgressIndicator { /// Additional indents to expand the container. public let insets: UIEdgeInsets - public var logDescription: String? { - ".percentage(\(ratio))" - } + public let logDescription: String? /// Creates new indicator content. /// - Parameters: @@ -45,8 +43,10 @@ public struct ProgressPercentageIndicator: ProgressIndicator { self.ratio = ratio self.color = color self.insets = insets + logDescription = ".percentage(\(ratio))" } + @MainActor public func updateContentView(_ contentView: View) -> View { contentView.content = self diff --git a/Sources/Addons/HUD/Progress/Progress.swift b/Sources/Addons/HUD/Progress/Progress.swift index ff8220f1..1f0564e3 100644 --- a/Sources/Addons/HUD/Progress/Progress.swift +++ b/Sources/Addons/HUD/Progress/Progress.swift @@ -8,6 +8,8 @@ import Foundation /// which are configured through the content /// by implementing the appropriate protocols ``ProgressHeader``, ``ProgressIndicator`` and ``ProgressFooter``. /// Each component is displayed with an animation defined in the ``animation`` property. + +@MainActor public struct Progress: CustomStringConvertible { /// Erased type of header content. @@ -22,20 +24,7 @@ public struct Progress: CustomStringConvertible { /// Animation of the appearance of progress components. public let animation: ProgressAnimation? - public var description: String { - let fields = [ - "header": header, - "indicator": indicator, - "footer": footer - ] - - return fields - .compactMap { key, value in - value.logDescription.map { (key, $0) } - } - .map { "\($0): \($1)" } - .joined(separator: ", ") - } + public let description: String /// Creates a new object with progress components and animation. /// - Parameters: @@ -57,6 +46,19 @@ public struct Progress: CustomStringConvertible { self.indicator = indicator self.footer = footer self.animation = animation + + let fields: [String: AnyProgressContent] = [ + "header": header, + "indicator": indicator, + "footer": footer + ] + + description = fields + .compactMap { key, value in + value.logDescription.map { (key, $0) } + } + .map { "\($0): \($1)" } + .joined(separator: ", ") } } diff --git a/Sources/Addons/MediaPicker/Errors/MediaPickerSourceAccessDeniedError.swift b/Sources/Addons/MediaPicker/Errors/MediaPickerSourceAccessDeniedError.swift index 55a12e0d..a15c326b 100644 --- a/Sources/Addons/MediaPicker/Errors/MediaPickerSourceAccessDeniedError.swift +++ b/Sources/Addons/MediaPicker/Errors/MediaPickerSourceAccessDeniedError.swift @@ -3,18 +3,14 @@ import Foundation public struct MediaPickerSourceAccessDeniedError: ScreenError { - public var description: String { - """ + public let description: String + + public init(for trigger: Any) { + description = """ User does not allow the app to access the media source for: \(trigger) """ } - - public let trigger: Any - - public init(for trigger: Any) { - self.trigger = trigger - } } extension Result where Failure == Error { diff --git a/Sources/Addons/MediaPicker/Errors/UnavailableMediaPickerSourceError.swift b/Sources/Addons/MediaPicker/Errors/UnavailableMediaPickerSourceError.swift index 1f743a05..c59facb3 100644 --- a/Sources/Addons/MediaPicker/Errors/UnavailableMediaPickerSourceError.swift +++ b/Sources/Addons/MediaPicker/Errors/UnavailableMediaPickerSourceError.swift @@ -3,18 +3,14 @@ import Foundation public struct UnavailableMediaPickerSourceError: ScreenError { - public var description: String { - """ + public let description: String + + public init(for trigger: Any) { + description = """ Media source is not available for: \(trigger) """ } - - public let trigger: Any - - public init(for trigger: Any) { - self.trigger = trigger - } } extension Result where Failure == Error { diff --git a/Sources/Addons/MediaPicker/Errors/UnavailableMediaPickerTypesError.swift b/Sources/Addons/MediaPicker/Errors/UnavailableMediaPickerTypesError.swift index 9bbbe1a5..31673291 100644 --- a/Sources/Addons/MediaPicker/Errors/UnavailableMediaPickerTypesError.swift +++ b/Sources/Addons/MediaPicker/Errors/UnavailableMediaPickerTypesError.swift @@ -3,18 +3,14 @@ import Foundation public struct UnavailableMediaPickerTypesError: ScreenError { - public var description: String { - """ + public let description: String + + public init(for trigger: Any) { + description = """ Media types are not available for: \(trigger) """ } - - public let trigger: Any - - public init(for trigger: Any) { - self.trigger = trigger - } } extension Result where Failure == Error { diff --git a/Sources/Addons/MediaPicker/MediaPicker.swift b/Sources/Addons/MediaPicker/MediaPicker.swift index 31bb8d5f..c88ec9e4 100644 --- a/Sources/Addons/MediaPicker/MediaPicker.swift +++ b/Sources/Addons/MediaPicker/MediaPicker.swift @@ -32,9 +32,7 @@ public struct MediaPicker: CustomStringConvertible { /// called when the user has selected a still image or movie or has canceled the pick operation. public let didFinish: (_ result: MediaPickerResult?) -> Void - public var description: String { - "ImagePicker(from: \"\(source)\")" - } + public let description: String /// Creates a configuration for selecting media items. /// - Parameters: @@ -71,6 +69,8 @@ public struct MediaPicker: CustomStringConvertible { self.didInitialize = didInitialize self.didFinish = didFinish + + description = "ImagePicker(from: \"\(source)\")" } /// Creates a configuration for selecting media items. @@ -103,6 +103,8 @@ public struct MediaPicker: CustomStringConvertible { self.didInitialize = didInitialize self.didFinish = didFinish + + description = "ImagePicker(from: \"\(source)\")" } } #endif diff --git a/Sources/Addons/MediaPicker/MediaPickerCameraSettings.swift b/Sources/Addons/MediaPicker/MediaPickerCameraSettings.swift index 54f47499..995d017b 100644 --- a/Sources/Addons/MediaPicker/MediaPickerCameraSettings.swift +++ b/Sources/Addons/MediaPicker/MediaPickerCameraSettings.swift @@ -2,7 +2,7 @@ import UIKit /// The object that defines the settings for the camera. -public struct MediaPickerCameraSettings { +public struct MediaPickerCameraSettings: Sendable { /// Default settings public static let `default` = Self() diff --git a/Sources/Addons/MediaPicker/MediaPickerSource.swift b/Sources/Addons/MediaPicker/MediaPickerSource.swift index 75d8c2ef..ca436b52 100644 --- a/Sources/Addons/MediaPicker/MediaPickerSource.swift +++ b/Sources/Addons/MediaPicker/MediaPickerSource.swift @@ -5,6 +5,7 @@ import UIKit /// /// A given source may not be available on a given device because the source is not physically present /// or because it cannot currently be accessed. +@MainActor public enum MediaPickerSource: CustomStringConvertible { /// Specifies the device’s photo library as the source for the image picker controller. @@ -19,7 +20,7 @@ public enum MediaPickerSource: CustomStringConvertible { /// Specifies the device’s built-in camera with default settings as the source for the image picker controller. public static let camera = Self.camera(settings: .default) - public var description: String { + nonisolated public var description: String { switch self { case .photoLibrary: return "Photo library" diff --git a/Sources/Addons/Safari/InvalidSafariURLError.swift b/Sources/Addons/Safari/InvalidSafariURLError.swift index 5fc86740..f6ac074e 100644 --- a/Sources/Addons/Safari/InvalidSafariURLError.swift +++ b/Sources/Addons/Safari/InvalidSafariURLError.swift @@ -3,18 +3,14 @@ import Foundation public struct InvalidSafariURLError: ScreenError { - public var description: String { - """ + public let description: String + + public init(for trigger: Any) { + description = """ Safari does not support the url scheme of: \(trigger) """ } - - public let trigger: Any - - public init(for trigger: Any) { - self.trigger = trigger - } } extension Result where Failure == Error { diff --git a/Sources/Addons/Safari/SafariManager.swift b/Sources/Addons/Safari/SafariManager.swift index e5bfbab9..780eb971 100644 --- a/Sources/Addons/Safari/SafariManager.swift +++ b/Sources/Addons/Safari/SafariManager.swift @@ -2,6 +2,7 @@ import Foundation import SafariServices +@MainActor internal final class SafariManager: NSObject, SFSafariViewControllerDelegate { diff --git a/Sources/Addons/Sharing/Activity/SharingActivity.swift b/Sources/Addons/Sharing/Activity/SharingActivity.swift index 1785368f..61ef045d 100644 --- a/Sources/Addons/Sharing/Activity/SharingActivity.swift +++ b/Sources/Addons/Sharing/Activity/SharingActivity.swift @@ -3,7 +3,7 @@ import UIKit public struct SharingActivity { - private typealias Body = (_ navigator: ScreenNavigator) -> UIActivity + private typealias Body = @MainActor (_ navigator: ScreenNavigator) -> UIActivity private let body: Body @@ -11,6 +11,7 @@ public struct SharingActivity { self.body = body } + @MainActor internal func activity(navigator: ScreenNavigator) -> UIActivity { body(navigator) } diff --git a/Sources/Addons/Sharing/Activity/SharingActivityManager.swift b/Sources/Addons/Sharing/Activity/SharingActivityManager.swift index b139f159..1e0be1b9 100644 --- a/Sources/Addons/Sharing/Activity/SharingActivityManager.swift +++ b/Sources/Addons/Sharing/Activity/SharingActivityManager.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) && os(iOS) import UIKit +@MainActor internal final class SharingActivityManager: UIActivity { internal override class var activityCategory: UIActivity.Category { @@ -33,7 +34,9 @@ internal final class SharingActivityManager: UI self?.activityDidFinish(completed) } - return screen.build(navigator: navigator) + return MainActor.assumeIsolated { [navigator] in + screen.build(navigator: navigator) + } } internal init( diff --git a/Sources/Addons/Sharing/Activity/SharingCustomActivity.swift b/Sources/Addons/Sharing/Activity/SharingCustomActivity.swift index 65c11b1a..6a329a67 100644 --- a/Sources/Addons/Sharing/Activity/SharingCustomActivity.swift +++ b/Sources/Addons/Sharing/Activity/SharingCustomActivity.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) && os(iOS) import UIKit +@MainActor public protocol SharingCustomActivity { static var category: SharingActivityCategory { get } diff --git a/Sources/Addons/Sharing/Activity/SharingSilentActivity.swift b/Sources/Addons/Sharing/Activity/SharingSilentActivity.swift index 763fcf20..6025fe7c 100644 --- a/Sources/Addons/Sharing/Activity/SharingSilentActivity.swift +++ b/Sources/Addons/Sharing/Activity/SharingSilentActivity.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) && os(iOS) import UIKit +@MainActor public protocol SharingSilentActivity: SharingCustomActivity { func perform( diff --git a/Sources/Addons/StoreProduct/InvalidStoreProductIDError.swift b/Sources/Addons/StoreProduct/InvalidStoreProductIDError.swift index 8f0d1448..9a884fed 100644 --- a/Sources/Addons/StoreProduct/InvalidStoreProductIDError.swift +++ b/Sources/Addons/StoreProduct/InvalidStoreProductIDError.swift @@ -3,18 +3,14 @@ import Foundation public struct InvalidStoreProductIDError: ScreenError { - public var description: String { - """ + public let description: String + + public init(for trigger: Any) { + description = """ Invalid store product ID for: \(trigger) """ } - - public let trigger: Any - - public init(for trigger: Any) { - self.trigger = trigger - } } extension Result where Failure == Error { diff --git a/Sources/Addons/StoreProduct/StoreProduct.swift b/Sources/Addons/StoreProduct/StoreProduct.swift index b401ddae..f534674c 100644 --- a/Sources/Addons/StoreProduct/StoreProduct.swift +++ b/Sources/Addons/StoreProduct/StoreProduct.swift @@ -17,9 +17,7 @@ public struct StoreProduct: CustomStringConvertible { /// Called when the user dismisses the store screen. public let didFinish: (() -> Void)? - public var description: String { - "StoreProduct(\(parameters))" - } + public let description: String /// Creates a configuration. /// - Parameters: @@ -37,6 +35,7 @@ public struct StoreProduct: CustomStringConvertible { self.parameters = parameters self.didInitialize = didInitialize self.didFinish = didFinish + description = "StoreProduct(\(parameters))" } } #endif diff --git a/Sources/Addons/URL/Call/InvalidCallParametersError.swift b/Sources/Addons/URL/Call/InvalidCallParametersError.swift index ebda4172..64728cea 100644 --- a/Sources/Addons/URL/Call/InvalidCallParametersError.swift +++ b/Sources/Addons/URL/Call/InvalidCallParametersError.swift @@ -3,18 +3,14 @@ import Foundation public struct InvalidCallParametersError: ScreenError { - public var description: String { - """ + public let description: String + + public init(for trigger: Any) { + description = """ Invalid call parameters for: \(trigger) """ } - - public let trigger: Any - - public init(for trigger: Any) { - self.trigger = trigger - } } extension Result where Failure == Error { diff --git a/Sources/Addons/URL/FailedToOpenURLError.swift b/Sources/Addons/URL/FailedToOpenURLError.swift index 42b6093c..cca0b554 100644 --- a/Sources/Addons/URL/FailedToOpenURLError.swift +++ b/Sources/Addons/URL/FailedToOpenURLError.swift @@ -3,22 +3,16 @@ import Foundation public struct FailedToOpenURLError: ScreenError { - public var description: String { - """ - Failed to open URL ("\(url)") for: - \(trigger) - """ - } - - public let url: URL - public let trigger: Any + public let description: String public init( url: URL, for trigger: Any ) { - self.url = url - self.trigger = trigger + description = """ + Failed to open URL ("\(url)") for: + \(trigger) + """ } } diff --git a/Sources/Addons/URL/Mail/InvalidMailParametersError.swift b/Sources/Addons/URL/Mail/InvalidMailParametersError.swift index a7666200..756e124f 100644 --- a/Sources/Addons/URL/Mail/InvalidMailParametersError.swift +++ b/Sources/Addons/URL/Mail/InvalidMailParametersError.swift @@ -3,18 +3,14 @@ import Foundation public struct InvalidMailParametersError: ScreenError { - public var description: String { - """ + public let description: String + + public init(for trigger: Any) { + description = """ Invalid mail parameters for: \(trigger) """ } - - public let trigger: Any - - public init(for trigger: Any) { - self.trigger = trigger - } } extension Result where Failure == Error { diff --git a/Sources/Addons/URL/Settings/InvalidOpenSettingsURLError.swift b/Sources/Addons/URL/Settings/InvalidOpenSettingsURLError.swift index c72aa34f..7c6e4937 100644 --- a/Sources/Addons/URL/Settings/InvalidOpenSettingsURLError.swift +++ b/Sources/Addons/URL/Settings/InvalidOpenSettingsURLError.swift @@ -3,18 +3,14 @@ import Foundation public struct InvalidOpenSettingsURLError: ScreenError { - public var description: String { - """ + public let description: String + + public init(for trigger: Any) { + description = """ Invalid settings URL for: \(trigger) """ } - - public let trigger: Any - - public init(for trigger: Any) { - self.trigger = trigger - } } extension Result where Failure == Error { diff --git a/Sources/Addons/URL/StoreApp/InvalidStoreAppIDError.swift b/Sources/Addons/URL/StoreApp/InvalidStoreAppIDError.swift index f83354a9..677d3af5 100644 --- a/Sources/Addons/URL/StoreApp/InvalidStoreAppIDError.swift +++ b/Sources/Addons/URL/StoreApp/InvalidStoreAppIDError.swift @@ -3,18 +3,14 @@ import Foundation public struct InvalidStoreAppIDError: ScreenError { - public var description: String { - """ + public let description: String + + public init(for trigger: Any) { + description = """ Invalid store app ID for: \(trigger) """ } - - public let trigger: Any - - public init(for trigger: Any) { - self.trigger = trigger - } } extension Result where Failure == Error { diff --git a/Sources/Deeplink/AnyDeeplink.swift b/Sources/Deeplink/AnyDeeplink.swift index 4428251d..9bc178c5 100644 --- a/Sources/Deeplink/AnyDeeplink.swift +++ b/Sources/Deeplink/AnyDeeplink.swift @@ -3,6 +3,7 @@ import Foundation /// Erased type of ``Deeplink`` protocol. /// /// - SeeAlso: ``Deeplink`` +@MainActor public protocol AnyDeeplink { /// The default implementation casts `screens` to the ``Deeplink/Screens`` type diff --git a/Sources/Deeplink/Deeplink.swift b/Sources/Deeplink/Deeplink.swift index 1224d8a5..864fa8ad 100644 --- a/Sources/Deeplink/Deeplink.swift +++ b/Sources/Deeplink/Deeplink.swift @@ -23,6 +23,7 @@ public protocol Deeplink: AnyDeeplink { /// - screens: Screen Factory. /// - navigator: Navigator for performing navigation actions. /// - handler: Handler for processing a new ``Deeplink`` + @MainActor func navigate( screens: Screens, navigator: ScreenNavigator, @@ -70,6 +71,7 @@ extension Deeplink { extension Deeplink { + @MainActor public func navigateIfPossible( screens: Any?, navigator: ScreenNavigator, diff --git a/Sources/Deeplink/DeeplinkHandler.swift b/Sources/Deeplink/DeeplinkHandler.swift index 369c5069..b8e48820 100644 --- a/Sources/Deeplink/DeeplinkHandler.swift +++ b/Sources/Deeplink/DeeplinkHandler.swift @@ -13,6 +13,7 @@ import UserNotifications /// The handler converts the external source (URL, Push-Notification, Shortcut) /// into a suitable ``Deeplink`` to make the navigation. /// If no suitable ``Deeplink`` was found, the handler methods will return `false`. +@MainActor public protocol DeeplinkHandler { /// Returns a Boolean value that indicates whether ``URLDeeplink`` exists to handle the URL. diff --git a/Sources/Deeplink/DeeplinkManager.swift b/Sources/Deeplink/DeeplinkManager.swift index e6377356..88014feb 100644 --- a/Sources/Deeplink/DeeplinkManager.swift +++ b/Sources/Deeplink/DeeplinkManager.swift @@ -589,7 +589,9 @@ public final class DeeplinkManager: DeeplinkHandler { object: nil, queue: nil ) { [weak self] _ in - self?.navigateIfPossible() + Task { @MainActor in + self?.navigateIfPossible() + } } } diff --git a/Sources/Deeplink/DeeplinkScope.swift b/Sources/Deeplink/DeeplinkScope.swift index b3b29fbc..d7ab9540 100644 --- a/Sources/Deeplink/DeeplinkScope.swift +++ b/Sources/Deeplink/DeeplinkScope.swift @@ -4,7 +4,7 @@ import Foundation /// /// The scope allows you to split deep links by activating and deactivating each scope independently. /// See ``DeeplinkManager`` for details. -public struct DeeplinkScope: Hashable, ExpressibleByStringLiteral { +public struct DeeplinkScope: Hashable, ExpressibleByStringLiteral, Sendable { /// A unique key for identifying a scope. public let key: String? diff --git a/Sources/Deeplink/Errors/DeeplinkDecodingError.swift b/Sources/Deeplink/Errors/DeeplinkDecodingError.swift index 125dec14..bc28b93c 100644 --- a/Sources/Deeplink/Errors/DeeplinkDecodingError.swift +++ b/Sources/Deeplink/Errors/DeeplinkDecodingError.swift @@ -2,16 +2,7 @@ import Foundation internal struct DeeplinkDecodingError: DeeplinkError { - internal var description: String { - """ - Failed to decode data for \(trigger) with error: - \(underlyingError) - """ - } - - internal let underlyingError: Error - - internal let trigger: Any + internal let description: String internal var isWarning: Bool { true @@ -21,7 +12,9 @@ internal struct DeeplinkDecodingError: DeeplinkError { underlyingError: Error, trigger: Any ) { - self.underlyingError = underlyingError - self.trigger = trigger + description = """ + Failed to decode data for \(trigger) with error: + \(underlyingError) + """ } } diff --git a/Sources/Deeplink/Errors/DeeplinkInvalidContextError.swift b/Sources/Deeplink/Errors/DeeplinkInvalidContextError.swift index 67f69b53..47d7a542 100644 --- a/Sources/Deeplink/Errors/DeeplinkInvalidContextError.swift +++ b/Sources/Deeplink/Errors/DeeplinkInvalidContextError.swift @@ -3,21 +3,7 @@ import Foundation /// The `Context` instance is not supported by the deeplink type. public struct DeeplinkInvalidContextError: DeeplinkError { - public var description: String { - """ - The type of the context \(context ?? "nil") does not match the expected type \(type) for: - \(trigger) - """ - } - - /// Context instance. - public let context: Any? - - /// Expected context type. - public let type: Any.Type - - /// The deeplink that caused the error. - public let trigger: Any + public let description: String /// Creates an error. /// @@ -30,8 +16,9 @@ public struct DeeplinkInvalidContextError: DeeplinkError { type: Any.Type, for trigger: Any ) { - self.context = context - self.type = type - self.trigger = trigger + description = """ + The type of the context \(context ?? "nil") does not match the expected type \(type) for: + \(trigger) + """ } } diff --git a/Sources/Deeplink/Errors/DeeplinkInvalidScreensError.swift b/Sources/Deeplink/Errors/DeeplinkInvalidScreensError.swift index 71a1e2dc..33c9c976 100644 --- a/Sources/Deeplink/Errors/DeeplinkInvalidScreensError.swift +++ b/Sources/Deeplink/Errors/DeeplinkInvalidScreensError.swift @@ -3,21 +3,7 @@ import Foundation /// The `Screens` instance is not supported by the deeplink type. public struct DeeplinkInvalidScreensError: DeeplinkError { - public var description: String { - """ - The type of the screens \(screens ?? "nil") does not match the expected type \(type) for: - \(trigger) - """ - } - - /// Screens instance. - public let screens: Any? - - /// Expected screens type. - public let type: Any.Type - - /// The deeplink that caused the error. - public let trigger: Any + public let description: String /// Creates an error. /// @@ -30,8 +16,9 @@ public struct DeeplinkInvalidScreensError: DeeplinkError { type: Any.Type, for trigger: Any ) { - self.screens = screens - self.type = type - self.trigger = trigger + description = """ + The type of the screens \(screens ?? "nil") does not match the expected type \(type) for: + \(trigger) + """ } } diff --git a/Sources/Deeplink/Notification/Errors/NotificationDeeplinkInvalidUserInfoError.swift b/Sources/Deeplink/Notification/Errors/NotificationDeeplinkInvalidUserInfoError.swift index 7e615886..0b370f11 100644 --- a/Sources/Deeplink/Notification/Errors/NotificationDeeplinkInvalidUserInfoError.swift +++ b/Sources/Deeplink/Notification/Errors/NotificationDeeplinkInvalidUserInfoError.swift @@ -5,18 +5,7 @@ import UserNotifications /// Failed to extract userInfo from response to the notification. public struct NotificationDeeplinkInvalidUserInfoError: DeeplinkError { - public var description: String { - """ - Failed to extract userInfo from response to the notification for: - \(trigger) - """ - } - - /// Response to the notification that caused the error. - public let response: UNNotificationResponse - - /// The deeplink that caused the error. - public let trigger: Any + public let description: String /// Creates an error. /// @@ -27,8 +16,10 @@ public struct NotificationDeeplinkInvalidUserInfoError: DeeplinkError { response: UNNotificationResponse, for trigger: Any ) { - self.response = response - self.trigger = trigger + description = """ + Failed to extract userInfo from response to the notification for: + \(trigger) + """ } } #endif diff --git a/Sources/Deeplink/URL/Errors/URLDeeplinkInvalidComponentsError.swift b/Sources/Deeplink/URL/Errors/URLDeeplinkInvalidComponentsError.swift index e2edc878..d57509d5 100644 --- a/Sources/Deeplink/URL/Errors/URLDeeplinkInvalidComponentsError.swift +++ b/Sources/Deeplink/URL/Errors/URLDeeplinkInvalidComponentsError.swift @@ -3,18 +3,7 @@ import Foundation /// Failed to extract components from deeplink URL. public struct URLDeeplinkInvalidComponentsError: DeeplinkError { - public var description: String { - """ - Failed to extract components from URL "\(url)" for: - \(trigger) - """ - } - - /// A URL that caused the error. - public let url: URL - - /// The deeplink that caused the error. - public let trigger: Any + public let description: String /// Creates an error. /// @@ -25,7 +14,9 @@ public struct URLDeeplinkInvalidComponentsError: DeeplinkError { url: URL, for trigger: Any ) { - self.url = url - self.trigger = trigger + description = """ + Failed to extract components from URL "\(url)" for: + \(trigger) + """ } } diff --git a/Sources/Screen/Actions/Any/AnyScreenAction.swift b/Sources/Screen/Actions/Any/AnyScreenAction.swift index b188c431..5dd2f57d 100755 --- a/Sources/Screen/Actions/Any/AnyScreenAction.swift +++ b/Sources/Screen/Actions/Any/AnyScreenAction.swift @@ -22,10 +22,7 @@ public struct AnyScreenAction: private let box: AnyScreenActionBaseBox - public var description: String { - box.description - } - + public let description: String /// Creates a type-erasing action to wrap the provided action. /// /// - Parameter wrapped: An action to wrap with a type-eraser. @@ -33,6 +30,7 @@ public struct AnyScreenAction: _ wrapped: Wrapped ) where Wrapped.Container == Container, Wrapped.Output == Output { box = AnyScreenActionBox(wrapped) { $0 } + description = box.description } public func cast(to type: Action.Type) -> Action? { @@ -66,6 +64,7 @@ extension AnyScreenAction where Output == Void { box = AnyScreenActionBox(wrapped) { result in result.ignoringValue() } + description = box.description } } diff --git a/Sources/Screen/Actions/Any/AnyScreenActionBaseBox.swift b/Sources/Screen/Actions/Any/AnyScreenActionBaseBox.swift index 305ec47f..e935ec85 100755 --- a/Sources/Screen/Actions/Any/AnyScreenActionBaseBox.swift +++ b/Sources/Screen/Actions/Any/AnyScreenActionBaseBox.swift @@ -6,7 +6,7 @@ internal class AnyScreenActionBaseBox: internal typealias Output = Output - internal var description: String { + nonisolated internal var description: String { fatalError("\(#function) has not been implemented") } diff --git a/Sources/Screen/Actions/Any/AnyScreenActionBox.swift b/Sources/Screen/Actions/Any/AnyScreenActionBox.swift index 399156ea..387f488d 100755 --- a/Sources/Screen/Actions/Any/AnyScreenActionBox.swift +++ b/Sources/Screen/Actions/Any/AnyScreenActionBox.swift @@ -10,13 +10,15 @@ internal final class AnyScreenActionBox< private let wrapped: Wrapped private let mapper: Mapper + private let _description: String internal override var description: String { - "\(wrapped)" + _description } internal init(_ wrapped: Wrapped, mapper: @escaping Mapper) { self.wrapped = wrapped self.mapper = mapper + _description = "\(wrapped)" } internal override func cast(to type: Action.Type) -> Action? { diff --git a/Sources/Screen/Actions/Generic/Find/ScreenPredicate.swift b/Sources/Screen/Actions/Generic/Find/ScreenPredicate.swift index 18ce5af4..23a290cd 100644 --- a/Sources/Screen/Actions/Generic/Find/ScreenPredicate.swift +++ b/Sources/Screen/Actions/Generic/Find/ScreenPredicate.swift @@ -4,6 +4,7 @@ import UIKit import Foundation #endif +@MainActor public struct ScreenPredicate: CustomStringConvertible { public let description: String diff --git a/Sources/Screen/Actions/Generic/Refresh/ScreenRefreshableContainer.swift b/Sources/Screen/Actions/Generic/Refresh/ScreenRefreshableContainer.swift index 7597a501..0af12bd1 100644 --- a/Sources/Screen/Actions/Generic/Refresh/ScreenRefreshableContainer.swift +++ b/Sources/Screen/Actions/Generic/Refresh/ScreenRefreshableContainer.swift @@ -1,5 +1,7 @@ import Foundation +@MainActor public protocol ScreenRefreshableContainer: ScreenContainer { + func refresh(completion: @escaping () -> Void) } diff --git a/Sources/Screen/Actions/Generic/Try/ScreenTryResolution.swift b/Sources/Screen/Actions/Generic/Try/ScreenTryResolution.swift index 0445ab79..b99f049b 100644 --- a/Sources/Screen/Actions/Generic/Try/ScreenTryResolution.swift +++ b/Sources/Screen/Actions/Generic/Try/ScreenTryResolution.swift @@ -1,5 +1,6 @@ import Foundation +@MainActor public struct ScreenTryResolution { public typealias DoneAction = (_ value: Output) -> AnyScreenAction diff --git a/Sources/Screen/Actions/ScreenAction.swift b/Sources/Screen/Actions/ScreenAction.swift index 7769c65c..082a269a 100755 --- a/Sources/Screen/Actions/ScreenAction.swift +++ b/Sources/Screen/Actions/ScreenAction.swift @@ -17,6 +17,7 @@ import Foundation /// For example, show a screen for authorization, /// as a result of which `completion` is called with success if authorization was completed, /// or with an error (for example `ScreenCanceledError`) if the user canceled authorization. +@MainActor public protocol ScreenAction { /// A type of container that the action uses for navigation. diff --git a/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackAnimation.swift b/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackAnimation.swift index 050579ab..f9301d6d 100644 --- a/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackAnimation.swift +++ b/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackAnimation.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor public enum ScreenStackAnimation { case `default` @@ -43,7 +44,7 @@ public enum ScreenStackAnimation { extension ScreenStackAnimation: Equatable { - public static func == (lhs: Self, rhs: Self) -> Bool { + nonisolated public static func == (lhs: Self, rhs: Self) -> Bool { switch (lhs, rhs) { case (.default, .default): return true diff --git a/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackCustomAnimation.swift b/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackCustomAnimation.swift index 134b911e..8582a13b 100644 --- a/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackCustomAnimation.swift +++ b/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackCustomAnimation.swift @@ -2,8 +2,10 @@ import UIKit public protocol ScreenStackCustomAnimation { + func isEqual(to other: ScreenStackCustomAnimation) -> Bool + @MainActor func animate( container: UINavigationController, stack: [UIViewController], diff --git a/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackTransitionAnimation.swift b/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackTransitionAnimation.swift index b57d1702..afa4d5b8 100644 --- a/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackTransitionAnimation.swift +++ b/Sources/Screen/Actions/Stack/SetStack/Animations/ScreenStackTransitionAnimation.swift @@ -1,7 +1,7 @@ #if canImport(UIKit) import UIKit -public struct ScreenStackTransitionAnimation: ScreenStackCustomAnimation, Equatable { +public struct ScreenStackTransitionAnimation: ScreenStackCustomAnimation, Equatable, Sendable { public let duration: TimeInterval public let options: UIView.AnimationOptions diff --git a/Sources/Screen/Actions/Stack/SetStack/Modifiers/Pop/ScreenStackPopModifier.swift b/Sources/Screen/Actions/Stack/SetStack/Modifiers/Pop/ScreenStackPopModifier.swift index 598fe757..bcfbe3f6 100755 --- a/Sources/Screen/Actions/Stack/SetStack/Modifiers/Pop/ScreenStackPopModifier.swift +++ b/Sources/Screen/Actions/Stack/SetStack/Modifiers/Pop/ScreenStackPopModifier.swift @@ -5,12 +5,11 @@ public struct ScreenStackPopModifier: ScreenStackModifier { public let predicate: ScreenStackPopPredicate - public var description: String { - "Pop \(predicate)" - } + public let description: String public init(predicate: ScreenStackPopPredicate) { self.predicate = predicate + description = "Pop \(predicate)" } public func perform( diff --git a/Sources/Screen/Actions/Stack/SetStack/Modifiers/Pop/ScreenStackPopPredicate.swift b/Sources/Screen/Actions/Stack/SetStack/Modifiers/Pop/ScreenStackPopPredicate.swift index 73a3534a..76d5c739 100644 --- a/Sources/Screen/Actions/Stack/SetStack/Modifiers/Pop/ScreenStackPopPredicate.swift +++ b/Sources/Screen/Actions/Stack/SetStack/Modifiers/Pop/ScreenStackPopPredicate.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor public struct ScreenStackPopPredicate: CustomStringConvertible { public let description: String diff --git a/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackClearModifier.swift b/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackClearModifier.swift index 74048bec..1fa445e0 100755 --- a/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackClearModifier.swift +++ b/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackClearModifier.swift @@ -3,11 +3,11 @@ import UIKit public struct ScreenStackClearModifier: ScreenStackModifier { - public var description: String { - "Clear" - } + public let description: String - public init() { } + public init() { + description = "Clear" + } public func perform( stack: [UIViewController], diff --git a/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackModifier.swift b/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackModifier.swift index c8fea0c6..73bdc16c 100755 --- a/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackModifier.swift +++ b/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackModifier.swift @@ -1,7 +1,9 @@ #if canImport(UIKit) import UIKit +@MainActor public protocol ScreenStackModifier: CustomStringConvertible { + func perform( stack: [UIViewController], navigator: ScreenNavigator diff --git a/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackPushModifier.swift b/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackPushModifier.swift index f95aae8e..8b5ee693 100755 --- a/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackPushModifier.swift +++ b/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackPushModifier.swift @@ -7,12 +7,11 @@ public struct ScreenStackPushModifier< public let screen: New - public var description: String { - "Push \(screen)" - } + public let description: String public init(screen: New) { self.screen = screen + description = "Push \(screen)" } public func perform( diff --git a/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackReplaceModifier.swift b/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackReplaceModifier.swift index cee654ea..d3f70f75 100755 --- a/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackReplaceModifier.swift +++ b/Sources/Screen/Actions/Stack/SetStack/Modifiers/ScreenStackReplaceModifier.swift @@ -7,12 +7,11 @@ public struct ScreenStackReplaceModifier< public let screen: New - public var description: String { - "Replace with \(screen)" - } + public let description: String public init(screen: New) { self.screen = screen + description = "Replace with \(screen)" } public func perform( diff --git a/Sources/Screen/Actions/Tabs/SelectTab/Animations/ScreenTabAnimation.swift b/Sources/Screen/Actions/Tabs/SelectTab/Animations/ScreenTabAnimation.swift index 114408c0..ca18633f 100644 --- a/Sources/Screen/Actions/Tabs/SelectTab/Animations/ScreenTabAnimation.swift +++ b/Sources/Screen/Actions/Tabs/SelectTab/Animations/ScreenTabAnimation.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor public enum ScreenTabAnimation { case custom(ScreenTabCustomAnimation) diff --git a/Sources/Screen/Actions/Tabs/SelectTab/Animations/ScreenTabCustomAnimation.swift b/Sources/Screen/Actions/Tabs/SelectTab/Animations/ScreenTabCustomAnimation.swift index f763e97d..b3132dad 100644 --- a/Sources/Screen/Actions/Tabs/SelectTab/Animations/ScreenTabCustomAnimation.swift +++ b/Sources/Screen/Actions/Tabs/SelectTab/Animations/ScreenTabCustomAnimation.swift @@ -1,7 +1,9 @@ #if canImport(UIKit) import UIKit +@MainActor public protocol ScreenTabCustomAnimation { + func animate( container: UITabBarController, from selectedTab: UIViewController, diff --git a/Sources/Screen/Actions/Tabs/SelectTab/ScreenTabPredicate.swift b/Sources/Screen/Actions/Tabs/SelectTab/ScreenTabPredicate.swift index e5471ebf..a3d8c6b0 100644 --- a/Sources/Screen/Actions/Tabs/SelectTab/ScreenTabPredicate.swift +++ b/Sources/Screen/Actions/Tabs/SelectTab/ScreenTabPredicate.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor public struct ScreenTabPredicate: CustomStringConvertible { public let description: String diff --git a/Sources/Screen/Actions/Window/SetRoot/Animations/ScreenRootAnimation.swift b/Sources/Screen/Actions/Window/SetRoot/Animations/ScreenRootAnimation.swift index eaeabbbd..53eb40e7 100644 --- a/Sources/Screen/Actions/Window/SetRoot/Animations/ScreenRootAnimation.swift +++ b/Sources/Screen/Actions/Window/SetRoot/Animations/ScreenRootAnimation.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor public enum ScreenRootAnimation { case custom(ScreenRootCustomAnimation) diff --git a/Sources/Screen/Actions/Window/SetRoot/Animations/ScreenRootCustomAnimation.swift b/Sources/Screen/Actions/Window/SetRoot/Animations/ScreenRootCustomAnimation.swift index e5ac4a95..4e44fe54 100644 --- a/Sources/Screen/Actions/Window/SetRoot/Animations/ScreenRootCustomAnimation.swift +++ b/Sources/Screen/Actions/Window/SetRoot/Animations/ScreenRootCustomAnimation.swift @@ -1,6 +1,7 @@ #if canImport(UIKit) import UIKit +@MainActor public protocol ScreenRootCustomAnimation { func animate( diff --git a/Sources/Screen/Any/Aliases/AnyModalScreen.swift b/Sources/Screen/Any/Aliases/AnyModalScreen.swift index ddc3842e..19bcb515 100755 --- a/Sources/Screen/Any/Aliases/AnyModalScreen.swift +++ b/Sources/Screen/Any/Aliases/AnyModalScreen.swift @@ -11,6 +11,7 @@ extension AnyModalScreen { /// Creates a type-erasing screen to wrap the provided screen. /// /// - Parameter wrapped: A screen to wrap with a type-eraser. + @MainActor public init( _ wrapped: Wrapped ) where Wrapped.Container: UIViewController { @@ -33,6 +34,7 @@ extension Screen where Container: UIViewController { /// /// - SeeAlso: `AnyModalScreen` /// - SeeAlso: `AnyScreen` + @MainActor public func eraseToAnyModalScreen() -> AnyModalScreen { AnyModalScreen(self) } diff --git a/Sources/Screen/Any/Aliases/AnyStackScreen.swift b/Sources/Screen/Any/Aliases/AnyStackScreen.swift index db664d13..ad86d57e 100755 --- a/Sources/Screen/Any/Aliases/AnyStackScreen.swift +++ b/Sources/Screen/Any/Aliases/AnyStackScreen.swift @@ -11,6 +11,7 @@ extension AnyStackScreen { /// Creates a type-erasing screen to wrap the provided screen. /// /// - Parameter wrapped: A screen to wrap with a type-eraser. + @MainActor public init( _ wrapped: Wrapped ) where Wrapped.Container: UINavigationController { @@ -33,6 +34,7 @@ extension Screen where Container: UINavigationController { /// /// - SeeAlso: `AnyStackScreen` /// - SeeAlso: `AnyScreen` + @MainActor public func eraseToAnyStackScreen() -> AnyStackScreen { AnyStackScreen(self) } diff --git a/Sources/Screen/Any/Aliases/AnyTabsScreen.swift b/Sources/Screen/Any/Aliases/AnyTabsScreen.swift index eccd0097..97604e24 100755 --- a/Sources/Screen/Any/Aliases/AnyTabsScreen.swift +++ b/Sources/Screen/Any/Aliases/AnyTabsScreen.swift @@ -11,6 +11,7 @@ extension AnyTabsScreen { /// Creates a type-erasing screen to wrap the provided screen. /// /// - Parameter wrapped: A screen to wrap with a type-eraser. + @MainActor public init( _ wrapped: Wrapped ) where Wrapped.Container: UITabBarController { @@ -33,6 +34,7 @@ extension Screen where Container: UITabBarController { /// /// - SeeAlso: `AnyTabsScreen` /// - SeeAlso: `AnyScreen` + @MainActor public func eraseToAnyTabsScreen() -> AnyTabsScreen { AnyTabsScreen(self) } diff --git a/Sources/Screen/Any/AnyScreen.swift b/Sources/Screen/Any/AnyScreen.swift index eba21672..c1c0001f 100755 --- a/Sources/Screen/Any/AnyScreen.swift +++ b/Sources/Screen/Any/AnyScreen.swift @@ -40,9 +40,7 @@ public struct AnyScreen: Screen { box.traits } - public var description: String { - box.description - } + public let description: String internal init( _ wrapped: Wrapped, @@ -52,11 +50,13 @@ public struct AnyScreen: Screen { ) -> Container ) { self.box = AnyScreenBox(wrapped, builder: builder) + description = box.description } /// Creates a type-erasing screen to wrap the provided screen. /// /// - Parameter wrapped: A screen to wrap with a type-eraser. + @MainActor public init( _ wrapped: Wrapped ) where Wrapped.Container == Container { @@ -82,6 +82,7 @@ extension Screen { /// - Returns: An `AnyScreen` wrapping this screen. /// /// - SeeAlso: `AnyScreen` + @MainActor public func eraseToAnyScreen() -> AnyScreen { AnyScreen(self) } diff --git a/Sources/Screen/Any/AnyScreenBaseBox.swift b/Sources/Screen/Any/AnyScreenBaseBox.swift index c6da2d88..9fca6647 100755 --- a/Sources/Screen/Any/AnyScreenBaseBox.swift +++ b/Sources/Screen/Any/AnyScreenBaseBox.swift @@ -10,7 +10,7 @@ internal class AnyScreenBaseBox: Screen { fatalError("\(#function) has not been implemented") } - internal var description: String { + nonisolated internal var description: String { fatalError("\(#function) has not been implemented") } diff --git a/Sources/Screen/Any/AnyScreenBox.swift b/Sources/Screen/Any/AnyScreenBox.swift index cf965a38..388f2792 100755 --- a/Sources/Screen/Any/AnyScreenBox.swift +++ b/Sources/Screen/Any/AnyScreenBox.swift @@ -21,13 +21,15 @@ internal final class AnyScreenBox< wrapped.traits } + private let _description: String internal override var description: String { - wrapped.description + _description } internal init(_ wrapped: Wrapped, builder: @escaping Builder) { self.wrapped = wrapped self.builder = builder + _description = wrapped.description } internal override func build(navigator: ScreenNavigator) -> Container { diff --git a/Sources/Screen/Container/ScreenIterableContainer.swift b/Sources/Screen/Container/ScreenIterableContainer.swift index 5316088d..709b0c17 100644 --- a/Sources/Screen/Container/ScreenIterableContainer.swift +++ b/Sources/Screen/Container/ScreenIterableContainer.swift @@ -10,6 +10,7 @@ import UIKit /// This protocol is used to find the specific container in nested containers. /// /// - SeeAlso: `ScreenContainer` +@MainActor public protocol ScreenIterableContainer: ScreenContainer { /// Returns the nested containers of a container. diff --git a/Sources/Screen/Container/ScreenKeyedContainer.swift b/Sources/Screen/Container/ScreenKeyedContainer.swift index c43d487e..bac2c723 100644 --- a/Sources/Screen/Container/ScreenKeyedContainer.swift +++ b/Sources/Screen/Container/ScreenKeyedContainer.swift @@ -48,6 +48,7 @@ import Foundation /// - SeeAlso: `Screen` /// - SeeAlso: `ScreenKey` /// - SeeAlso: `ScreenContainer` +@MainActor public protocol ScreenKeyedContainer: ScreenContainer { /// Screen key that is used to find the container in the container hierarchy. diff --git a/Sources/Screen/Container/ScreenVisibleContainer.swift b/Sources/Screen/Container/ScreenVisibleContainer.swift index 9cfcd938..63b33215 100644 --- a/Sources/Screen/Container/ScreenVisibleContainer.swift +++ b/Sources/Screen/Container/ScreenVisibleContainer.swift @@ -10,6 +10,7 @@ import UIKit /// The `UIWindow` and `UIViewController` classes and all their subclasses already implement this protocol /// /// - SeeAlso: `ScreenContainer` +@MainActor public protocol ScreenVisibleContainer: ScreenContainer { /// A Boolean value indicating whether the container is visible. diff --git a/Sources/Screen/Decorators/Modal/ModalStyle/ScreenModalStyleDecorator.swift b/Sources/Screen/Decorators/Modal/ModalStyle/ScreenModalStyleDecorator.swift index b4a47ac1..97242c4b 100644 --- a/Sources/Screen/Decorators/Modal/ModalStyle/ScreenModalStyleDecorator.swift +++ b/Sources/Screen/Decorators/Modal/ModalStyle/ScreenModalStyleDecorator.swift @@ -18,12 +18,11 @@ public struct ScreenModalStyleDecorator: ScreenDeco } } - public var description: String { - "ModalStyleDecorator" - } + public let description: String public init(style: ScreenModalStyle) { self.style = style + description = "ModalStyleDecorator" } public func build( @@ -57,6 +56,7 @@ extension Screen where Container: UIViewController { /// /// - Parameter style: Type of modal presentation style. /// - Returns: New `Screen`, which will be animated with the selected style when presented. + @MainActor public func withModalStyle(_ style: ScreenModalStyle) -> AnyScreen { decorated(by: ScreenModalStyleDecorator(style: style)) } @@ -66,6 +66,7 @@ extension Screen where Container: UIViewController { /// - Returns: New `Screen` with the `modalPresentationStyle` property set. /// /// - SeeAlso: `UIModalPresentationStyle` + @MainActor public func withModalPresentationStyle(_ style: UIModalPresentationStyle) -> AnyScreen { withModalStyle(.default(presentation: style)) } @@ -75,6 +76,7 @@ extension Screen where Container: UIViewController { /// - Returns: New `Screen` with the `modalTransitionStyle` property set. /// /// - SeeAlso: `UIModalTransitionStyle` + @MainActor public func withModalTransitionStyle(_ style: UIModalTransitionStyle) -> AnyScreen { withModalStyle(.default(transition: style)) } @@ -101,6 +103,7 @@ extension Screen where Container: UIViewController { /// The lifecycle of the implementation class will correspond to the lifecycle of the screen container. /// /// - Returns: New `Screen` with the `transitioningDelegate` property set. + @MainActor public func withModalTransitioningDelegate( _ delegate: UIViewControllerTransitioningDelegate ) -> AnyScreen { diff --git a/Sources/Screen/Decorators/Modal/Popover/ScreenPopoverPresentationAnchor.swift b/Sources/Screen/Decorators/Modal/Popover/ScreenPopoverPresentationAnchor.swift index 83a01946..25640b75 100644 --- a/Sources/Screen/Decorators/Modal/Popover/ScreenPopoverPresentationAnchor.swift +++ b/Sources/Screen/Decorators/Modal/Popover/ScreenPopoverPresentationAnchor.swift @@ -4,6 +4,7 @@ import UIKit /// Anchor to configure the `UIPopoverPresentationController` for the `UIViewController`. /// /// - SeeAlso: `popoverPresentationController` +@MainActor public struct ScreenPopoverPresentationAnchor { public let rect: CGRect? diff --git a/Sources/Screen/Decorators/Modal/Popover/ScreenPopoverPresentationDecorator.swift b/Sources/Screen/Decorators/Modal/Popover/ScreenPopoverPresentationDecorator.swift index 35e181c6..e2cc8891 100644 --- a/Sources/Screen/Decorators/Modal/Popover/ScreenPopoverPresentationDecorator.swift +++ b/Sources/Screen/Decorators/Modal/Popover/ScreenPopoverPresentationDecorator.swift @@ -13,12 +13,11 @@ public struct ScreenPopoverPresentationDecorator: S nil } - public var description: String { - "PopoverPresentationDecorator" - } + public let description: String public init(anchor: ScreenPopoverPresentationAnchor) { self.anchor = anchor + description = "PopoverPresentationDecorator" } public func build( @@ -56,6 +55,7 @@ extension Screen where Container: UIViewController { /// /// - Parameter anchor: Anchor for `popoverPresentationController`. /// - Returns: New `Screen` with configured `UIPopoverPresentationController`. + @MainActor public func withPopoverPresentation(anchor: ScreenPopoverPresentationAnchor) -> AnyScreen { decorated(by: ScreenPopoverPresentationDecorator(anchor: anchor)) } diff --git a/Sources/Screen/Decorators/Modal/ScreenLeftBarButtonDecorator.swift b/Sources/Screen/Decorators/Modal/ScreenLeftBarButtonDecorator.swift index a86ac5e3..a5dba318 100644 --- a/Sources/Screen/Decorators/Modal/ScreenLeftBarButtonDecorator.swift +++ b/Sources/Screen/Decorators/Modal/ScreenLeftBarButtonDecorator.swift @@ -10,12 +10,11 @@ public struct ScreenLeftBarButtonDecorator: ScreenD nil } - public var description: String { - "LeftBarButtonDecorator" - } + public let description: String public init(item: UIBarButtonItem) { self.item = item + description = "LeftBarButtonDecorator" } public func build( @@ -38,6 +37,7 @@ extension Screen where Container: UIViewController { /// /// - SeeAlso: `UINavigationItem` /// - SeeAlso: `UIBarButtonItem` + @MainActor public func withLeftBarButton(_ item: UIBarButtonItem) -> AnyScreen { decorated(by: ScreenLeftBarButtonDecorator(item: item)) } diff --git a/Sources/Screen/Decorators/Modal/ScreenRightBarButtonDecorator.swift b/Sources/Screen/Decorators/Modal/ScreenRightBarButtonDecorator.swift index f43a9900..8966095f 100644 --- a/Sources/Screen/Decorators/Modal/ScreenRightBarButtonDecorator.swift +++ b/Sources/Screen/Decorators/Modal/ScreenRightBarButtonDecorator.swift @@ -10,12 +10,11 @@ public struct ScreenRightBarButtonDecorator: Screen nil } - public var description: String { - "RightBarButtonDecorator" - } + public let description: String public init(item: UIBarButtonItem) { self.item = item + description = "RightBarButtonDecorator" } public func build( @@ -38,6 +37,7 @@ extension Screen where Container: UIViewController { /// /// - SeeAlso: `UINavigationItem` /// - SeeAlso: `UIBarButtonItem` + @MainActor public func withRightBarButton(_ item: UIBarButtonItem) -> AnyScreen { decorated(by: ScreenRightBarButtonDecorator(item: item)) } diff --git a/Sources/Screen/Decorators/Modal/ScreenStackContainerDecorator.swift b/Sources/Screen/Decorators/Modal/ScreenStackContainerDecorator.swift index 23b563fa..7c90dfe7 100644 --- a/Sources/Screen/Decorators/Modal/ScreenStackContainerDecorator.swift +++ b/Sources/Screen/Decorators/Modal/ScreenStackContainerDecorator.swift @@ -11,11 +11,11 @@ public struct ScreenStackContainerDecorator< nil } - public var description: String { - "StackContainerDecorator" - } + public let description: String - public init() { } + public init() { + description = "StackContainerDecorator" + } public func build( screen: Wrapped, @@ -30,6 +30,7 @@ extension Screen where Container: UIViewController { /// Wraps the screen container in a navigation controller with the specified class type. /// - Parameter type: `UINavigationController` class type. /// - Returns: New `Screen` with new container of class type `UINavigationController`. + @MainActor public func withStackContainer( of type: Output.Type ) -> AnyScreen { @@ -38,6 +39,7 @@ extension Screen where Container: UIViewController { /// Wraps the screen container in a navigation controller. /// - Returns: New `Screen` with new container of class `UINavigationController`. + @MainActor public func withStackContainer() -> AnyStackScreen { withStackContainer(of: UINavigationController.self) } diff --git a/Sources/Screen/Decorators/Modal/ScreenTabBarItemDecorator.swift b/Sources/Screen/Decorators/Modal/ScreenTabBarItemDecorator.swift index d69f13c6..31841da2 100644 --- a/Sources/Screen/Decorators/Modal/ScreenTabBarItemDecorator.swift +++ b/Sources/Screen/Decorators/Modal/ScreenTabBarItemDecorator.swift @@ -10,12 +10,11 @@ public struct ScreenTabBarItemDecorator: ScreenDeco nil } - public var description: String { - "TabBarItemDecorator" - } + public let description: String public init(item: UITabBarItem) { self.item = item + description = "TabBarItemDecorator" } public func build( @@ -35,6 +34,7 @@ extension Screen where Container: UIViewController { /// Sets the `tabBarItem` property for a container with type `UIViewController`. /// - Parameter item: `item` to set. /// - Returns: New `Screen` with `UITabBarItem` set to `tabBarItem`. + @MainActor public func withTabBarItem(_ item: UITabBarItem) -> AnyScreen { decorated(by: ScreenTabBarItemDecorator(item: item)) } diff --git a/Sources/Screen/Decorators/ScreenDecorator.swift b/Sources/Screen/Decorators/ScreenDecorator.swift index d769b7f2..fce6255b 100755 --- a/Sources/Screen/Decorators/ScreenDecorator.swift +++ b/Sources/Screen/Decorators/ScreenDecorator.swift @@ -20,6 +20,7 @@ import Foundation /// ``` /// /// - SeeAlso: `Screen` +@MainActor public protocol ScreenDecorator: CustomStringConvertible { /// The type of screen container to be decorated. @@ -57,6 +58,7 @@ extension Screen { /// Decorating the screen with the decorator. /// - Parameter decorator: A decorator instance that implements `ScreenDecorator`. /// - Returns: New `Screen` with the container type specified in the `Output` of decorator. + @MainActor public func decorated( by decorator: Decorator ) -> AnyScreen where Container == Decorator.Container { diff --git a/Sources/Screen/Decorators/Stack/ScreenStackDecorator.swift b/Sources/Screen/Decorators/Stack/ScreenStackDecorator.swift index 74909fe2..2396dc72 100644 --- a/Sources/Screen/Decorators/Stack/ScreenStackDecorator.swift +++ b/Sources/Screen/Decorators/Stack/ScreenStackDecorator.swift @@ -11,12 +11,11 @@ public struct ScreenStackDecorator: ScreenDec nil } - public var description: String { - "StackDecorator" - } + public let description: String public init(stack: [AnyModalScreen]) { self.stack = stack + description = "StackDecorator" } public func build( @@ -42,6 +41,7 @@ extension Screen where Container: UINavigationController { /// the new bottom-to-top order of the controllers in the navigation stack. /// Thus, the last item added to the array becomes the top item of the navigation stack. /// - Returns: New `Screen` with replaced `viewControllers` in container. + @MainActor public func withStack(_ stack: [AnyModalScreen]) -> AnyScreen { decorated(by: ScreenStackDecorator(stack: stack)) } @@ -53,6 +53,7 @@ extension Screen where Container: UINavigationController { /// the new bottom-to-top order of the controllers in the navigation stack. /// Thus, the last item added to the array becomes the top item of the navigation stack. /// - Returns: New `Screen` with replaced `viewControllers` in container. + @MainActor public func withStack(_ stack: AnyModalScreen...) -> AnyScreen { withStack(stack) } @@ -61,6 +62,7 @@ extension Screen where Container: UINavigationController { /// Sets the `viewControllers` property for a container with type `UINavigationController`. /// - Parameter screen: The screen to place in the stack as root. /// - Returns: New `Screen` with replaced `viewControllers` in container. + @MainActor public func withStack( _ screen: T ) -> AnyScreen where T.Container: UIViewController { @@ -75,6 +77,7 @@ extension Screen where Container: UINavigationController { /// - screen0: The screen to place in the stack as root. /// - screen1: The screen to place in the stack as top. /// - Returns: New `Screen` with replaced `viewControllers` in container. + @MainActor public func withStack( _ screen0: T0, _ screen1: T1 @@ -94,6 +97,7 @@ extension Screen where Container: UINavigationController { /// - screen1: The screen to place in the stack as second after the root. /// - screen2: The screen to place in the stack as top. /// - Returns: New `Screen` with replaced `viewControllers` in container. + @MainActor public func withStack( _ screen0: T0, _ screen1: T1, @@ -117,6 +121,7 @@ extension Screen where Container: UINavigationController { /// - screen2: The screen to place in the stack as third after the root. /// - screen3: The screen to place in the stack as top. /// - Returns: New `Screen` with replaced `viewControllers` in container. + @MainActor public func withStack( _ screen0: T0, _ screen1: T1, @@ -144,6 +149,7 @@ extension Screen where Container: UINavigationController { /// - screen3: The screen to place in the stack as fourth after the root. /// - screen4: The screen to place in the stack as top. /// - Returns: New `Screen` with replaced `viewControllers` in container. + @MainActor public func withStack( _ screen0: T0, _ screen1: T1, diff --git a/Sources/Screen/Decorators/Tabs/ScreenTabsDecorator.swift b/Sources/Screen/Decorators/Tabs/ScreenTabsDecorator.swift index 8465b610..7c676554 100644 --- a/Sources/Screen/Decorators/Tabs/ScreenTabsDecorator.swift +++ b/Sources/Screen/Decorators/Tabs/ScreenTabsDecorator.swift @@ -11,12 +11,11 @@ public struct ScreenTabsDecorator: ScreenDecorato nil } - public var description: String { - "TabsDecorator" - } + public let description: String public init(tabs: [AnyModalScreen], selected: Int = 0) { self.tabs = tabs + description = "TabsDecorator" } public func build( @@ -42,6 +41,7 @@ extension Screen where Container: UITabBarController { /// with the screen at index 0 representing the left-most tab, /// the screen at index 1 the next tab to the right, and so on. /// - Returns: New `Screen` with updated `viewControllers` in container. + @MainActor public func withTabs(_ tabs: [AnyModalScreen]) -> AnyScreen { decorated(by: ScreenTabsDecorator(tabs: tabs)) } @@ -53,6 +53,7 @@ extension Screen where Container: UITabBarController { /// with the screen at index 0 representing the left-most tab, /// the screen at index 1 the next tab to the right, and so on. /// - Returns: New `Screen` with updated `viewControllers` in container. + @MainActor public func withTabs(_ tabs: AnyModalScreen...) -> AnyScreen { withTabs(tabs) } @@ -61,6 +62,7 @@ extension Screen where Container: UITabBarController { /// Sets the `viewControllers` property for a container with type `UITabBarController`. /// - Parameter screen: The screen to display in the tab bar interface. /// - Returns: New `Screen` with updated `viewControllers` in container. + @MainActor public func withTabs( _ screen: T ) -> AnyScreen where T.Container: UIViewController { @@ -75,6 +77,7 @@ extension Screen where Container: UITabBarController { /// - screen0: The screen representing the left-most tab. /// - screen1: The screen of the next tab after `screen0`. /// - Returns: New `Screen` with updated `viewControllers` in container. + @MainActor public func withTabs( _ screen0: T0, _ screen1: T1 @@ -94,6 +97,7 @@ extension Screen where Container: UITabBarController { /// - screen1: The screen of the next tab after `screen0`. /// - screen2: The screen of the next tab after `screen1`. /// - Returns: New `Screen` with updated `viewControllers` in container. + @MainActor public func withTabs( _ screen0: T0, _ screen1: T1, @@ -117,6 +121,7 @@ extension Screen where Container: UITabBarController { /// - screen2: The screen of the next tab after `screen1`. /// - screen3: The screen of the next tab after `screen2`. /// - Returns: New `Screen` with updated `viewControllers` in container. + @MainActor public func withTabs( _ screen0: T0, _ screen1: T1, @@ -144,6 +149,7 @@ extension Screen where Container: UITabBarController { /// - screen3: The screen of the next tab after `screen2`. /// - screen4: The screen of the next tab after `screen3`. /// - Returns: New `Screen` with updated `viewControllers` in container. + @MainActor public func withTabs( _ screen0: T0, _ screen1: T1, diff --git a/Sources/Screen/Errors/ScreenCanceledError.swift b/Sources/Screen/Errors/ScreenCanceledError.swift index 888b3456..8a4387fd 100644 --- a/Sources/Screen/Errors/ScreenCanceledError.swift +++ b/Sources/Screen/Errors/ScreenCanceledError.swift @@ -5,21 +5,16 @@ import Foundation /// This error occurs whenever an action is canceled. public struct ScreenCanceledError: ScreenError { - public var description: String { - """ - Action canceled: - \(trigger) - """ - } - - /// The action that caused the error. - public let trigger: Any + public let description: String /// Creates an error. /// /// - Parameters: /// - trigger: The action that caused the error. public init(for trigger: Any) { - self.trigger = trigger + description = """ + Action canceled: + \(trigger) + """ } } diff --git a/Sources/Screen/Errors/ScreenContainerAlreadyPresentingError.swift b/Sources/Screen/Errors/ScreenContainerAlreadyPresentingError.swift index 2f9dedc8..bba91423 100644 --- a/Sources/Screen/Errors/ScreenContainerAlreadyPresentingError.swift +++ b/Sources/Screen/Errors/ScreenContainerAlreadyPresentingError.swift @@ -6,18 +6,7 @@ import Foundation /// which is already presenting another container. public struct ScreenContainerAlreadyPresentingError: ScreenError { - public var description: String { - """ - The container \(container) is already presenting another container for: - \(trigger) - """ - } - - /// Container that is already presenting another screen. - public let container: ScreenContainer - - /// The action that caused the error. - public let trigger: Any + public let description: String /// Creates an error. /// @@ -25,8 +14,10 @@ public struct ScreenContainerAlreadyPresentingError: ScreenError { /// - container: Container that is already presenting another screen. /// - trigger: The action that caused the error. public init(container: ScreenContainer, for trigger: Any) { - self.container = container - self.trigger = trigger + description = """ + The container \(container) is already presenting another container for: + \(trigger) + """ } } diff --git a/Sources/Screen/Errors/ScreenContainerNotFoundError.swift b/Sources/Screen/Errors/ScreenContainerNotFoundError.swift index 66155e9c..86bc1c14 100644 --- a/Sources/Screen/Errors/ScreenContainerNotFoundError.swift +++ b/Sources/Screen/Errors/ScreenContainerNotFoundError.swift @@ -5,18 +5,7 @@ import Foundation /// This error occurs whenever an action fails to find the container. public struct ScreenContainerNotFoundError: ScreenError { - public var description: String { - """ - No container of \(type) type found for: - \(trigger) - """ - } - - /// The type of container that could not be found. - public let type: Any.Type - - /// The action that caused the error. - public let trigger: Any + public let description: String /// Creates an error. /// @@ -24,8 +13,10 @@ public struct ScreenContainerNotFoundError: ScreenError { /// - type: The type of container that could not be found. /// - trigger: The action that caused the error. public init(type: Any.Type, for trigger: Any) { - self.type = type - self.trigger = trigger + description = """ + No container of \(type) type found for: + \(trigger) + """ } } diff --git a/Sources/Screen/Errors/ScreenContainerNotSupportedError.swift b/Sources/Screen/Errors/ScreenContainerNotSupportedError.swift index f63b8a0d..7263b3bf 100644 --- a/Sources/Screen/Errors/ScreenContainerNotSupportedError.swift +++ b/Sources/Screen/Errors/ScreenContainerNotSupportedError.swift @@ -5,18 +5,7 @@ import Foundation /// This error occurs whenever an action handles an unsupported container type. public struct ScreenContainerNotSupportedError: ScreenError { - public var description: String { - """ - The type of the container \(container) is not supported for: - \(trigger) - """ - } - - /// Container that is not supported. - public let container: ScreenContainer - - /// The action that caused the error. - public let trigger: Any + public let description: String /// Creates an error. /// @@ -24,8 +13,10 @@ public struct ScreenContainerNotSupportedError: ScreenError { /// - container: Container that does not match the expected type. /// - trigger: The action that caused the error. public init(container: ScreenContainer, for trigger: Any) { - self.container = container - self.trigger = trigger + description = """ + The type of the container \(container) is not supported for: + \(trigger) + """ } } diff --git a/Sources/Screen/Errors/ScreenContainerTypeMismatchError.swift b/Sources/Screen/Errors/ScreenContainerTypeMismatchError.swift index cc524700..72f7499f 100644 --- a/Sources/Screen/Errors/ScreenContainerTypeMismatchError.swift +++ b/Sources/Screen/Errors/ScreenContainerTypeMismatchError.swift @@ -5,21 +5,7 @@ import Foundation /// This error occurs whenever an action fails to cast the container to the expected type. public struct ScreenContainerTypeMismatchError: ScreenError { - public var description: String { - """ - The type of the container \(container) does not match the expected type \(type) for: - \(trigger) - """ - } - - /// Container that does not match the expected type. - public let container: ScreenContainer - - /// Expected container type - public let type: Any.Type - - /// The action that caused the error. - public let trigger: Any + public let description: String /// Creates an error. /// @@ -28,9 +14,10 @@ public struct ScreenContainerTypeMismatchError: ScreenError { /// - type: Expected container type. /// - trigger: The action that caused the error. public init(container: ScreenContainer, type: Any.Type, for trigger: Any) { - self.container = container - self.type = type - self.trigger = trigger + description = """ + The type of the container \(container) does not match the expected type \(type) for: + \(trigger) + """ } } diff --git a/Sources/Screen/Navigator/Iterator/ScreenIterator.swift b/Sources/Screen/Navigator/Iterator/ScreenIterator.swift index 9db5d987..f501cd40 100644 --- a/Sources/Screen/Navigator/Iterator/ScreenIterator.swift +++ b/Sources/Screen/Navigator/Iterator/ScreenIterator.swift @@ -1,6 +1,7 @@ import Foundation /// A type that iterates and searches through containers of screens with a given predicate. +@MainActor public protocol ScreenIterator { /// Iterate through containers starting from a given `container` as long as the `predicate` condition holds. diff --git a/Sources/Screen/Navigator/Observatory/ScreenObservatory.swift b/Sources/Screen/Navigator/Observatory/ScreenObservatory.swift index 194a729c..357b2e53 100644 --- a/Sources/Screen/Navigator/Observatory/ScreenObservatory.swift +++ b/Sources/Screen/Navigator/Observatory/ScreenObservatory.swift @@ -88,6 +88,7 @@ import Foundation /// - SeeAlso: `ScreenObserver` /// - SeeAlso: `ScreenObservation` /// - SeeAlso: `ScreenObserverPredicate` +@MainActor public protocol ScreenObservatory { /// Observing containers by an observer. diff --git a/Sources/Screen/Navigator/ScreenNavigator.swift b/Sources/Screen/Navigator/ScreenNavigator.swift index fbf631dc..903427cd 100644 --- a/Sources/Screen/Navigator/ScreenNavigator.swift +++ b/Sources/Screen/Navigator/ScreenNavigator.swift @@ -32,6 +32,7 @@ import Foundation /// - SeeAlso: `ScreenObservatory` /// - SeeAlso: `ScreenIterator` /// - SeeAlso: `ScreenLogger` +@MainActor public final class ScreenNavigator { /// Closure with the result of the navigation action. @@ -84,15 +85,15 @@ public final class ScreenNavigator { /// - iterator: Implementation of a container iterator for searching. /// - logger: Implementation of the navigation log output. Pass `nil` to disable logging. public init( - windowProvider: ScreenWindowProvider = ScreenKeyWindowProvider(), - observatory: ScreenObservatory = DefaultScreenObservatory(), - iterator: ScreenIterator = DefaultScreenIterator(), - logger: ScreenLogger? = DefaultScreenLogger() + windowProvider: ScreenWindowProvider? = nil, + observatory: ScreenObservatory? = nil, + iterator: ScreenIterator? = nil, + logger: ScreenLogger? = nil ) { - self.windowProvider = windowProvider - self.observatory = observatory - self.iterator = iterator - self.logger = logger + self.windowProvider = windowProvider ?? ScreenKeyWindowProvider() + self.observatory = observatory ?? DefaultScreenObservatory() + self.iterator = iterator ?? DefaultScreenIterator() + self.logger = logger ?? DefaultScreenLogger() } /// Initializing an instance of `ScreenNavigator`. @@ -104,14 +105,14 @@ public final class ScreenNavigator { /// - logger: Implementation of the navigation log output. Pass `nil` to disable logging. public init( window: UIWindow, - observatory: ScreenObservatory = DefaultScreenObservatory(), - iterator: ScreenIterator = DefaultScreenIterator(), - logger: ScreenLogger? = DefaultScreenLogger() + observatory: ScreenObservatory? = nil, + iterator: ScreenIterator? = nil, + logger: ScreenLogger? = nil ) { self.windowProvider = ScreenCustomWindowProvider(window: window) - self.observatory = observatory - self.iterator = iterator - self.logger = logger + self.observatory = observatory ?? DefaultScreenObservatory() + self.iterator = iterator ?? DefaultScreenIterator() + self.logger = logger ?? DefaultScreenLogger() } #else /// Initializing an instance of `ScreenNavigator`. diff --git a/Sources/Screen/Navigator/WindowProvider/ScreenWindowProvider.swift b/Sources/Screen/Navigator/WindowProvider/ScreenWindowProvider.swift index 813878ee..28b7b499 100644 --- a/Sources/Screen/Navigator/WindowProvider/ScreenWindowProvider.swift +++ b/Sources/Screen/Navigator/WindowProvider/ScreenWindowProvider.swift @@ -2,6 +2,7 @@ import UIKit /// A type that provides an instance of `UIWindow` for navigating and searching containers. +@MainActor public protocol ScreenWindowProvider { /// The `UIWindow` for navigating and searching for containers. diff --git a/Sources/Screen/Observation/ScreenObserverPredicate.swift b/Sources/Screen/Observation/ScreenObserverPredicate.swift index ab3a51c1..fbe8f4f1 100644 --- a/Sources/Screen/Observation/ScreenObserverPredicate.swift +++ b/Sources/Screen/Observation/ScreenObserverPredicate.swift @@ -42,6 +42,7 @@ import UIKit /// ``` /// /// - SeeAlso: ``ScreenObserver`` +@MainActor public struct ScreenObserverPredicate { public typealias Filter = ( diff --git a/Sources/Screen/Observation/Storage/ScreenObserverStorage.swift b/Sources/Screen/Observation/Storage/ScreenObserverStorage.swift index 24e4795a..797b4b43 100644 --- a/Sources/Screen/Observation/Storage/ScreenObserverStorage.swift +++ b/Sources/Screen/Observation/Storage/ScreenObserverStorage.swift @@ -1,5 +1,6 @@ import Foundation +@MainActor internal protocol ScreenObserverStorage: AnyObject { var predicate: ScreenObserverPredicate { get } diff --git a/Sources/Screen/Payload/ScreenPayloadedContainer.swift b/Sources/Screen/Payload/ScreenPayloadedContainer.swift index 0ae6b8bf..bc475978 100644 --- a/Sources/Screen/Payload/ScreenPayloadedContainer.swift +++ b/Sources/Screen/Payload/ScreenPayloadedContainer.swift @@ -10,6 +10,7 @@ import Foundation /// to associate the payload with the container. /// /// - SeeAlso: `ScreenContainer` +@MainActor public protocol ScreenPayloadedContainer: ScreenContainer { /// Screen payload. diff --git a/Sources/Screen/Route/ScreenRouteConvertible.swift b/Sources/Screen/Route/ScreenRouteConvertible.swift index f403e8b8..54edce0c 100644 --- a/Sources/Screen/Route/ScreenRouteConvertible.swift +++ b/Sources/Screen/Route/ScreenRouteConvertible.swift @@ -6,6 +6,7 @@ import Foundation /// /// - SeeAlso: `ScreenRoute` /// - SeeAlso: `ScreenRootRoute` +@MainActor public protocol ScreenRouteConvertible { /// Returns the root route with the actions of the current instance. diff --git a/Sources/Screen/Route/ScreenThenable.swift b/Sources/Screen/Route/ScreenThenable.swift index 85780c3b..080c3173 100644 --- a/Sources/Screen/Route/ScreenThenable.swift +++ b/Sources/Screen/Route/ScreenThenable.swift @@ -1,6 +1,7 @@ import Foundation /// A protocol representing the route to which actions can be added. +@MainActor public protocol ScreenThenable { /// A type of root container that will be used to perform actions. diff --git a/Sources/Screen/Screen.swift b/Sources/Screen/Screen.swift index d88a4411..c01a0e1e 100755 --- a/Sources/Screen/Screen.swift +++ b/Sources/Screen/Screen.swift @@ -148,6 +148,7 @@ public protocol Screen: CustomStringConvertible { /// - Returns: Container instance. /// /// - SeeAlso: `ScreenNavigator` + @MainActor func build(navigator: ScreenNavigator) -> Container /// Builds the screen module and returns its container. @@ -159,6 +160,7 @@ public protocol Screen: CustomStringConvertible { /// /// - SeeAlso: `ScreenNavigator` /// - SeeAlso: `ScreenObservation` + @MainActor func build( navigator: ScreenNavigator, observation: ScreenObservation @@ -174,6 +176,7 @@ extension Screen where Self: ScreenContainer, Observer == Never { extension Screen where Observer == Never { + @MainActor public func build( navigator: ScreenNavigator, observation: ScreenObservation @@ -184,6 +187,7 @@ extension Screen where Observer == Never { extension Screen { + @MainActor public func build(navigator: ScreenNavigator) -> Container { let observation = navigator.observation(of: Observer.self) diff --git a/Sources/Screen/ScreenKey.swift b/Sources/Screen/ScreenKey.swift index c809e914..ec6a729a 100644 --- a/Sources/Screen/ScreenKey.swift +++ b/Sources/Screen/ScreenKey.swift @@ -7,7 +7,7 @@ import Foundation /// /// - SeeAlso: `Screen`. /// - SeeAlso: `ScreenKeyedContainer`. -public struct ScreenKey: Hashable, CustomStringConvertible { +public struct ScreenKey: Hashable, CustomStringConvertible, Sendable { /// Screen name. public let name: String @@ -15,13 +15,7 @@ public struct ScreenKey: Hashable, CustomStringConvertible { /// Screen traits that are used to distinguish screens with the same name. public let traits: Set - public var description: String { - let traits = self.traits.map { $0.base } - - return traits.isEmpty - ? name - : "\(name)(\(traits))" - } + public let description: String /// Creates a screen key. /// @@ -31,5 +25,9 @@ public struct ScreenKey: Hashable, CustomStringConvertible { public init(name: String, traits: Set = []) { self.name = name self.traits = traits + let traits = self.traits.map { $0.base } + description = traits.isEmpty + ? name + : "\(name)(\(traits))" } } diff --git a/Sources/Tools/DictionaryDecoder/DictionaryDecoder.swift b/Sources/Tools/DictionaryDecoder/DictionaryDecoder.swift index 8ae7b8ca..fd900d5a 100644 --- a/Sources/Tools/DictionaryDecoder/DictionaryDecoder.swift +++ b/Sources/Tools/DictionaryDecoder/DictionaryDecoder.swift @@ -2,6 +2,7 @@ import Foundation internal struct DictionaryDecoder { + @MainActor internal static let `default` = Self() internal var dateDecodingStrategy: DictionaryDateDecodingStrategy diff --git a/Sources/Tools/KeyboardHandler.swift b/Sources/Tools/KeyboardHandler.swift index d35e85c9..50e45549 100644 --- a/Sources/Tools/KeyboardHandler.swift +++ b/Sources/Tools/KeyboardHandler.swift @@ -1,7 +1,7 @@ #if canImport(UIKit) && os(iOS) import UIKit -internal protocol KeyboardHandler: AnyObject { +internal protocol KeyboardHandler: AnyObject, Sendable { var keyboardFrame: CGRect { get set } @@ -14,6 +14,7 @@ internal protocol KeyboardHandler: AnyObject { var keyboardWillHideNotificationObserver: NotificationObserver? { get set } var keyboardDidHideNotificationObserver: NotificationObserver? { get set } + @MainActor func handleKeyboardFrame( _ keyboardFrame: CGRect, animationDuration: TimeInterval, @@ -102,12 +103,16 @@ extension KeyboardHandler { } self.keyboardFrame = keyboardFrame - - handleKeyboardFrame( - keyboardFrame, - animationDuration: resolveKeyboardAnimationDuration(from: notification), - animationOptions: resolveKeyboardAnimationOptions(from: notification) - ) + let duration = resolveKeyboardAnimationDuration(from: notification) + let options = resolveKeyboardAnimationOptions(from: notification) + + MainActor.assumeIsolated { + handleKeyboardFrame( + keyboardFrame, + animationDuration: duration, + animationOptions: options + ) + } } internal func subscribeToKeyboardNotifications() { diff --git a/Sources/Tools/NotificationObserver.swift b/Sources/Tools/NotificationObserver.swift index 88c59fea..2c925e90 100644 --- a/Sources/Tools/NotificationObserver.swift +++ b/Sources/Tools/NotificationObserver.swift @@ -7,21 +7,21 @@ internal class NotificationObserver { internal let center: NotificationCenter internal let name: Notification.Name internal let queue: OperationQueue? - internal let handler: ((_ notification: Notification) -> Void)? + internal let handler: (@Sendable (_ notification: Notification) -> Void)? internal init( center: NotificationCenter = .default, name: Notification.Name, queue: OperationQueue? = nil, - handler: ((_ notification: Notification) -> Void)? + handler: (@Sendable (_ notification: Notification) -> Void)? ) { self.center = center self.name = name self.queue = queue self.handler = handler - self.token = center.addObserver(forName: name, object: nil, queue: queue) { [weak self] notification in - self?.handler?(notification) + self.token = center.addObserver(forName: name, object: nil, queue: queue) { notification in + handler?(notification) } } diff --git a/Sources/Tools/ObjectAssociation.swift b/Sources/Tools/ObjectAssociation.swift index bc6a0ccd..f55c07fe 100644 --- a/Sources/Tools/ObjectAssociation.swift +++ b/Sources/Tools/ObjectAssociation.swift @@ -1,6 +1,6 @@ import Foundation -internal final class ObjectAssociation { +internal final class ObjectAssociation: Sendable { private let policy: objc_AssociationPolicy diff --git a/Sources/Tools/URLQueryDecoder/URLQueryDecoder.swift b/Sources/Tools/URLQueryDecoder/URLQueryDecoder.swift index 156d31f5..fbaf2d85 100644 --- a/Sources/Tools/URLQueryDecoder/URLQueryDecoder.swift +++ b/Sources/Tools/URLQueryDecoder/URLQueryDecoder.swift @@ -2,6 +2,7 @@ import Foundation internal struct URLQueryDecoder { + @MainActor internal static let `default` = Self() internal var dateDecodingStrategy: URLQueryDateDecodingStrategy From 260c050c6d21f8bae879e856a49336bad038b84e Mon Sep 17 00:00:00 2001 From: Alexander Khodko Date: Mon, 30 Sep 2024 15:23:56 +0300 Subject: [PATCH 02/10] t --- Example/NivelirExample.xcodeproj/project.pbxproj | 10 ++++++---- .../Routing/Sharing/SharingOpenInBrowserActivity.swift | 1 + .../Services/Profile/DefaultProfileService.swift | 2 +- .../Services/Profile/ProfileService.swift | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Example/NivelirExample.xcodeproj/project.pbxproj b/Example/NivelirExample.xcodeproj/project.pbxproj index 43b5d3c8..f85e7cae 100644 --- a/Example/NivelirExample.xcodeproj/project.pbxproj +++ b/Example/NivelirExample.xcodeproj/project.pbxproj @@ -1053,7 +1053,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7VKZYG8P42; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = NivelirExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1072,7 +1072,7 @@ buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = 7VKZYG8P42; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = NivelirExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1092,6 +1092,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "Brand Assets"; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = NivelirExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1100,7 +1101,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "ru.hh.Nivelir-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 3; }; name = Debug; @@ -1112,6 +1113,7 @@ ASSETCATALOG_COMPILER_APPICON_NAME = "Brand Assets"; ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = NivelirExample/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", @@ -1120,7 +1122,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "ru.hh.Nivelir-Example"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 3; }; name = Release; diff --git a/Example/NivelirExample/Routing/Sharing/SharingOpenInBrowserActivity.swift b/Example/NivelirExample/Routing/Sharing/SharingOpenInBrowserActivity.swift index 28a2881d..8235aac7 100644 --- a/Example/NivelirExample/Routing/Sharing/SharingOpenInBrowserActivity.swift +++ b/Example/NivelirExample/Routing/Sharing/SharingOpenInBrowserActivity.swift @@ -70,6 +70,7 @@ extension SharingActivityType { extension SharingActivity { + @MainActor static var openInBrowser: Self { .custom(SharingOpenInBrowserActivity()) } diff --git a/Example/NivelirExample/Services/Profile/DefaultProfileService.swift b/Example/NivelirExample/Services/Profile/DefaultProfileService.swift index f7db6d8b..57148ca9 100644 --- a/Example/NivelirExample/Services/Profile/DefaultProfileService.swift +++ b/Example/NivelirExample/Services/Profile/DefaultProfileService.swift @@ -56,7 +56,7 @@ final class DefaultProfileService: ProfileService, Sendable { Task { await MainActor.run { - progress(intervalCount.value * 0.01) + progress(self.intervalCount.value * 0.01) } } diff --git a/Example/NivelirExample/Services/Profile/ProfileService.swift b/Example/NivelirExample/Services/Profile/ProfileService.swift index bbb3160c..f221cee3 100644 --- a/Example/NivelirExample/Services/Profile/ProfileService.swift +++ b/Example/NivelirExample/Services/Profile/ProfileService.swift @@ -1,8 +1,8 @@ import UIKit -@MainActor protocol ProfileService { + @MainActor func uploadPhoto( image: UIImage, progress: @MainActor @Sendable @escaping (_ ratio: CGFloat) -> Void, From 9d5731c1bad924c3513281112a853a3f4c401751 Mon Sep 17 00:00:00 2001 From: Alexander Khodko Date: Mon, 30 Sep 2024 15:27:25 +0300 Subject: [PATCH 03/10] t --- Nivelir.podspec | 2 +- Nivelir.xcodeproj/project.pbxproj | 12 ++--- Sources/Addons/Safari/SafariManager.swift | 1 - .../Sharing/Activity/SharingActivity.swift | 5 +- .../Activity/SharingActivityManager.swift | 52 ++++++++++++------- .../Activity/SharingCustomActivity.swift | 1 - .../Activity/SharingSilentActivity.swift | 4 +- Sources/Addons/Sharing/Item/SharingItem.swift | 2 +- Sources/Screen/ScreenKey.swift | 2 +- 9 files changed, 47 insertions(+), 34 deletions(-) diff --git a/Nivelir.podspec b/Nivelir.podspec index 4385330d..bd812ded 100644 --- a/Nivelir.podspec +++ b/Nivelir.podspec @@ -8,7 +8,7 @@ Pod::Spec.new do |spec| spec.author = { "Almaz Ibragimov" => "almazrafi@gmail.com" } spec.source = { :git => "https://github.com/hhru/Nivelir.git", :tag => "#{spec.version}" } - spec.swift_version = '5.7' + spec.swift_version = '6.0' spec.requires_arc = true spec.source_files = 'Sources/**/*.swift' diff --git a/Nivelir.xcodeproj/project.pbxproj b/Nivelir.xcodeproj/project.pbxproj index f9fca6b7..00d7d402 100755 --- a/Nivelir.xcodeproj/project.pbxproj +++ b/Nivelir.xcodeproj/project.pbxproj @@ -3456,7 +3456,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "ru.hh.Nivelir.Tests-iOS"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -3475,7 +3475,7 @@ ); PRODUCT_BUNDLE_IDENTIFIER = "ru.hh.Nivelir.Tests-iOS"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -3507,7 +3507,7 @@ SKIP_INSTALL = YES; SKIP_SWIFTLINT = ""; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 3; }; name = Debug; @@ -3538,7 +3538,7 @@ SDKROOT = appletvos; SKIP_INSTALL = YES; SKIP_SWIFTLINT = YES; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 3; }; name = Release; @@ -3558,7 +3558,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "ru.hh.Nivelir.Tests-tvOS"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 3; }; name = Debug; @@ -3578,7 +3578,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "ru.hh.Nivelir.Tests-tvOS"; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = appletvos; - SWIFT_VERSION = 5.7; + SWIFT_VERSION = 6.0; TARGETED_DEVICE_FAMILY = 3; }; name = Release; diff --git a/Sources/Addons/Safari/SafariManager.swift b/Sources/Addons/Safari/SafariManager.swift index 780eb971..e5bfbab9 100644 --- a/Sources/Addons/Safari/SafariManager.swift +++ b/Sources/Addons/Safari/SafariManager.swift @@ -2,7 +2,6 @@ import Foundation import SafariServices -@MainActor internal final class SafariManager: NSObject, SFSafariViewControllerDelegate { diff --git a/Sources/Addons/Sharing/Activity/SharingActivity.swift b/Sources/Addons/Sharing/Activity/SharingActivity.swift index 61ef045d..417badc6 100644 --- a/Sources/Addons/Sharing/Activity/SharingActivity.swift +++ b/Sources/Addons/Sharing/Activity/SharingActivity.swift @@ -3,7 +3,7 @@ import UIKit public struct SharingActivity { - private typealias Body = @MainActor (_ navigator: ScreenNavigator) -> UIActivity + private typealias Body = (_ navigator: ScreenNavigator) -> UIActivity private let body: Body @@ -11,7 +11,6 @@ public struct SharingActivity { self.body = body } - @MainActor internal func activity(navigator: ScreenNavigator) -> UIActivity { body(navigator) } @@ -25,6 +24,7 @@ extension SharingActivity { } } + @MainActor public static func custom(_ value: Value) -> Self { Self { navigator in SharingActivityManager( @@ -34,6 +34,7 @@ extension SharingActivity { } } + @MainActor public static func custom(_ value: Value) -> Self { Self { navigator in SharingActivityManager( diff --git a/Sources/Addons/Sharing/Activity/SharingActivityManager.swift b/Sources/Addons/Sharing/Activity/SharingActivityManager.swift index 1e0be1b9..7bc9dc4c 100644 --- a/Sources/Addons/Sharing/Activity/SharingActivityManager.swift +++ b/Sources/Addons/Sharing/Activity/SharingActivityManager.swift @@ -2,7 +2,7 @@ import UIKit @MainActor -internal final class SharingActivityManager: UIActivity { +internal final class SharingActivityManager: UIActivity, Sendable { internal override class var activityCategory: UIActivity.Category { Activity.category @@ -14,28 +14,34 @@ internal final class SharingActivityManager: UI internal let activity: Activity internal override var activityType: UIActivity.ActivityType? { - activity.type + MainActor.assumeIsolated { + activity.type + } } internal override var activityTitle: String? { - activity.title + MainActor.assumeIsolated { + activity.title + } } internal override var activityImage: UIImage? { - activity.image + MainActor.assumeIsolated { + activity.image + } } internal override var activityViewController: UIViewController? { - guard let activity = activity as? SharingVisualActivity else { - return nil - } + MainActor.assumeIsolated { + guard let activity = activity as? SharingVisualActivity else { + return nil + } - let screen = activity.prepare(for: items) { [weak self] completed in - self?.activityDidFinish(completed) - } + let screen = activity.prepare(for: items) { [weak self] completed in + self?.activityDidFinish(completed) + } - return MainActor.assumeIsolated { [navigator] in - screen.build(navigator: navigator) + return screen.build(navigator: navigator) } } @@ -48,20 +54,28 @@ internal final class SharingActivityManager: UI } internal override func canPerform(withActivityItems activityItems: [Any]) -> Bool { - activity.isApplicable(for: activityItems.map(SharingItem.init(activityItem:))) + let activityItems = activityItems.map(SharingItem.init(activityItem:)) + return MainActor.assumeIsolated { + activity.isApplicable(for: activityItems) + } } internal override func prepare(withActivityItems activityItems: [Any]) { - items = activityItems.map(SharingItem.init(activityItem:)) + let activityItems = activityItems.map(SharingItem.init(activityItem:)) + MainActor.assumeIsolated { + items = activityItems + } } internal override func perform() { - guard let activity = activity as? SharingSilentActivity else { - return activityDidFinish(false) - } + MainActor.assumeIsolated { + guard let activity = activity as? SharingSilentActivity else { + return activityDidFinish(false) + } - activity.perform(for: items, navigator: navigator) { [weak self] completed in - self?.activityDidFinish(completed) + activity.perform(for: items, navigator: navigator) { [weak self] completed in + self?.activityDidFinish(completed) + } } } } diff --git a/Sources/Addons/Sharing/Activity/SharingCustomActivity.swift b/Sources/Addons/Sharing/Activity/SharingCustomActivity.swift index 6a329a67..65c11b1a 100644 --- a/Sources/Addons/Sharing/Activity/SharingCustomActivity.swift +++ b/Sources/Addons/Sharing/Activity/SharingCustomActivity.swift @@ -1,7 +1,6 @@ #if canImport(UIKit) && os(iOS) import UIKit -@MainActor public protocol SharingCustomActivity { static var category: SharingActivityCategory { get } diff --git a/Sources/Addons/Sharing/Activity/SharingSilentActivity.swift b/Sources/Addons/Sharing/Activity/SharingSilentActivity.swift index 6025fe7c..1b0374e0 100644 --- a/Sources/Addons/Sharing/Activity/SharingSilentActivity.swift +++ b/Sources/Addons/Sharing/Activity/SharingSilentActivity.swift @@ -1,9 +1,9 @@ #if canImport(UIKit) && os(iOS) import UIKit -@MainActor -public protocol SharingSilentActivity: SharingCustomActivity { +public protocol SharingSilentActivity: SharingCustomActivity, Sendable { + @MainActor func perform( for items: [SharingItem], navigator: ScreenNavigator, diff --git a/Sources/Addons/Sharing/Item/SharingItem.swift b/Sources/Addons/Sharing/Item/SharingItem.swift index 91d7228c..a9cd2de0 100644 --- a/Sources/Addons/Sharing/Item/SharingItem.swift +++ b/Sources/Addons/Sharing/Item/SharingItem.swift @@ -1,7 +1,7 @@ #if canImport(UIKit) && os(iOS) import UIKit -public enum SharingItem: CustomStringConvertible { +public enum SharingItem: CustomStringConvertible, @unchecked Sendable { case regular(Any) case custom(SharingCustomItem) diff --git a/Sources/Screen/ScreenKey.swift b/Sources/Screen/ScreenKey.swift index ec6a729a..05695a64 100644 --- a/Sources/Screen/ScreenKey.swift +++ b/Sources/Screen/ScreenKey.swift @@ -7,7 +7,7 @@ import Foundation /// /// - SeeAlso: `Screen`. /// - SeeAlso: `ScreenKeyedContainer`. -public struct ScreenKey: Hashable, CustomStringConvertible, Sendable { +public struct ScreenKey: Hashable, CustomStringConvertible { /// Screen name. public let name: String From 63300a00da06a8437a8fdd04426b178a90f0f22c Mon Sep 17 00:00:00 2001 From: Alexander Khodko Date: Mon, 30 Sep 2024 15:54:30 +0300 Subject: [PATCH 04/10] t --- .github/workflows/swift.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index b55cdc34..1f606ef9 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -17,13 +17,13 @@ jobs: name: Build & Tests runs-on: macOS-13 env: - DEVELOPER_DIR: /Applications/Xcode_15.2.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer XCODE_PROJECT: Nivelir.xcodeproj IOS_SCHEME: Nivelir iOS - IOS_DESTINATION: OS=17.2,name=iPhone 15 + IOS_DESTINATION: OS=18.0,name=iPhone 16 IOS_RESULT_PATH: xcodebuild-ios.xcresult TVOS_SCHEME: Nivelir tvOS - TVOS_DESTINATION: OS=17.2,name=Apple TV + TVOS_DESTINATION: OS=18.0,name=Apple TV TVOS_RESULT_PATH: xcodebuild-tvos.xcresult SKIP_SWIFTLINT: YES SWIFTLINT_VERSION: 0.52.2 From 94517e699a9368e57106c5ea57601f971f87eeab Mon Sep 17 00:00:00 2001 From: Alexander Khodko Date: Mon, 30 Sep 2024 15:54:47 +0300 Subject: [PATCH 05/10] t --- .github/workflows/swift.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 1f606ef9..174dd2c2 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -61,7 +61,7 @@ jobs: gem install bundler bundle install --without=documentation - name: Switch Xcode version - run: sudo xcode-select --switch /Applications/Xcode_15.2.app + run: sudo xcode-select --switch /Applications/Xcode_16.0.app - name: Linting run: bundle exec pod lib lint --skip-tests --allow-warnings From 3cfe88ae0b2b7fa0c99989c038f0edfd6fa2666d Mon Sep 17 00:00:00 2001 From: Alexander Khodko Date: Mon, 30 Sep 2024 15:59:53 +0300 Subject: [PATCH 06/10] t --- .github/workflows/swift.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 174dd2c2..4316bb66 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -31,6 +31,8 @@ jobs: steps: - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 + - name: List available Xcode versions + run: ls /Applications | grep Xcode - name: Bundler run: | gem install bundler From 2f1a63ad30d3a76309d859114997de869a4fef1f Mon Sep 17 00:00:00 2001 From: Alexander Khodko Date: Mon, 30 Sep 2024 16:06:18 +0300 Subject: [PATCH 07/10] t --- .github/workflows/swift.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 4316bb66..8604ab01 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -15,7 +15,7 @@ env: jobs: BuildAndTests: name: Build & Tests - runs-on: macOS-13 + runs-on: macOS-14 env: DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer XCODE_PROJECT: Nivelir.xcodeproj @@ -54,7 +54,7 @@ jobs: Cocoapods: name: Cocoapods - runs-on: macOS-13 + runs-on: macOS-14 steps: - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 @@ -69,7 +69,7 @@ jobs: SPM: name: Swift Package Manager - runs-on: macOS-13 + runs-on: macOS-14 steps: - uses: actions/checkout@v3 - name: Build From 6726c90e5258a10755b25a7a798ab7dea05afbc0 Mon Sep 17 00:00:00 2001 From: Alexander Khodko Date: Mon, 30 Sep 2024 16:07:30 +0300 Subject: [PATCH 08/10] t --- .github/workflows/swift.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 8604ab01..81944af3 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -17,7 +17,7 @@ jobs: name: Build & Tests runs-on: macOS-14 env: - DEVELOPER_DIR: /Applications/Xcode_16.0.app/Contents/Developer + DEVELOPER_DIR: /Applications/Xcode_16.app/Contents/Developer XCODE_PROJECT: Nivelir.xcodeproj IOS_SCHEME: Nivelir iOS IOS_DESTINATION: OS=18.0,name=iPhone 16 @@ -31,8 +31,6 @@ jobs: steps: - uses: actions/checkout@v3 - uses: ruby/setup-ruby@v1 - - name: List available Xcode versions - run: ls /Applications | grep Xcode - name: Bundler run: | gem install bundler @@ -63,7 +61,7 @@ jobs: gem install bundler bundle install --without=documentation - name: Switch Xcode version - run: sudo xcode-select --switch /Applications/Xcode_16.0.app + run: sudo xcode-select --switch /Applications/Xcode_16.app - name: Linting run: bundle exec pod lib lint --skip-tests --allow-warnings From 2ca51e4981b177316c06aad2ed487394ce04b7b4 Mon Sep 17 00:00:00 2001 From: Alexander Khodko Date: Mon, 30 Sep 2024 16:19:52 +0300 Subject: [PATCH 09/10] t --- .../Options/DictionaryDataDecodingStrategy.swift | 2 +- .../Options/DictionaryDateDecodingStrategy.swift | 2 +- .../Options/DictionaryKeyDecodingStrategy.swift | 2 +- .../DictionaryDecoder/DictionaryDecoderTesting.swift | 10 +++++----- .../Tools/URLQueryDecoder/URLQueryDecoderTesting.swift | 6 +++--- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Sources/Tools/DictionaryDecoder/Options/DictionaryDataDecodingStrategy.swift b/Sources/Tools/DictionaryDecoder/Options/DictionaryDataDecodingStrategy.swift index 3f3de189..39d271a5 100644 --- a/Sources/Tools/DictionaryDecoder/Options/DictionaryDataDecodingStrategy.swift +++ b/Sources/Tools/DictionaryDecoder/Options/DictionaryDataDecodingStrategy.swift @@ -10,5 +10,5 @@ public enum DictionaryDataDecodingStrategy { case base64 /// The strategy that decodes data using a user-defined function. - case custom((_ decoder: Decoder) throws -> Data) + case custom(@Sendable (_ decoder: Decoder) throws -> Data) } diff --git a/Sources/Tools/DictionaryDecoder/Options/DictionaryDateDecodingStrategy.swift b/Sources/Tools/DictionaryDecoder/Options/DictionaryDateDecodingStrategy.swift index 0809e32d..a3dca17b 100644 --- a/Sources/Tools/DictionaryDecoder/Options/DictionaryDateDecodingStrategy.swift +++ b/Sources/Tools/DictionaryDecoder/Options/DictionaryDateDecodingStrategy.swift @@ -20,5 +20,5 @@ public enum DictionaryDateDecodingStrategy { case formatted(DateFormatter) /// The strategy that formats custom dates by calling a user-defined function. - case custom((_ decoder: Decoder) throws -> Date) + case custom(@Sendable (_ decoder: Decoder) throws -> Date) } diff --git a/Sources/Tools/DictionaryDecoder/Options/DictionaryKeyDecodingStrategy.swift b/Sources/Tools/DictionaryDecoder/Options/DictionaryKeyDecodingStrategy.swift index 0f5c9670..7c5334e8 100644 --- a/Sources/Tools/DictionaryDecoder/Options/DictionaryKeyDecodingStrategy.swift +++ b/Sources/Tools/DictionaryDecoder/Options/DictionaryKeyDecodingStrategy.swift @@ -7,5 +7,5 @@ public enum DictionaryKeyDecodingStrategy { case useDefaultKeys /// A key decoding strategy defined by the closure you supply. - case custom((_ codingPath: [CodingKey]) -> CodingKey) + case custom(@Sendable (_ codingPath: [CodingKey]) -> CodingKey) } diff --git a/Tests/Tools/DictionaryDecoder/DictionaryDecoderTesting.swift b/Tests/Tools/DictionaryDecoder/DictionaryDecoderTesting.swift index 6feae332..2ad7905c 100644 --- a/Tests/Tools/DictionaryDecoder/DictionaryDecoderTesting.swift +++ b/Tests/Tools/DictionaryDecoder/DictionaryDecoderTesting.swift @@ -28,7 +28,7 @@ extension DictionaryDecoderTesting { func assertDecoderSucceeds( decoding expectedValue: [Key: Value], from dictionary: [String: Any], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { do { @@ -48,7 +48,7 @@ extension DictionaryDecoderTesting { func assertDecoderSucceeds( decoding valueType: [Key: Value].Type, from dictionary: [String: Any], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { do { @@ -68,7 +68,7 @@ extension DictionaryDecoderTesting { func assertDecoderSucceeds( decoding expectedValue: T, from dictionary: [String: Any], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { do { @@ -83,7 +83,7 @@ extension DictionaryDecoderTesting { func assertDecoderSucceeds( decoding valueType: T.Type, from dictionary: [String: Any], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { do { @@ -103,7 +103,7 @@ extension DictionaryDecoderTesting { func assertDecoderFails( decoding valueType: T.Type, from dictionary: [String: Any], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line, errorValidation: (_ error: Error) -> Bool ) { diff --git a/Tests/Tools/URLQueryDecoder/URLQueryDecoderTesting.swift b/Tests/Tools/URLQueryDecoder/URLQueryDecoderTesting.swift index b1cff05f..008718be 100644 --- a/Tests/Tools/URLQueryDecoder/URLQueryDecoderTesting.swift +++ b/Tests/Tools/URLQueryDecoder/URLQueryDecoderTesting.swift @@ -13,7 +13,7 @@ extension URLQueryDecoderTesting { decoding valueType: [Key: Value].Type, from query: String, expecting expectedValue: [Key: Value], - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { do { @@ -34,7 +34,7 @@ extension URLQueryDecoderTesting { decoding valueType: T.Type, from query: String, expecting expectedValue: T, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line ) { do { @@ -49,7 +49,7 @@ extension URLQueryDecoderTesting { func assertDecoderFails( decoding valueType: T.Type, from query: String, - file: StaticString = #file, + file: StaticString = #filePath, line: UInt = #line, errorValidation: (_ error: Error) -> Bool ) { From 23447c4b75578e226d6b766a097be2dcd5ad0a62 Mon Sep 17 00:00:00 2001 From: Alexander Khodko Date: Mon, 30 Sep 2024 18:49:17 +0300 Subject: [PATCH 10/10] t --- Gemfile.lock | 192 +++++++++++++++++++++++++++------------------------ 1 file changed, 100 insertions(+), 92 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index 350824c7..4d038a06 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,48 +1,58 @@ GEM remote: https://rubygems.org/ specs: - CFPropertyList (3.0.6) + CFPropertyList (3.0.7) + base64 + nkf rexml - activesupport (7.0.5) - concurrent-ruby (~> 1.0, >= 1.0.2) + activesupport (7.2.1) + base64 + bigdecimal + concurrent-ruby (~> 1.0, >= 1.3.1) + connection_pool (>= 2.2.5) + drb i18n (>= 1.6, < 2) + logger (>= 1.4.2) minitest (>= 5.1) - tzinfo (~> 2.0) - addressable (2.8.4) - public_suffix (>= 2.0.2, < 6.0) + securerandom (>= 0.3) + tzinfo (~> 2.0, >= 2.0.5) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) algoliasearch (1.27.5) httpclient (~> 2.8, >= 2.8.3) json (>= 1.5.1) - artifactory (3.0.15) + artifactory (3.0.17) atomos (0.1.3) - aws-eventstream (1.2.0) - aws-partitions (1.780.0) - aws-sdk-core (3.175.0) - aws-eventstream (~> 1, >= 1.0.2) + aws-eventstream (1.3.0) + aws-partitions (1.981.0) + aws-sdk-core (3.209.1) + aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.651.0) - aws-sigv4 (~> 1.5) + aws-sigv4 (~> 1.9) jmespath (~> 1, >= 1.6.1) - aws-sdk-kms (1.67.0) - aws-sdk-core (~> 3, >= 3.174.0) - aws-sigv4 (~> 1.1) - aws-sdk-s3 (1.126.0) - aws-sdk-core (~> 3, >= 3.174.0) + aws-sdk-kms (1.94.0) + aws-sdk-core (~> 3, >= 3.207.0) + aws-sigv4 (~> 1.5) + aws-sdk-s3 (1.166.0) + aws-sdk-core (~> 3, >= 3.207.0) aws-sdk-kms (~> 1) - aws-sigv4 (~> 1.4) - aws-sigv4 (1.5.2) + aws-sigv4 (~> 1.5) + aws-sigv4 (1.10.0) aws-eventstream (~> 1, >= 1.0.2) babosa (1.0.4) + base64 (0.2.0) + bigdecimal (3.1.8) claide (1.1.0) claide-plugins (0.9.2) cork nap open4 (~> 1.3) - cocoapods (1.12.1) + cocoapods (1.15.2) addressable (~> 2.8) claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.12.1) + cocoapods-core (= 1.15.2) cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.6.0, < 2.0) + cocoapods-downloader (>= 2.1, < 3.0) cocoapods-plugins (>= 1.0.0, < 2.0) cocoapods-search (>= 1.0.0, < 2.0) cocoapods-trunk (>= 1.6.0, < 2.0) @@ -54,8 +64,8 @@ GEM molinillo (~> 0.8.0) nap (~> 1.0) ruby-macho (>= 2.3.0, < 3.0) - xcodeproj (>= 1.21.0, < 2.0) - cocoapods-core (1.12.1) + xcodeproj (>= 1.23.0, < 2.0) + cocoapods-core (1.15.2) activesupport (>= 5.0, < 8) addressable (~> 2.8) algoliasearch (~> 1.0) @@ -66,7 +76,7 @@ GEM public_suffix (~> 4.0) typhoeus (~> 1.0) cocoapods-deintegrate (1.0.5) - cocoapods-downloader (1.6.3) + cocoapods-downloader (2.1) cocoapods-plugins (1.0.0) nap cocoapods-search (1.0.1) @@ -78,10 +88,11 @@ GEM colored2 (3.1.2) commander (4.6.0) highline (~> 2.0.0) - concurrent-ruby (1.2.2) + concurrent-ruby (1.3.4) + connection_pool (2.4.1) cork (0.3.0) colored2 (~> 3.1) - danger (9.3.1) + danger (9.5.0) claide (~> 1.0) claide-plugins (>= 0.9.2) colored2 (~> 3.1) @@ -91,30 +102,29 @@ GEM git (~> 1.13) kramdown (~> 2.3) kramdown-parser-gfm (~> 1.0) - no_proxy_fix - octokit (~> 6.0) + octokit (>= 4.0) terminal-table (>= 1, < 4) danger-plugin-api (1.0.0) danger (> 2.0) - danger-swiftlint (0.33.0) + danger-swiftlint (0.36.1) danger rake (> 10) - thor (~> 0.19) - danger-xcode_summary (1.2.0) + thor (~> 1.0.0) + danger-xcode_summary (1.3.1) danger-plugin-api (~> 1.0) - xcresult (~> 0.2) + xcresult (~> 0.2.2) declarative (0.0.20) - digest-crc (0.6.4) + digest-crc (0.6.5) rake (>= 12.0.0, < 14.0.0) - domain_name (0.5.20190701) - unf (>= 0.0.5, < 1.0.0) + domain_name (0.6.20240107) dotenv (2.8.1) + drb (2.2.1) emoji_regex (3.2.3) escape (0.0.4) ethon (0.16.0) ffi (>= 1.15.0) - excon (0.100.0) - faraday (1.10.3) + excon (0.111.0) + faraday (1.10.4) faraday-em_http (~> 1.0) faraday-em_synchrony (~> 1.0) faraday-excon (~> 1.1) @@ -132,27 +142,27 @@ GEM faraday-em_http (1.0.0) faraday-em_synchrony (1.0.0) faraday-excon (1.1.0) - faraday-http-cache (2.5.0) + faraday-http-cache (2.5.1) faraday (>= 0.8) faraday-httpclient (1.0.1) faraday-multipart (1.0.4) multipart-post (~> 2) - faraday-net_http (1.0.1) + faraday-net_http (1.0.2) faraday-net_http_persistent (1.2.0) faraday-patron (1.0.0) faraday-rack (1.0.0) faraday-retry (1.0.3) - faraday_middleware (1.2.0) + faraday_middleware (1.2.1) faraday (~> 1.0) - fastimage (2.2.7) - fastlane (2.213.0) + fastimage (2.3.1) + fastlane (2.223.1) CFPropertyList (>= 2.3, < 4.0.0) addressable (>= 2.8, < 3.0.0) artifactory (~> 3.0) aws-sdk-s3 (~> 1.0) babosa (>= 1.0.3, < 2.0.0) bundler (>= 1.12.0, < 3.0.0) - colored + colored (~> 1.2) commander (~> 4.6) dotenv (>= 2.1.1, < 3.0.0) emoji_regex (>= 0.1, < 4.0) @@ -164,36 +174,38 @@ GEM gh_inspector (>= 1.1.2, < 2.0.0) google-apis-androidpublisher_v3 (~> 0.3) google-apis-playcustomapp_v1 (~> 0.1) + google-cloud-env (>= 1.6.0, < 2.0.0) google-cloud-storage (~> 1.31) highline (~> 2.0) + http-cookie (~> 1.0.5) json (< 3.0.0) jwt (>= 2.1.0, < 3) mini_magick (>= 4.9.4, < 5.0.0) multipart-post (>= 2.0.0, < 3.0.0) naturally (~> 2.2) - optparse (~> 0.1.1) + optparse (>= 0.1.1, < 1.0.0) plist (>= 3.1.0, < 4.0.0) rubyzip (>= 2.0.0, < 3.0.0) - security (= 0.1.3) + security (= 0.1.5) simctl (~> 1.6.3) terminal-notifier (>= 2.0.0, < 3.0.0) - terminal-table (>= 1.4.5, < 2.0.0) + terminal-table (~> 3) tty-screen (>= 0.6.3, < 1.0.0) tty-spinner (>= 0.8.0, < 1.0.0) word_wrap (~> 1.0.0) xcodeproj (>= 1.13.0, < 2.0.0) xcpretty (~> 0.3.0) - xcpretty-travis-formatter (>= 0.0.3) - ffi (1.15.5) + xcpretty-travis-formatter (>= 0.0.3, < 2.0.0) + ffi (1.17.0) fourflusher (2.3.1) fuzzy_match (2.0.4) gh_inspector (1.1.3) - git (1.18.0) + git (1.19.1) addressable (~> 2.8) rchardet (~> 1.8) - google-apis-androidpublisher_v3 (0.44.0) + google-apis-androidpublisher_v3 (0.54.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-core (0.11.0) + google-apis-core (0.11.3) addressable (~> 2.5, >= 2.5.1) googleauth (>= 0.16.2, < 2.a) httpclient (>= 2.8.1, < 3.a) @@ -201,75 +213,74 @@ GEM representable (~> 3.0) retriable (>= 2.0, < 4.a) rexml - webrick google-apis-iamcredentials_v1 (0.17.0) google-apis-core (>= 0.11.0, < 2.a) google-apis-playcustomapp_v1 (0.13.0) google-apis-core (>= 0.11.0, < 2.a) - google-apis-storage_v1 (0.19.0) - google-apis-core (>= 0.9.0, < 2.a) - google-cloud-core (1.6.0) - google-cloud-env (~> 1.0) + google-apis-storage_v1 (0.31.0) + google-apis-core (>= 0.11.0, < 2.a) + google-cloud-core (1.7.1) + google-cloud-env (>= 1.0, < 3.a) google-cloud-errors (~> 1.0) google-cloud-env (1.6.0) faraday (>= 0.17.3, < 3.0) - google-cloud-errors (1.3.1) - google-cloud-storage (1.44.0) + google-cloud-errors (1.4.0) + google-cloud-storage (1.47.0) addressable (~> 2.8) digest-crc (~> 0.4) google-apis-iamcredentials_v1 (~> 0.1) - google-apis-storage_v1 (~> 0.19.0) + google-apis-storage_v1 (~> 0.31.0) google-cloud-core (~> 1.6) googleauth (>= 0.16.2, < 2.a) mini_mime (~> 1.0) - googleauth (1.5.2) + googleauth (1.8.1) faraday (>= 0.17.3, < 3.a) jwt (>= 1.4, < 3.0) - memoist (~> 0.16) multi_json (~> 1.11) os (>= 0.9, < 2.0) signet (>= 0.16, < 2.a) highline (2.0.3) - http-cookie (1.0.5) + http-cookie (1.0.7) domain_name (~> 0.5) httpclient (2.8.3) - i18n (1.14.1) + i18n (1.14.6) concurrent-ruby (~> 1.0) jmespath (1.6.2) - json (2.6.3) - jwt (2.7.1) + json (2.7.2) + jwt (2.9.1) + base64 kramdown (2.4.0) rexml kramdown-parser-gfm (1.1.0) kramdown (~> 2.0) - memoist (0.16.2) - mini_magick (4.12.0) - mini_mime (1.1.2) - minitest (5.18.1) + logger (1.6.1) + mini_magick (4.13.2) + mini_mime (1.1.5) + minitest (5.25.1) molinillo (0.8.0) multi_json (1.15.0) - multipart-post (2.3.0) + multipart-post (2.4.1) nanaimo (0.3.0) nap (1.1.0) naturally (2.2.1) netrc (0.11.0) - no_proxy_fix (0.1.2) - octokit (6.1.1) + nkf (0.2.0) + octokit (9.1.0) faraday (>= 1, < 3) sawyer (~> 0.9) open4 (1.3.4) - optparse (0.1.1) + optparse (0.5.0) os (1.1.4) - plist (3.7.0) + plist (3.7.1) public_suffix (4.0.7) - rake (13.0.6) + rake (13.2.1) rchardet (1.8.0) representable (3.2.0) declarative (< 0.1.0) trailblazer-option (>= 0.1.1, < 0.2.0) uber (< 0.2.0) retriable (3.1.2) - rexml (3.2.5) + rexml (3.3.8) rouge (2.0.7) ruby-macho (2.5.1) ruby2_keywords (0.0.5) @@ -277,8 +288,9 @@ GEM sawyer (0.9.2) addressable (>= 2.3.5) faraday (>= 0.17.3, < 3) - security (0.1.3) - signet (0.17.0) + securerandom (0.3.1) + security (0.1.5) + signet (0.19.0) addressable (~> 2.8) faraday (>= 0.17.5, < 3.a) jwt (>= 1.5, < 3.0) @@ -287,42 +299,38 @@ GEM CFPropertyList naturally terminal-notifier (2.0.0) - terminal-table (1.8.0) - unicode-display_width (~> 1.1, >= 1.1.1) - thor (0.20.3) + terminal-table (3.0.2) + unicode-display_width (>= 1.1.1, < 3) + thor (1.0.1) trailblazer-option (0.1.2) tty-cursor (0.7.1) - tty-screen (0.8.1) + tty-screen (0.8.2) tty-spinner (0.9.3) tty-cursor (~> 0.7) - typhoeus (1.4.0) + typhoeus (1.4.1) ethon (>= 0.9.0) tzinfo (2.0.6) concurrent-ruby (~> 1.0) uber (0.1.0) - unf (0.1.4) - unf_ext - unf_ext (0.0.8.2) - unicode-display_width (1.8.0) - webrick (1.8.1) + unicode-display_width (2.6.0) word_wrap (1.0.0) xcode-install (2.8.1) claide (>= 0.9.1) fastlane (>= 2.1.0, < 3.0.0) - xcodeproj (1.22.0) + xcodeproj (1.25.0) CFPropertyList (>= 2.3.3, < 4.0) atomos (~> 0.1.3) claide (>= 1.0.2, < 2.0) colored2 (~> 3.1) nanaimo (~> 0.3.0) - rexml (~> 3.2.4) + rexml (>= 3.3.2, < 4.0) xcpretty (0.3.0) rouge (~> 2.0.7) xcpretty-json-formatter (0.1.1) xcpretty (~> 0.2, >= 0.0.7) xcpretty-travis-formatter (1.0.1) xcpretty (~> 0.2, >= 0.0.7) - xcresult (0.2.1) + xcresult (0.2.2) PLATFORMS ruby