From 52751dc80126341fb8c50f2bdf5e6f6e9bfa422b Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Sun, 24 Jul 2022 15:25:28 +0300 Subject: [PATCH 01/17] feat: added initial alerts factory implementation --- .../Alerts/Factories/AlertFactory.swift | 83 +++++++++++++++++++ .../Helpers/AlertDescriptor+Helpers.swift | 43 ++++++++++ .../UIAlertController+AlertPresentable.swift | 46 ++++++++++ .../Sources/Alerts/Helpers/View+Helpers.swift | 53 ++++++++++++ .../Sources/Alerts/Models/AlertAction.swift | 61 ++++++++++++++ .../Alerts/Models/AlertDescriptor.swift | 55 ++++++++++++ .../Alerts/Protocols/AlertPresentable.swift | 28 +++++++ .../Protocols/PresentationContext.swift | 27 ++++++ .../Alerts/Protocols/SwiftUIContext.swift | 43 ++++++++++ .../Alerts/Protocols/UIKitContext.swift | 25 ++++++ 10 files changed, 464 insertions(+) create mode 100644 TIUIElements/Sources/Alerts/Factories/AlertFactory.swift create mode 100644 TIUIElements/Sources/Alerts/Helpers/AlertDescriptor+Helpers.swift create mode 100644 TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift create mode 100644 TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift create mode 100644 TIUIElements/Sources/Alerts/Models/AlertAction.swift create mode 100644 TIUIElements/Sources/Alerts/Models/AlertDescriptor.swift create mode 100644 TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift create mode 100644 TIUIElements/Sources/Alerts/Protocols/PresentationContext.swift create mode 100644 TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift create mode 100644 TIUIElements/Sources/Alerts/Protocols/UIKitContext.swift diff --git a/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift b/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift new file mode 100644 index 00000000..37f7ac96 --- /dev/null +++ b/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift @@ -0,0 +1,83 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import TISwiftUtils +import UIKit + +open class AlertFactory { + + open class func alert(title: String? = nil, + message: String? = nil, + tint: UIColor = .systemBlue, + actions: [AlertAction]) -> AlertDescriptor { + + return AlertDescriptor(title: title, + message: message, + style: .alert, + tintColor: tint, + actions: actions) + } + + open class func sheetAlert(title: String? = nil, + message: String? = nil, + tint: UIColor = .systemBlue, + actions: [AlertAction]) -> AlertDescriptor { + + return AlertDescriptor(title: title, + message: message, + style: .actionSheet, + tintColor: tint, + actions: actions) + } + + open class func okAlert(title: String? = nil, + message: String? = nil, + tint: UIColor = .systemBlue) -> AlertDescriptor { + AlertDescriptor(title: title, + message: message, + style: .alert, + tintColor: tint, + actions: [.okAction]) + } + + open class func retryAlert(title: String? = nil, + message: String? = nil, + cancelTitle: String = "Cancel", + tint: UIColor = .systemBlue, + retryAction: VoidClosure? = nil) -> AlertDescriptor { + AlertDescriptor(title: title, + message: message, + tintColor: tint, + actions: [.cancelAction(cancelTitle), + AlertAction(title: "Retry", action: retryAction)]) + } +} + +private extension AlertAction { + static var okAction: AlertAction { + AlertAction(title: "Ok", action: {}) + } + + static func cancelAction(_ title: String = "Cancel") -> AlertAction { + AlertAction(title: title, style: .cancel, action: {}) + } +} diff --git a/TIUIElements/Sources/Alerts/Helpers/AlertDescriptor+Helpers.swift b/TIUIElements/Sources/Alerts/Helpers/AlertDescriptor+Helpers.swift new file mode 100644 index 00000000..9166ea38 --- /dev/null +++ b/TIUIElements/Sources/Alerts/Helpers/AlertDescriptor+Helpers.swift @@ -0,0 +1,43 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import TISwiftUtils +import UIKit + +extension AlertDescriptor { + public func present(on context: PresentationContext, completion: VoidClosure? = nil) { + let alertFactory: Closure = { configuration in + UIAlertController(title: configuration.title, + message: configuration.message, + preferredStyle: configuration.style) + .configured(with: configuration) + } + + present(on: context, alertViewFactory: alertFactory, completion: completion) + } + + public func present(on context: PresentationContext, + alertViewFactory: Closure, + completion: VoidClosure? = nil) { + alertViewFactory(self).present(on: context, completion: completion) + } +} diff --git a/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift b/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift new file mode 100644 index 00000000..789c778a --- /dev/null +++ b/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift @@ -0,0 +1,46 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import TISwiftUtils +import UIKit + +extension UIAlertController { + + @discardableResult + public func configured(with configuration: AlertDescriptor) -> Self { + title = configuration.title + message = configuration.message + view.tintColor = configuration.tintColor + + for action in configuration.actions { + addAction(action.asUIAlertAction) + } + + return self + } +} + +extension UIAlertController: AlertPresentable { + public func present(on context: PresentationContext, completion: VoidClosure?) { + context.present(self, animated: true, completion: completion) + } +} diff --git a/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift b/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift new file mode 100644 index 00000000..b7184e68 --- /dev/null +++ b/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift @@ -0,0 +1,53 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import TISwiftUtils +import SwiftUI + +@available(iOS 13.0, *) +public extension View { + func alert(isPresented: Binding, + on context: PresentationContext, + alert: AlertDescriptor) -> some View { + + if isPresented.wrappedValue { + alert.present(on: context) { + isPresented.wrappedValue = false + } + } + + return self + } + + func alert(isPresented: Binding, + on context: PresentationContext, + alertViewFactory: ResultClosure) -> some View { + + if isPresented.wrappedValue { + alertViewFactory().present(on: context) { + isPresented.wrappedValue = false + } + } + + return self + } +} diff --git a/TIUIElements/Sources/Alerts/Models/AlertAction.swift b/TIUIElements/Sources/Alerts/Models/AlertAction.swift new file mode 100644 index 00000000..ef6f43ca --- /dev/null +++ b/TIUIElements/Sources/Alerts/Models/AlertAction.swift @@ -0,0 +1,61 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import TISwiftUtils +import UIKit + +// struct describe alert button information +public struct AlertAction: Identifiable { + + public let id = UUID() + + /// Alert button title + public let title: String + + /// Alert button style + public let style: UIAlertAction.Style + + /// Alert button action + public let action: VoidClosure? + + init(title: String, style: UIAlertAction.Style = .default, action: VoidClosure? = nil) { + self.title = title + self.style = style + self.action = action + } +} + +// MARK: - AlertAction + Equatable + +extension AlertAction: Equatable { + public static func == (lhs: AlertAction, rhs: AlertAction) -> Bool { + return false + } +} + +// MARK: - AlertAction + Helpers + +extension AlertAction { + var asUIAlertAction: UIAlertAction { + UIAlertAction(title: title, style: style, handler: { _ in action?() }) + } +} diff --git a/TIUIElements/Sources/Alerts/Models/AlertDescriptor.swift b/TIUIElements/Sources/Alerts/Models/AlertDescriptor.swift new file mode 100644 index 00000000..cd07687c --- /dev/null +++ b/TIUIElements/Sources/Alerts/Models/AlertDescriptor.swift @@ -0,0 +1,55 @@ +// +// Copyright (c) 2021 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import UIKit + +/// Struct describes alert data +public struct AlertDescriptor { + + /// Alert title + public let title: String? + + /// Alert message + public let message: String? + + /// Alert style + public let style: UIAlertController.Style + + /// Alert tint color + public let tintColor: UIColor + + /// Alert actions + public let actions: [AlertAction] + + public init(title: String? = nil, + message: String? = nil, + style: UIAlertController.Style = .alert, + tintColor: UIColor = .systemBlue, + actions: [AlertAction] = []) { + + self.title = title + self.message = message + self.style = style + self.tintColor = tintColor + self.actions = actions + } +} diff --git a/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift b/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift new file mode 100644 index 00000000..9e8c3488 --- /dev/null +++ b/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift @@ -0,0 +1,28 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import TISwiftUtils +import Foundation + +public protocol AlertPresentable { + func present(on context: PresentationContext, completion: VoidClosure?) +} diff --git a/TIUIElements/Sources/Alerts/Protocols/PresentationContext.swift b/TIUIElements/Sources/Alerts/Protocols/PresentationContext.swift new file mode 100644 index 00000000..caf5028b --- /dev/null +++ b/TIUIElements/Sources/Alerts/Protocols/PresentationContext.swift @@ -0,0 +1,27 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import UIKit + +public protocol PresentationContext { + func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) +} diff --git a/TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift b/TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift new file mode 100644 index 00000000..9a812b63 --- /dev/null +++ b/TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift @@ -0,0 +1,43 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import SwiftUI + +@available(iOS 13, *) +public protocol SwiftUIContext: PresentationContext { + var presentedViewController: UIViewController? { get } +} + +@available(iOS 13, *) +extension SwiftUIContext { + var presentedViewController: UIViewController? { + UIApplication.shared.windows.first?.rootViewController?.presentedViewController + } + + func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) { + guard let viewController = presentedViewController else { + return + } + + viewController.present(viewControllerToPresent, animated: flag, completion: completion) + } +} diff --git a/TIUIElements/Sources/Alerts/Protocols/UIKitContext.swift b/TIUIElements/Sources/Alerts/Protocols/UIKitContext.swift new file mode 100644 index 00000000..5958824a --- /dev/null +++ b/TIUIElements/Sources/Alerts/Protocols/UIKitContext.swift @@ -0,0 +1,25 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import UIKit + +public protocol UIKitContext: PresentationContext { } From 000e88f98af234fc196ac9aff2a8e055b2eb4ccd Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Sun, 24 Jul 2022 15:34:09 +0300 Subject: [PATCH 02/17] fix: small access control fixes --- TIUIElements/Sources/Alerts/Models/AlertAction.swift | 2 +- TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/TIUIElements/Sources/Alerts/Models/AlertAction.swift b/TIUIElements/Sources/Alerts/Models/AlertAction.swift index ef6f43ca..ce2a92a0 100644 --- a/TIUIElements/Sources/Alerts/Models/AlertAction.swift +++ b/TIUIElements/Sources/Alerts/Models/AlertAction.swift @@ -37,7 +37,7 @@ public struct AlertAction: Identifiable { /// Alert button action public let action: VoidClosure? - init(title: String, style: UIAlertAction.Style = .default, action: VoidClosure? = nil) { + public init(title: String, style: UIAlertAction.Style = .default, action: VoidClosure? = nil) { self.title = title self.style = style self.action = action diff --git a/TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift b/TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift index 9a812b63..7c998fc0 100644 --- a/TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift +++ b/TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift @@ -28,7 +28,7 @@ public protocol SwiftUIContext: PresentationContext { } @available(iOS 13, *) -extension SwiftUIContext { +public extension SwiftUIContext { var presentedViewController: UIViewController? { UIApplication.shared.windows.first?.rootViewController?.presentedViewController } From c223a026f26fd02bf124e90d86397777c204928c Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Mon, 25 Jul 2022 14:08:01 +0300 Subject: [PATCH 03/17] fix: custom alerts configuration for sui + version control changes --- TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift | 5 +++-- TIUIElements/Sources/Alerts/Models/AlertAction.swift | 7 ++++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift b/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift index b7184e68..2327e244 100644 --- a/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift +++ b/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift @@ -40,10 +40,11 @@ public extension View { func alert(isPresented: Binding, on context: PresentationContext, - alertViewFactory: ResultClosure) -> some View { + alertDescriptor descriptor: AlertDescriptor, + alertViewFactory: Closure) -> some View { if isPresented.wrappedValue { - alertViewFactory().present(on: context) { + alertViewFactory(descriptor).present(on: context) { isPresented.wrappedValue = false } } diff --git a/TIUIElements/Sources/Alerts/Models/AlertAction.swift b/TIUIElements/Sources/Alerts/Models/AlertAction.swift index ce2a92a0..229d3f0a 100644 --- a/TIUIElements/Sources/Alerts/Models/AlertAction.swift +++ b/TIUIElements/Sources/Alerts/Models/AlertAction.swift @@ -24,7 +24,7 @@ import TISwiftUtils import UIKit // struct describe alert button information -public struct AlertAction: Identifiable { +public struct AlertAction { public let id = UUID() @@ -52,6 +52,11 @@ extension AlertAction: Equatable { } } +// MARK: - AlertAction + Identifiable + +@available(iOS 13, *) +extension AlertAction: Identifiable { } + // MARK: - AlertAction + Helpers extension AlertAction { From 37b722426415ca459110fae9f5e11abdd73fa619 Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Mon, 25 Jul 2022 15:34:04 +0300 Subject: [PATCH 04/17] feat: added default localization provider for actions + documentation added --- .../Alerts/Factories/AlertFactory.swift | 135 +++++++++++++----- .../UIAlertController+AlertPresentable.swift | 2 +- .../Sources/Alerts/Helpers/View+Helpers.swift | 14 +- .../Sources/Alerts/Models/AlertAction.swift | 2 +- .../Alerts/Models/AlertDescriptor.swift | 2 +- .../DefaultAlertLocalizationProvider.swift | 53 +++++++ .../Protocols/AlertLocalizationProvider.swift | 29 ++++ 7 files changed, 196 insertions(+), 41 deletions(-) create mode 100644 TIUIElements/Sources/Alerts/Models/DefaultAlertLocalizationProvider.swift create mode 100644 TIUIElements/Sources/Alerts/Protocols/AlertLocalizationProvider.swift diff --git a/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift b/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift index 37f7ac96..6f5d88b6 100644 --- a/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift +++ b/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift @@ -25,59 +25,120 @@ import UIKit open class AlertFactory { - open class func alert(title: String? = nil, - message: String? = nil, - tint: UIColor = .systemBlue, - actions: [AlertAction]) -> AlertDescriptor { + public var localizationProvider: AlertLocalizationProvider - return AlertDescriptor(title: title, - message: message, - style: .alert, - tintColor: tint, - actions: actions) + public init(localizationProvider: AlertLocalizationProvider = DefaultAlertLocalizationProvider()) { + self.localizationProvider = localizationProvider } - open class func sheetAlert(title: String? = nil, - message: String? = nil, - tint: UIColor = .systemBlue, - actions: [AlertAction]) -> AlertDescriptor { + /// Provides general alert description. + /// - Parameters: + /// - title: A text string used as the title of the alert. + /// - message: A text string used as the message of the alert. + /// - tint: A color used as a tint color of the alert. Default color is UIColor.systemBlue. + /// - actions: An array of actions of the alert. + /// - Returns: Alert descriptor, which can be used to present alert view. + open func alert(title: String? = nil, + message: String? = nil, + tint: UIColor = .systemBlue, + actions: [AlertAction]) -> AlertDescriptor { - return AlertDescriptor(title: title, - message: message, - style: .actionSheet, - tintColor: tint, - actions: actions) + AlertDescriptor(title: title, + message: message, + tintColor: tint, + actions: actions) } - open class func okAlert(title: String? = nil, + /// Provides general sheet alert description. + /// - Parameters: + /// - title: A text string used as the title of the sheet alert. + /// - message: A text string used as the message of the sheet alert. + /// - tint: A color used as a tint color of the sheet alert. Default color is UIColor.systemBlue. + /// - actions: An array of actions of the sheet alert. + /// - Returns: Alert descriptor, which can be used to present sheet alert view. + open func sheetAlert(title: String? = nil, + message: String? = nil, + tint: UIColor = .systemBlue, + actions: [AlertAction]) -> AlertDescriptor { + + AlertDescriptor(title: title, + message: message, + style: .actionSheet, + tintColor: tint, + actions: actions) + } + + /// Provides ok type alert description. + /// - Parameters: + /// - title: A text string used as the title of the alert. + /// - message: A text string used as the message of the alert. + /// - tint: A color used as a tint color of the alert. Default color is UIColor.systemBlue. + /// - Returns: Alert descriptor, which can be used to present alert view. + open func okAlert(title: String? = nil, + message: String? = nil, + tint: UIColor = .systemBlue) -> AlertDescriptor { + + AlertDescriptor(title: title, + message: message, + tintColor: tint, + actions: [.simpleAction(localizationProvider.okTitle)]) + } + + /// Provides retry type alert description. + /// - Parameters: + /// - title: A text string used as the title of the alert. + /// - message: A text string used as the message of the alert. + /// - tint: A color used as a tint color of the alert. Default color is UIColor.systemBlue. + /// - retryAction: A closure called by tapping on the retry button of the alert. + /// - Returns: Alert descriptor, which can be used to present alert view. + open func retryAlert(title: String? = nil, + message: String? = nil, + tint: UIColor = .systemBlue, + retryAction: VoidClosure? = nil) -> AlertDescriptor { + + AlertDescriptor(title: title, + message: message, + tintColor: tint, + actions: [ + .cancelAction(localizationProvider.cancelTitle), + .init(title: localizationProvider.retryTitle, action: retryAction) + ]) + } + + /// Provides dialogue type alert description. Dialogue type alert containes to buttons: Yes and No. + /// - Parameters: + /// - title: A text string used as the title of the alert. + /// - message: A text string used as the message of the alert. + /// - tint: A color used as a tint color of the alert. Default color is UIColor.systemBlue. + /// - yesAction: A closure called by tapping on the yes button of the alert. + /// - noAction: A closure called by tapping on the no button of the alert. + /// - Returns: Alert descriptor, which can be used to present alert view. + open func dialogueAlert(title: String? = nil, message: String? = nil, - tint: UIColor = .systemBlue) -> AlertDescriptor { - AlertDescriptor(title: title, - message: message, - style: .alert, - tintColor: tint, - actions: [.okAction]) - } + tint: UIColor = .systemBlue, + yesAction: VoidClosure? = nil, + noAction: VoidClosure? = nil) -> AlertDescriptor { - open class func retryAlert(title: String? = nil, - message: String? = nil, - cancelTitle: String = "Cancel", - tint: UIColor = .systemBlue, - retryAction: VoidClosure? = nil) -> AlertDescriptor { AlertDescriptor(title: title, message: message, tintColor: tint, - actions: [.cancelAction(cancelTitle), - AlertAction(title: "Retry", action: retryAction)]) + actions: [ + .init(title: localizationProvider.yesTitle, style: .destructive, action: yesAction), + .init(title: localizationProvider.noTitle, action: noAction) + ]) } } +// MARK: - AlertAction + Helpers + private extension AlertAction { - static var okAction: AlertAction { - AlertAction(title: "Ok", action: {}) + static func simpleAction(_ title: String, + style: UIAlertAction.Style = .default) -> AlertAction { + + AlertAction(title: title, style: style, action: nil) } - static func cancelAction(_ title: String = "Cancel") -> AlertAction { - AlertAction(title: title, style: .cancel, action: {}) + static func cancelAction(_ title: String) -> AlertAction { + .simpleAction(title, style: .cancel) } } diff --git a/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift b/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift index 789c778a..4a718c09 100644 --- a/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift +++ b/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2021 Touch Instinct +// Copyright (c) 2022 Touch Instinct // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the Software), to deal diff --git a/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift b/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift index 2327e244..6af75ec1 100644 --- a/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift +++ b/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2021 Touch Instinct +// Copyright (c) 2022 Touch Instinct // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the Software), to deal @@ -25,6 +25,12 @@ import SwiftUI @available(iOS 13.0, *) public extension View { + + /// Presents an alert with a description on a context when a given condition is true. + /// - Parameters: + /// - isPresented: A binding to a Boolean value that determines whether to present the alert. When the user presses or taps one of the alert’s actions, the system sets this value to false and dismisses. + /// - context: The view that will show the alert + /// - alert: Descriptor of the alert. func alert(isPresented: Binding, on context: PresentationContext, alert: AlertDescriptor) -> some View { @@ -38,6 +44,12 @@ public extension View { return self } + /// Presents an alert with a description on a context with custom configuration of the alert when a given condition is true. + /// - Parameters: + /// - isPresented: A binding to a Boolean value that determines whether to present the alert. When the user presses or taps one of the alert’s actions, the system sets this value to false and dismisses. + /// - context: The view that will show the alert + /// - descriptor: Descriptor of the alert. + /// - alertViewFactory: A closure called to configure custom alert. func alert(isPresented: Binding, on context: PresentationContext, alertDescriptor descriptor: AlertDescriptor, diff --git a/TIUIElements/Sources/Alerts/Models/AlertAction.swift b/TIUIElements/Sources/Alerts/Models/AlertAction.swift index 229d3f0a..c90b8996 100644 --- a/TIUIElements/Sources/Alerts/Models/AlertAction.swift +++ b/TIUIElements/Sources/Alerts/Models/AlertAction.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2021 Touch Instinct +// Copyright (c) 2022 Touch Instinct // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the Software), to deal diff --git a/TIUIElements/Sources/Alerts/Models/AlertDescriptor.swift b/TIUIElements/Sources/Alerts/Models/AlertDescriptor.swift index cd07687c..2efb8190 100644 --- a/TIUIElements/Sources/Alerts/Models/AlertDescriptor.swift +++ b/TIUIElements/Sources/Alerts/Models/AlertDescriptor.swift @@ -1,5 +1,5 @@ // -// Copyright (c) 2021 Touch Instinct +// Copyright (c) 2022 Touch Instinct // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the Software), to deal diff --git a/TIUIElements/Sources/Alerts/Models/DefaultAlertLocalizationProvider.swift b/TIUIElements/Sources/Alerts/Models/DefaultAlertLocalizationProvider.swift new file mode 100644 index 00000000..a1a7084c --- /dev/null +++ b/TIUIElements/Sources/Alerts/Models/DefaultAlertLocalizationProvider.swift @@ -0,0 +1,53 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import Foundation + +/// Provide default localization for alerts' buttons +open class DefaultAlertLocalizationProvider: AlertLocalizationProvider { + + public private(set) var bundle: Bundle + + public init(bundle: Bundle = .main) { + self.bundle = bundle + } + + open var okTitle: String { + bundle.localizedString(forKey: "common_ok", value: "Ок", table: nil) + } + + open var cancelTitle: String { + bundle.localizedString(forKey: "common_cancel", value: "Отмена", table: nil) + } + + open var retryTitle: String { + bundle.localizedString(forKey: "common_retry", value: "Повторить", table: nil) + } + + open var yesTitle: String { + bundle.localizedString(forKey: "common_yes", value: "Да", table: nil) + } + + open var noTitle: String { + bundle.localizedString(forKey: "common_no", value: "Нет", table: nil) + } +} diff --git a/TIUIElements/Sources/Alerts/Protocols/AlertLocalizationProvider.swift b/TIUIElements/Sources/Alerts/Protocols/AlertLocalizationProvider.swift new file mode 100644 index 00000000..98795b27 --- /dev/null +++ b/TIUIElements/Sources/Alerts/Protocols/AlertLocalizationProvider.swift @@ -0,0 +1,29 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +public protocol AlertLocalizationProvider { + var okTitle: String { get } + var cancelTitle: String { get } + var retryTitle: String { get } + var yesTitle: String { get } + var noTitle: String { get } +} From b96478c248d0773f0e9cd97903cf1d1bc61098a2 Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Mon, 25 Jul 2022 15:53:38 +0300 Subject: [PATCH 05/17] fix: dialogue type alert actions' styles --- TIUIElements/Sources/Alerts/Factories/AlertFactory.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift b/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift index 6f5d88b6..79c62efc 100644 --- a/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift +++ b/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift @@ -123,8 +123,8 @@ open class AlertFactory { message: message, tintColor: tint, actions: [ - .init(title: localizationProvider.yesTitle, style: .destructive, action: yesAction), - .init(title: localizationProvider.noTitle, action: noAction) + .init(title: localizationProvider.yesTitle, action: yesAction), + .init(title: localizationProvider.noTitle, style: .destructive, action: noAction) ]) } } From 24d1384e0f464638b8c24440a139f73a7ae94e62 Mon Sep 17 00:00:00 2001 From: Nikita Semenov <69932531+castlele@users.noreply.github.com> Date: Mon, 25 Jul 2022 16:36:32 +0300 Subject: [PATCH 06/17] doc: implement documentation for alerts api --- TIUIElements/README.md | 76 +++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) diff --git a/TIUIElements/README.md b/TIUIElements/README.md index 0bafa5af..91e83ced 100644 --- a/TIUIElements/README.md +++ b/TIUIElements/README.md @@ -126,7 +126,81 @@ class ViewController: UITableViewController, CollapsibleViewsContainer {

- + +# AlertsFactory +Use to present alerts in a few lines of code. Can be used for UIKit and SwiftUI +> You can initialize `AlertsFactory` with your own *LocalizationProvider* or use `DefaultAlertLocalizationProvider` + +## Your view or view controller must implement PresentationContext protocol +There are `UIKitContext` and `SwiftUIContext` protocols that are designed to make it easier to work with `PresentationContext` protocol. By default, no changes need to be made for UIKit view controllers and SwiftUI views to make them conform to these protocols + +## Custom alerts +```swift +// Presents alert +func presentAlert() { + factory + .alert(title: "Alert's title", + message: "Alert's message", + tint: .systemBlue, + actions: [ + AlertAction(title: "Ok", style: .default, action: nil), + AlertAction(title: "Cancel", style: .cancel, action: nil) + ]) + .present(on: self) +} + +// Presents sheet alert +func presentSheetAlert() { + factory + .sheetAlert(title: "Alert's title", + message: "Alert's message", + tint: .systemBlue, + actions: [ + AlertAction(title: "Ok", style: .default, action: nil), + AlertAction(title: "Cancel", style: .cancel, action: nil) + ]) + .present(on: self) +} +``` + +## Default alerts +```swift +// Ok alert +func presentOkAlert() { + factory + .okAlert(title: "Title", message: "Message") + .present(on: self) +} + +// Retry alert +func presentRetryAlert() { + factory + .retryAlert(title: "Title", message: "Message") { [weak self] in + self?.presentOkAlert() + } + .present(on: self) +} + +// Dialogue alert +func presentDialogueAlert() { + factory + .dialogueAlert(title: "Title", message: "Message") + .present(on: self) +} +``` + +## SwiftUI alerts +```swift +var body: some View { + Button("Show custom alert with binding property") { + alertDescription = factory.okAlert(title: "Title", message: "Message") + isPresentedCustomAlert = true + } + } + .alert(isPresented: $isPresentedAlert, on: self, alert: alertDescription) +} +``` + # Installation via SPM You can install this framework as a target of LeadKit. From 693843bb70e76856ac2806f2a7369f5e0099874e Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Mon, 25 Jul 2022 19:01:55 +0300 Subject: [PATCH 07/17] fix: code review notes --- CHANGELOG.md | 4 ++++ LeadKit.podspec | 2 +- TIAppleMapUtils/TIAppleMapUtils.podspec | 2 +- TIAuth/TIAuth.podspec | 2 +- TIFoundationUtils/TIFoundationUtils.podspec | 2 +- TIGoogleMapUtils/TIGoogleMapUtils.podspec | 2 +- TIKeychainUtils/TIKeychainUtils.podspec | 2 +- TIMapUtils/TIMapUtils.podspec | 2 +- TIMoyaNetworking/TIMoyaNetworking.podspec | 2 +- TINetworking/TINetworking.podspec | 2 +- TINetworkingCache/TINetworkingCache.podspec | 2 +- TIPagination/TIPagination.podspec | 2 +- TISwiftUICore/TISwiftUICore.podspec | 2 +- TISwiftUtils/TISwiftUtils.podspec | 2 +- TITableKitUtils/TITableKitUtils.podspec | 2 +- TITransitions/TITransitions.podspec | 2 +- TIUIElements/README.md | 2 +- .../Alerts/Factories/AlertFactory.swift | 1 - .../Helpers/AlertDescriptor+Helpers.swift | 6 +++--- .../UIAlertController+AlertPresentable.swift | 8 ++++---- .../Sources/Alerts/Helpers/View+Helpers.swift | 4 ++-- .../DefaultAlertLocalizationProvider.swift | 2 +- .../Alerts/Protocols/AlertPresentable.swift | 2 +- ...t.swift => AlertPresentationContext.swift} | 5 +++-- ...ontext.swift => SwiftUIAlertContext.swift} | 19 ++++++------------- ...tContext.swift => UIKitAlertContext.swift} | 2 +- TIUIElements/TIUIElements.podspec | 2 +- TIUIKitCore/TIUIKitCore.podspec | 2 +- TIYandexMapUtils/TIYandexMapUtils.podspec | 2 +- 29 files changed, 44 insertions(+), 47 deletions(-) rename TIUIElements/Sources/Alerts/Protocols/{PresentationContext.swift => AlertPresentationContext.swift} (91%) rename TIUIElements/Sources/Alerts/Protocols/{SwiftUIContext.swift => SwiftUIAlertContext.swift} (70%) rename TIUIElements/Sources/Alerts/Protocols/{UIKitContext.swift => UIKitAlertContext.swift} (94%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 86e1929f..b9477b9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +### 1.24.0 + +- **Add**: `AlertFactory` for presenting alerts in SwiftUI and UIKit. + ### 1.22.0 - **Update**: Asynchronous request preprocessing diff --git a/LeadKit.podspec b/LeadKit.podspec index 4d42224b..cb70b7b8 100644 --- a/LeadKit.podspec +++ b/LeadKit.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "LeadKit" - s.version = "1.22.0" + s.version = "1.24.0" s.summary = "iOS framework with a bunch of tools for rapid development" s.homepage = "https://github.com/TouchInstinct/LeadKit" s.license = "Apache License, Version 2.0" diff --git a/TIAppleMapUtils/TIAppleMapUtils.podspec b/TIAppleMapUtils/TIAppleMapUtils.podspec index 59ba157b..b3f84580 100644 --- a/TIAppleMapUtils/TIAppleMapUtils.podspec +++ b/TIAppleMapUtils/TIAppleMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIAppleMapUtils' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Set of helpers for map objects clustering and interacting using Apple MapKit.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIAuth/TIAuth.podspec b/TIAuth/TIAuth.podspec index 3266d6e5..9bc961f6 100644 --- a/TIAuth/TIAuth.podspec +++ b/TIAuth/TIAuth.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIAuth' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Login, registration, confirmation and other related actions' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIFoundationUtils/TIFoundationUtils.podspec b/TIFoundationUtils/TIFoundationUtils.podspec index 07b02a63..39fd763a 100644 --- a/TIFoundationUtils/TIFoundationUtils.podspec +++ b/TIFoundationUtils/TIFoundationUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIFoundationUtils' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Set of helpers for Foundation framework classes.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIGoogleMapUtils/TIGoogleMapUtils.podspec b/TIGoogleMapUtils/TIGoogleMapUtils.podspec index ea5456a5..68ad58e9 100644 --- a/TIGoogleMapUtils/TIGoogleMapUtils.podspec +++ b/TIGoogleMapUtils/TIGoogleMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIGoogleMapUtils' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Set of helpers for map objects clustering and interacting using Google Maps SDK.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIKeychainUtils/TIKeychainUtils.podspec b/TIKeychainUtils/TIKeychainUtils.podspec index d099e240..f68e2a3b 100644 --- a/TIKeychainUtils/TIKeychainUtils.podspec +++ b/TIKeychainUtils/TIKeychainUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIKeychainUtils' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Set of helpers for Keychain classes.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIMapUtils/TIMapUtils.podspec b/TIMapUtils/TIMapUtils.podspec index ef157380..29fb1077 100644 --- a/TIMapUtils/TIMapUtils.podspec +++ b/TIMapUtils/TIMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIMapUtils' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Set of helpers for map objects clustering and interacting.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIMoyaNetworking/TIMoyaNetworking.podspec b/TIMoyaNetworking/TIMoyaNetworking.podspec index d4061461..9ceeffb5 100644 --- a/TIMoyaNetworking/TIMoyaNetworking.podspec +++ b/TIMoyaNetworking/TIMoyaNetworking.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIMoyaNetworking' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Moya + Swagger network service.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TINetworking/TINetworking.podspec b/TINetworking/TINetworking.podspec index 1749684d..f6631a9a 100644 --- a/TINetworking/TINetworking.podspec +++ b/TINetworking/TINetworking.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TINetworking' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Swagger-frendly networking layer helpers.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TINetworkingCache/TINetworkingCache.podspec b/TINetworkingCache/TINetworkingCache.podspec index fa086f5a..a12b2177 100644 --- a/TINetworkingCache/TINetworkingCache.podspec +++ b/TINetworkingCache/TINetworkingCache.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TINetworkingCache' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Caching results of EndpointRequests.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIPagination/TIPagination.podspec b/TIPagination/TIPagination.podspec index be2e9143..eea01a31 100644 --- a/TIPagination/TIPagination.podspec +++ b/TIPagination/TIPagination.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIPagination' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Generic pagination component.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TISwiftUICore/TISwiftUICore.podspec b/TISwiftUICore/TISwiftUICore.podspec index 7c8dde9f..fd2b61a2 100644 --- a/TISwiftUICore/TISwiftUICore.podspec +++ b/TISwiftUICore/TISwiftUICore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TISwiftUICore' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Core UI elements: protocols, views and helpers..' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TISwiftUtils/TISwiftUtils.podspec b/TISwiftUtils/TISwiftUtils.podspec index f22e5a1e..9aebb85f 100644 --- a/TISwiftUtils/TISwiftUtils.podspec +++ b/TISwiftUtils/TISwiftUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TISwiftUtils' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Bunch of useful helpers for Swift development.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TITableKitUtils/TITableKitUtils.podspec b/TITableKitUtils/TITableKitUtils.podspec index d808aba8..20966a66 100644 --- a/TITableKitUtils/TITableKitUtils.podspec +++ b/TITableKitUtils/TITableKitUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TITableKitUtils' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Set of helpers for TableKit classes.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TITransitions/TITransitions.podspec b/TITransitions/TITransitions.podspec index e1dcf910..1cb39350 100644 --- a/TITransitions/TITransitions.podspec +++ b/TITransitions/TITransitions.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TITransitions' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Set of custom transitions to present controller. ' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIUIElements/README.md b/TIUIElements/README.md index 91e83ced..9eea58ad 100644 --- a/TIUIElements/README.md +++ b/TIUIElements/README.md @@ -132,7 +132,7 @@ Use to present alerts in a few lines of code. Can be used for UIKit and SwiftUI > You can initialize `AlertsFactory` with your own *LocalizationProvider* or use `DefaultAlertLocalizationProvider` ## Your view or view controller must implement PresentationContext protocol -There are `UIKitContext` and `SwiftUIContext` protocols that are designed to make it easier to work with `PresentationContext` protocol. By default, no changes need to be made for UIKit view controllers and SwiftUI views to make them conform to these protocols +There are `UIKitAlertContext` and `SwiftUIAlertContext` protocols that are designed to make it easier to work with `AlertPresentationContext` protocol. By default, no changes need to be made for UIKit view controllers to make them conform to `UIKitAlertContext`. ## Custom alerts ```swift diff --git a/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift b/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift index 79c62efc..9a50f530 100644 --- a/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift +++ b/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift @@ -24,7 +24,6 @@ import TISwiftUtils import UIKit open class AlertFactory { - public var localizationProvider: AlertLocalizationProvider public init(localizationProvider: AlertLocalizationProvider = DefaultAlertLocalizationProvider()) { diff --git a/TIUIElements/Sources/Alerts/Helpers/AlertDescriptor+Helpers.swift b/TIUIElements/Sources/Alerts/Helpers/AlertDescriptor+Helpers.swift index 9166ea38..192f504e 100644 --- a/TIUIElements/Sources/Alerts/Helpers/AlertDescriptor+Helpers.swift +++ b/TIUIElements/Sources/Alerts/Helpers/AlertDescriptor+Helpers.swift @@ -23,8 +23,8 @@ import TISwiftUtils import UIKit -extension AlertDescriptor { - public func present(on context: PresentationContext, completion: VoidClosure? = nil) { +public extension AlertDescriptor { + func present(on context: AlertPresentationContext, completion: VoidClosure? = nil) { let alertFactory: Closure = { configuration in UIAlertController(title: configuration.title, message: configuration.message, @@ -35,7 +35,7 @@ extension AlertDescriptor { present(on: context, alertViewFactory: alertFactory, completion: completion) } - public func present(on context: PresentationContext, + func present(on context: AlertPresentationContext, alertViewFactory: Closure, completion: VoidClosure? = nil) { alertViewFactory(self).present(on: context, completion: completion) diff --git a/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift b/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift index 4a718c09..a2a5458a 100644 --- a/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift +++ b/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift @@ -20,13 +20,13 @@ // THE SOFTWARE. // -import TISwiftUtils +import typealias TISwiftUtils.VoidClosure import UIKit -extension UIAlertController { +public extension UIAlertController { @discardableResult - public func configured(with configuration: AlertDescriptor) -> Self { + func configured(with configuration: AlertDescriptor) -> Self { title = configuration.title message = configuration.message view.tintColor = configuration.tintColor @@ -40,7 +40,7 @@ extension UIAlertController { } extension UIAlertController: AlertPresentable { - public func present(on context: PresentationContext, completion: VoidClosure?) { + public func present(on context: AlertPresentationContext, completion: VoidClosure?) { context.present(self, animated: true, completion: completion) } } diff --git a/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift b/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift index 6af75ec1..2f9bea2d 100644 --- a/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift +++ b/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift @@ -32,7 +32,7 @@ public extension View { /// - context: The view that will show the alert /// - alert: Descriptor of the alert. func alert(isPresented: Binding, - on context: PresentationContext, + on context: AlertPresentationContext, alert: AlertDescriptor) -> some View { if isPresented.wrappedValue { @@ -51,7 +51,7 @@ public extension View { /// - descriptor: Descriptor of the alert. /// - alertViewFactory: A closure called to configure custom alert. func alert(isPresented: Binding, - on context: PresentationContext, + on context: AlertPresentationContext, alertDescriptor descriptor: AlertDescriptor, alertViewFactory: Closure) -> some View { diff --git a/TIUIElements/Sources/Alerts/Models/DefaultAlertLocalizationProvider.swift b/TIUIElements/Sources/Alerts/Models/DefaultAlertLocalizationProvider.swift index a1a7084c..9b506998 100644 --- a/TIUIElements/Sources/Alerts/Models/DefaultAlertLocalizationProvider.swift +++ b/TIUIElements/Sources/Alerts/Models/DefaultAlertLocalizationProvider.swift @@ -25,7 +25,7 @@ import Foundation /// Provide default localization for alerts' buttons open class DefaultAlertLocalizationProvider: AlertLocalizationProvider { - public private(set) var bundle: Bundle + public var bundle: Bundle public init(bundle: Bundle = .main) { self.bundle = bundle diff --git a/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift b/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift index 9e8c3488..142f5b89 100644 --- a/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift +++ b/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift @@ -24,5 +24,5 @@ import TISwiftUtils import Foundation public protocol AlertPresentable { - func present(on context: PresentationContext, completion: VoidClosure?) + func present(on context: AlertPresentationContext, completion: VoidClosure?) } diff --git a/TIUIElements/Sources/Alerts/Protocols/PresentationContext.swift b/TIUIElements/Sources/Alerts/Protocols/AlertPresentationContext.swift similarity index 91% rename from TIUIElements/Sources/Alerts/Protocols/PresentationContext.swift rename to TIUIElements/Sources/Alerts/Protocols/AlertPresentationContext.swift index caf5028b..c060a1ef 100644 --- a/TIUIElements/Sources/Alerts/Protocols/PresentationContext.swift +++ b/TIUIElements/Sources/Alerts/Protocols/AlertPresentationContext.swift @@ -20,8 +20,9 @@ // THE SOFTWARE. // +import TISwiftUtils import UIKit -public protocol PresentationContext { - func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) +public protocol AlertPresentationContext { + func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: VoidClosure?) } diff --git a/TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift b/TIUIElements/Sources/Alerts/Protocols/SwiftUIAlertContext.swift similarity index 70% rename from TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift rename to TIUIElements/Sources/Alerts/Protocols/SwiftUIAlertContext.swift index 7c998fc0..da9cd8e6 100644 --- a/TIUIElements/Sources/Alerts/Protocols/SwiftUIContext.swift +++ b/TIUIElements/Sources/Alerts/Protocols/SwiftUIAlertContext.swift @@ -20,24 +20,17 @@ // THE SOFTWARE. // +import TISwiftUtils import SwiftUI @available(iOS 13, *) -public protocol SwiftUIContext: PresentationContext { - var presentedViewController: UIViewController? { get } +public protocol SwiftUIAlertContext: AlertPresentationContext { + var presentingViewController: UIViewController { get set } } @available(iOS 13, *) -public extension SwiftUIContext { - var presentedViewController: UIViewController? { - UIApplication.shared.windows.first?.rootViewController?.presentedViewController - } - - func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)?) { - guard let viewController = presentedViewController else { - return - } - - viewController.present(viewControllerToPresent, animated: flag, completion: completion) +public extension SwiftUIAlertContext { + func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: VoidClosure?) { + presentingViewController.present(viewControllerToPresent, animated: flag, completion: completion) } } diff --git a/TIUIElements/Sources/Alerts/Protocols/UIKitContext.swift b/TIUIElements/Sources/Alerts/Protocols/UIKitAlertContext.swift similarity index 94% rename from TIUIElements/Sources/Alerts/Protocols/UIKitContext.swift rename to TIUIElements/Sources/Alerts/Protocols/UIKitAlertContext.swift index 5958824a..3551febb 100644 --- a/TIUIElements/Sources/Alerts/Protocols/UIKitContext.swift +++ b/TIUIElements/Sources/Alerts/Protocols/UIKitAlertContext.swift @@ -22,4 +22,4 @@ import UIKit -public protocol UIKitContext: PresentationContext { } +public protocol UIKitAlertContext: AlertPresentationContext { } diff --git a/TIUIElements/TIUIElements.podspec b/TIUIElements/TIUIElements.podspec index 93d0709f..620f2c14 100644 --- a/TIUIElements/TIUIElements.podspec +++ b/TIUIElements/TIUIElements.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIUIElements' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Bunch of useful protocols and views.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIUIKitCore/TIUIKitCore.podspec b/TIUIKitCore/TIUIKitCore.podspec index 32675f8d..93baeac2 100644 --- a/TIUIKitCore/TIUIKitCore.podspec +++ b/TIUIKitCore/TIUIKitCore.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIUIKitCore' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Core UI elements: protocols, views and helpers.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } diff --git a/TIYandexMapUtils/TIYandexMapUtils.podspec b/TIYandexMapUtils/TIYandexMapUtils.podspec index 851f7167..943e1a6d 100644 --- a/TIYandexMapUtils/TIYandexMapUtils.podspec +++ b/TIYandexMapUtils/TIYandexMapUtils.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'TIYandexMapUtils' - s.version = '1.22.0' + s.version = '1.24.0' s.summary = 'Set of helpers for map objects clustering and interacting using Yandex Maps SDK.' s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name s.license = { :type => 'MIT', :file => 'LICENSE' } From 81382911530255675a3af7cd12858f6c7e37ecea Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Tue, 26 Jul 2022 13:40:56 +0300 Subject: [PATCH 08/17] feat: SUI alerts added to different library --- Package.swift | 2 ++ TISwiftUIElements/README.md | 5 +++++ .../Sources/Alerts/Modifiers/View+Alerts.swift | 3 ++- .../Alerts/Protocols/SwiftUIAlertContext.swift | 5 ++--- TISwiftUIElements/TISwiftUIElements.podspec | 17 +++++++++++++++++ .../UIAlertController+AlertPresentable.swift | 2 +- .../Alerts/Protocols/AlertPresentable.swift | 1 - 7 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 TISwiftUIElements/README.md rename TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift => TISwiftUIElements/Sources/Alerts/Modifiers/View+Alerts.swift (98%) rename {TIUIElements => TISwiftUIElements}/Sources/Alerts/Protocols/SwiftUIAlertContext.swift (96%) create mode 100644 TISwiftUIElements/TISwiftUIElements.podspec diff --git a/Package.swift b/Package.swift index 0edf613e..20b41c98 100644 --- a/Package.swift +++ b/Package.swift @@ -14,6 +14,7 @@ let package = Package( // MARK: - SwiftUI .library(name: "TISwiftUICore", targets: ["TISwiftUICore"]), + .library(name: "TISwiftUIElements", targets: ["TISwiftUIElements"]), // MARK: - Utils .library(name: "TISwiftUtils", targets: ["TISwiftUtils"]), @@ -55,6 +56,7 @@ let package = Package( // MARK: - SwiftUI .target(name: "TISwiftUICore", path: "TISwiftUICore/Sources"), + .target(name: "TISwiftUIElements", path: "TISwiftUIElements/Sources"), // MARK: - Utils .target(name: "TISwiftUtils", path: "TISwiftUtils/Sources"), diff --git a/TISwiftUIElements/README.md b/TISwiftUIElements/README.md new file mode 100644 index 00000000..6c804ac6 --- /dev/null +++ b/TISwiftUIElements/README.md @@ -0,0 +1,5 @@ +# TISwiftUIElements + +# Installation via SPM + +You can install this framework as a target of LeadKit. diff --git a/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift b/TISwiftUIElements/Sources/Alerts/Modifiers/View+Alerts.swift similarity index 98% rename from TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift rename to TISwiftUIElements/Sources/Alerts/Modifiers/View+Alerts.swift index 2f9bea2d..1b3b4121 100644 --- a/TIUIElements/Sources/Alerts/Helpers/View+Helpers.swift +++ b/TISwiftUIElements/Sources/Alerts/Modifiers/View+Alerts.swift @@ -21,9 +21,10 @@ // import TISwiftUtils +import TIUIElements import SwiftUI -@available(iOS 13.0, *) +@available(iOS 13, *) public extension View { /// Presents an alert with a description on a context when a given condition is true. diff --git a/TIUIElements/Sources/Alerts/Protocols/SwiftUIAlertContext.swift b/TISwiftUIElements/Sources/Alerts/Protocols/SwiftUIAlertContext.swift similarity index 96% rename from TIUIElements/Sources/Alerts/Protocols/SwiftUIAlertContext.swift rename to TISwiftUIElements/Sources/Alerts/Protocols/SwiftUIAlertContext.swift index da9cd8e6..0ea6ad63 100644 --- a/TIUIElements/Sources/Alerts/Protocols/SwiftUIAlertContext.swift +++ b/TISwiftUIElements/Sources/Alerts/Protocols/SwiftUIAlertContext.swift @@ -21,14 +21,13 @@ // import TISwiftUtils -import SwiftUI +import TIUIElements +import UIKit -@available(iOS 13, *) public protocol SwiftUIAlertContext: AlertPresentationContext { var presentingViewController: UIViewController { get set } } -@available(iOS 13, *) public extension SwiftUIAlertContext { func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: VoidClosure?) { presentingViewController.present(viewControllerToPresent, animated: flag, completion: completion) diff --git a/TISwiftUIElements/TISwiftUIElements.podspec b/TISwiftUIElements/TISwiftUIElements.podspec new file mode 100644 index 00000000..c99bcd30 --- /dev/null +++ b/TISwiftUIElements/TISwiftUIElements.podspec @@ -0,0 +1,17 @@ +Pod::Spec.new do |s| + s.name = 'TISwiftUIElements' + s.version = '1.24.0' + s.summary = 'Bunch of useful protocols and views.' + s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name + s.license = { :type => 'MIT', :file => 'LICENSE' } + s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' } + s.source = { :git => 'https://github.com/TouchInstinct/LeadKit.git', :tag => s.version.to_s } + + s.ios.deployment_target = '13.0' + s.swift_versions = ['5.3'] + + s.source_files = s.name + '/Sources/**/*' + + s.dependency 'TIUIElements', s.version.to_s + s.dependency 'TISwiftUtils', s.version.to_s +end diff --git a/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift b/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift index a2a5458a..d40ca0ef 100644 --- a/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift +++ b/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift @@ -20,7 +20,7 @@ // THE SOFTWARE. // -import typealias TISwiftUtils.VoidClosure +import TISwiftUtils import UIKit public extension UIAlertController { diff --git a/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift b/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift index 142f5b89..64eda4e1 100644 --- a/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift +++ b/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift @@ -21,7 +21,6 @@ // import TISwiftUtils -import Foundation public protocol AlertPresentable { func present(on context: AlertPresentationContext, completion: VoidClosure?) From ffa66048b0471db355dc69d6e79c6173564ff474 Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Tue, 26 Jul 2022 13:53:25 +0300 Subject: [PATCH 09/17] fix: removed TISwiftUIElements lib and moved components to TISwiftUICore --- Package.swift | 2 -- .../Sources/Alerts/Modifiers/View+Alerts.swift | 0 .../Alerts/Protocols/SwiftUIAlertContext.swift | 0 TISwiftUICore/TISwiftUICore.podspec | 2 ++ TISwiftUIElements/README.md | 5 ----- TISwiftUIElements/TISwiftUIElements.podspec | 17 ----------------- 6 files changed, 2 insertions(+), 24 deletions(-) rename {TISwiftUIElements => TISwiftUICore}/Sources/Alerts/Modifiers/View+Alerts.swift (100%) rename {TISwiftUIElements => TISwiftUICore}/Sources/Alerts/Protocols/SwiftUIAlertContext.swift (100%) delete mode 100644 TISwiftUIElements/README.md delete mode 100644 TISwiftUIElements/TISwiftUIElements.podspec diff --git a/Package.swift b/Package.swift index 20b41c98..0edf613e 100644 --- a/Package.swift +++ b/Package.swift @@ -14,7 +14,6 @@ let package = Package( // MARK: - SwiftUI .library(name: "TISwiftUICore", targets: ["TISwiftUICore"]), - .library(name: "TISwiftUIElements", targets: ["TISwiftUIElements"]), // MARK: - Utils .library(name: "TISwiftUtils", targets: ["TISwiftUtils"]), @@ -56,7 +55,6 @@ let package = Package( // MARK: - SwiftUI .target(name: "TISwiftUICore", path: "TISwiftUICore/Sources"), - .target(name: "TISwiftUIElements", path: "TISwiftUIElements/Sources"), // MARK: - Utils .target(name: "TISwiftUtils", path: "TISwiftUtils/Sources"), diff --git a/TISwiftUIElements/Sources/Alerts/Modifiers/View+Alerts.swift b/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift similarity index 100% rename from TISwiftUIElements/Sources/Alerts/Modifiers/View+Alerts.swift rename to TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift diff --git a/TISwiftUIElements/Sources/Alerts/Protocols/SwiftUIAlertContext.swift b/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift similarity index 100% rename from TISwiftUIElements/Sources/Alerts/Protocols/SwiftUIAlertContext.swift rename to TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift diff --git a/TISwiftUICore/TISwiftUICore.podspec b/TISwiftUICore/TISwiftUICore.podspec index fd2b61a2..a844e1cc 100644 --- a/TISwiftUICore/TISwiftUICore.podspec +++ b/TISwiftUICore/TISwiftUICore.podspec @@ -12,4 +12,6 @@ Pod::Spec.new do |s| s.source_files = s.name + '/Sources/**/*' + s.dependency 'TIUIElements', s.version.to_s + s.dependency 'TISwiftUtils', s.version.to_s end diff --git a/TISwiftUIElements/README.md b/TISwiftUIElements/README.md deleted file mode 100644 index 6c804ac6..00000000 --- a/TISwiftUIElements/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# TISwiftUIElements - -# Installation via SPM - -You can install this framework as a target of LeadKit. diff --git a/TISwiftUIElements/TISwiftUIElements.podspec b/TISwiftUIElements/TISwiftUIElements.podspec deleted file mode 100644 index c99bcd30..00000000 --- a/TISwiftUIElements/TISwiftUIElements.podspec +++ /dev/null @@ -1,17 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'TISwiftUIElements' - s.version = '1.24.0' - s.summary = 'Bunch of useful protocols and views.' - s.homepage = 'https://github.com/TouchInstinct/LeadKit/tree/' + s.version.to_s + '/' + s.name - s.license = { :type => 'MIT', :file => 'LICENSE' } - s.author = { 'petropavel13' => 'ivan.smolin@touchin.ru' } - s.source = { :git => 'https://github.com/TouchInstinct/LeadKit.git', :tag => s.version.to_s } - - s.ios.deployment_target = '13.0' - s.swift_versions = ['5.3'] - - s.source_files = s.name + '/Sources/**/*' - - s.dependency 'TIUIElements', s.version.to_s - s.dependency 'TISwiftUtils', s.version.to_s -end From 34c7407ecb8383096d4a1b6beef49029014de700 Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Tue, 26 Jul 2022 13:59:25 +0300 Subject: [PATCH 10/17] docs: SUI alerts --- TISwiftUICore/README.md | 20 +++++++++++++++++++- TIUIElements/README.md | 14 +------------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/TISwiftUICore/README.md b/TISwiftUICore/README.md index 75092272..c06adcf8 100644 --- a/TISwiftUICore/README.md +++ b/TISwiftUICore/README.md @@ -1,3 +1,21 @@ # TISwiftUICore -Core UI elements: protocols, views and helpers. \ No newline at end of file +Core UI elements: protocols, views and helpers. + +## SwiftUI alerts +> SwiftUI views should conform to protocol `SwiftUIAlertContext` to present alert + +```swift +var body: some View { + Button("Show custom alert with binding property") { + alertDescription = factory.okAlert(title: "Title", message: "Message") + isPresentedCustomAlert = true + } + } + .alert(isPresented: $isPresentedAlert, on: self, alert: alertDescription) +} +``` + +# Installation via SPM + +You can install this framework as a target of LeadKit. \ No newline at end of file diff --git a/TIUIElements/README.md b/TIUIElements/README.md index 9eea58ad..923d26f4 100644 --- a/TIUIElements/README.md +++ b/TIUIElements/README.md @@ -132,7 +132,7 @@ Use to present alerts in a few lines of code. Can be used for UIKit and SwiftUI > You can initialize `AlertsFactory` with your own *LocalizationProvider* or use `DefaultAlertLocalizationProvider` ## Your view or view controller must implement PresentationContext protocol -There are `UIKitAlertContext` and `SwiftUIAlertContext` protocols that are designed to make it easier to work with `AlertPresentationContext` protocol. By default, no changes need to be made for UIKit view controllers to make them conform to `UIKitAlertContext`. +There are `UIKitAlertContext` protocol that are designed to make it easier to work with `AlertPresentationContext` protocol. By default, no changes need to be made for UIKit view controllers to make them conform to `UIKitAlertContext`. ## Custom alerts ```swift @@ -189,18 +189,6 @@ func presentDialogueAlert() { } ``` -## SwiftUI alerts -```swift -var body: some View { - Button("Show custom alert with binding property") { - alertDescription = factory.okAlert(title: "Title", message: "Message") - isPresentedCustomAlert = true - } - } - .alert(isPresented: $isPresentedAlert, on: self, alert: alertDescription) -} -``` - # Installation via SPM You can install this framework as a target of LeadKit. From a88a85fe750976b2ee0252943ffccb974b05cc27 Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Tue, 26 Jul 2022 15:09:42 +0300 Subject: [PATCH 11/17] fix: move alerts into TIUIKitCore --- TIUIElements/README.md | 62 ------------- TIUIKitCore/README.md | 88 +++++++++++++++++-- .../Alerts/Factories/AlertFactory.swift | 0 .../Sources/Alerts/Models/AlertAction.swift | 0 .../Alerts/Models/AlertDescriptor.swift | 0 .../Alerts/Protocols/AlertPresentable.swift | 0 .../Protocols/AlertPresentationContext.swift | 0 .../Alerts/Protocols/UIKitAlertContext.swift | 0 .../Alerts}/AlertDescriptor+Helpers.swift | 0 .../UIAlertController+AlertPresentable.swift | 0 .../AlertLocalizationProvider.swift | 0 .../DefaultAlertLocalizationProvider.swift | 0 TIUIKitCore/TIUIKitCore.podspec | 2 + 13 files changed, 84 insertions(+), 68 deletions(-) rename {TIUIElements => TIUIKitCore}/Sources/Alerts/Factories/AlertFactory.swift (100%) rename {TIUIElements => TIUIKitCore}/Sources/Alerts/Models/AlertAction.swift (100%) rename {TIUIElements => TIUIKitCore}/Sources/Alerts/Models/AlertDescriptor.swift (100%) rename {TIUIElements => TIUIKitCore}/Sources/Alerts/Protocols/AlertPresentable.swift (100%) rename {TIUIElements => TIUIKitCore}/Sources/Alerts/Protocols/AlertPresentationContext.swift (100%) rename {TIUIElements => TIUIKitCore}/Sources/Alerts/Protocols/UIKitAlertContext.swift (100%) rename {TIUIElements/Sources/Alerts/Helpers => TIUIKitCore/Sources/Extensions/Alerts}/AlertDescriptor+Helpers.swift (100%) rename {TIUIElements/Sources/Alerts/Helpers => TIUIKitCore/Sources/Extensions/Alerts}/UIAlertController+AlertPresentable.swift (100%) rename {TIUIElements/Sources/Alerts/Protocols => TIUIKitCore/Sources/Localization/AlertsLocalization}/AlertLocalizationProvider.swift (100%) rename {TIUIElements/Sources/Alerts/Models => TIUIKitCore/Sources/Localization/AlertsLocalization}/DefaultAlertLocalizationProvider.swift (100%) diff --git a/TIUIElements/README.md b/TIUIElements/README.md index 923d26f4..1814f815 100644 --- a/TIUIElements/README.md +++ b/TIUIElements/README.md @@ -127,68 +127,6 @@ class ViewController: UITableViewController, CollapsibleViewsContainer {

-# AlertsFactory -Use to present alerts in a few lines of code. Can be used for UIKit and SwiftUI -> You can initialize `AlertsFactory` with your own *LocalizationProvider* or use `DefaultAlertLocalizationProvider` - -## Your view or view controller must implement PresentationContext protocol -There are `UIKitAlertContext` protocol that are designed to make it easier to work with `AlertPresentationContext` protocol. By default, no changes need to be made for UIKit view controllers to make them conform to `UIKitAlertContext`. - -## Custom alerts -```swift -// Presents alert -func presentAlert() { - factory - .alert(title: "Alert's title", - message: "Alert's message", - tint: .systemBlue, - actions: [ - AlertAction(title: "Ok", style: .default, action: nil), - AlertAction(title: "Cancel", style: .cancel, action: nil) - ]) - .present(on: self) -} - -// Presents sheet alert -func presentSheetAlert() { - factory - .sheetAlert(title: "Alert's title", - message: "Alert's message", - tint: .systemBlue, - actions: [ - AlertAction(title: "Ok", style: .default, action: nil), - AlertAction(title: "Cancel", style: .cancel, action: nil) - ]) - .present(on: self) -} -``` - -## Default alerts -```swift -// Ok alert -func presentOkAlert() { - factory - .okAlert(title: "Title", message: "Message") - .present(on: self) -} - -// Retry alert -func presentRetryAlert() { - factory - .retryAlert(title: "Title", message: "Message") { [weak self] in - self?.presentOkAlert() - } - .present(on: self) -} - -// Dialogue alert -func presentDialogueAlert() { - factory - .dialogueAlert(title: "Title", message: "Message") - .present(on: self) -} -``` - # Installation via SPM You can install this framework as a target of LeadKit. diff --git a/TIUIKitCore/README.md b/TIUIKitCore/README.md index 96d028a7..bbd3408d 100644 --- a/TIUIKitCore/README.md +++ b/TIUIKitCore/README.md @@ -4,11 +4,87 @@ Core UI elements: protocols, views and helpers. # Protocols -- [InitializableView](InitializableView/InitializableView.swift) - protocol with methods that should be called in constructor methods of view. -- [Animatable](Animatable/Animatable.swift) - protocol that ensures that specific type support basic animation actions. -- [ActivityIndicator](ActivityIndicator/ActivityIndicator.swift) - basic activity indicator. -- [ActivityIndicatorHolder](ActivityIndicator/ActivityIndicatorHolder.swift) - placeholder view, containing activity indicator. +- [InitializableView](Sources/InitializableView/InitializableViewProtocol.swift) - protocol with methods that should be called in constructor methods of view. +- [Animatable](Sources/ActivityIndicator/Animatable.swift) - protocol that ensures that specific type support basic animation actions. +- [ActivityIndicator](Sources/ActivityIndicator/ActivityIndicator.swift) - basic activity indicator. +- [ActivityIndicatorHolder](Sources/ActivityIndicator/ActivityIndicatorHolder.swift) - placeholder view, containing activity indicator. +- [AlertLocalizationProvider](Sources/Localization/AlertsLocalization/AlertLocalizationProvider.swift) - protocol that ensures that localization for alerts will be provided. +- [AlertPresentable](Sources/Alerts/Protocols/AlertPresentable.swift) - protocol indicates that certain object can present alerts. +- [AlertPresentationContext](Sources/Alerts/Protocols/AlertPresentationContext.swift) - protocol indicates that certain object can present alert on top of itself. +- [UIKitAlertContext](Sources/Alerts/Protocols/UIKitAlertContext.swift) - helper to provide easy conformance of `UIViewController` to `AlertPresentationContext`. -# Views +# Models -- [BaseInitializableView](BaseInitializableView/BaseInitializableView.swift) - UIView conformance to InitializableView. +- [DefaultAlertLocalizationProvider](Sources/Localization/AlertsLocalization/DefaultAlertLocalizationProvider.swift) - default localization provider for alerts. +- [AlertAction](Sources/Alerts/Models/AlertAction.swift) - representation of alert action +- [AlertDescriptor](Sources/Alerts/Models/AlertDescriptor.swift) - struct that holds all needed information to present alert + +# Factories + +- [AlertsFactory](Sources/Alerts/Factories/AlertFactory.swift) - factory to present alerts. + +## AlertsFactory +Use to present alerts in a few lines of code. Can be used for UIKit and SwiftUI +> You can initialize `AlertsFactory` with your own *LocalizationProvider* or use `DefaultAlertLocalizationProvider` + +### Your view or view controller must implement PresentationContext protocol +There are `UIKitAlertContext` protocol that are designed to make it easier to work with `AlertPresentationContext` protocol. By default, no changes need to be made for UIKit view controllers to make them conform to `UIKitAlertContext`. + +## Custom alerts +```swift +// Presents alert +func presentAlert() { + factory + .alert(title: "Alert's title", + message: "Alert's message", + tint: .systemBlue, + actions: [ + AlertAction(title: "Ok", style: .default, action: nil), + AlertAction(title: "Cancel", style: .cancel, action: nil) + ]) + .present(on: self) +} + +// Presents sheet alert +func presentSheetAlert() { + factory + .sheetAlert(title: "Alert's title", + message: "Alert's message", + tint: .systemBlue, + actions: [ + AlertAction(title: "Ok", style: .default, action: nil), + AlertAction(title: "Cancel", style: .cancel, action: nil) + ]) + .present(on: self) +} +``` + +## Default alerts +```swift +// Ok alert +func presentOkAlert() { + factory + .okAlert(title: "Title", message: "Message") + .present(on: self) +} + +// Retry alert +func presentRetryAlert() { + factory + .retryAlert(title: "Title", message: "Message") { [weak self] in + self?.presentOkAlert() + } + .present(on: self) +} + +// Dialogue alert +func presentDialogueAlert() { + factory + .dialogueAlert(title: "Title", message: "Message") + .present(on: self) +} +``` + +# Installation via SPM + +You can install this framework as a target of LeadKit. diff --git a/TIUIElements/Sources/Alerts/Factories/AlertFactory.swift b/TIUIKitCore/Sources/Alerts/Factories/AlertFactory.swift similarity index 100% rename from TIUIElements/Sources/Alerts/Factories/AlertFactory.swift rename to TIUIKitCore/Sources/Alerts/Factories/AlertFactory.swift diff --git a/TIUIElements/Sources/Alerts/Models/AlertAction.swift b/TIUIKitCore/Sources/Alerts/Models/AlertAction.swift similarity index 100% rename from TIUIElements/Sources/Alerts/Models/AlertAction.swift rename to TIUIKitCore/Sources/Alerts/Models/AlertAction.swift diff --git a/TIUIElements/Sources/Alerts/Models/AlertDescriptor.swift b/TIUIKitCore/Sources/Alerts/Models/AlertDescriptor.swift similarity index 100% rename from TIUIElements/Sources/Alerts/Models/AlertDescriptor.swift rename to TIUIKitCore/Sources/Alerts/Models/AlertDescriptor.swift diff --git a/TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift similarity index 100% rename from TIUIElements/Sources/Alerts/Protocols/AlertPresentable.swift rename to TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift diff --git a/TIUIElements/Sources/Alerts/Protocols/AlertPresentationContext.swift b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentationContext.swift similarity index 100% rename from TIUIElements/Sources/Alerts/Protocols/AlertPresentationContext.swift rename to TIUIKitCore/Sources/Alerts/Protocols/AlertPresentationContext.swift diff --git a/TIUIElements/Sources/Alerts/Protocols/UIKitAlertContext.swift b/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift similarity index 100% rename from TIUIElements/Sources/Alerts/Protocols/UIKitAlertContext.swift rename to TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift diff --git a/TIUIElements/Sources/Alerts/Helpers/AlertDescriptor+Helpers.swift b/TIUIKitCore/Sources/Extensions/Alerts/AlertDescriptor+Helpers.swift similarity index 100% rename from TIUIElements/Sources/Alerts/Helpers/AlertDescriptor+Helpers.swift rename to TIUIKitCore/Sources/Extensions/Alerts/AlertDescriptor+Helpers.swift diff --git a/TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift b/TIUIKitCore/Sources/Extensions/Alerts/UIAlertController+AlertPresentable.swift similarity index 100% rename from TIUIElements/Sources/Alerts/Helpers/UIAlertController+AlertPresentable.swift rename to TIUIKitCore/Sources/Extensions/Alerts/UIAlertController+AlertPresentable.swift diff --git a/TIUIElements/Sources/Alerts/Protocols/AlertLocalizationProvider.swift b/TIUIKitCore/Sources/Localization/AlertsLocalization/AlertLocalizationProvider.swift similarity index 100% rename from TIUIElements/Sources/Alerts/Protocols/AlertLocalizationProvider.swift rename to TIUIKitCore/Sources/Localization/AlertsLocalization/AlertLocalizationProvider.swift diff --git a/TIUIElements/Sources/Alerts/Models/DefaultAlertLocalizationProvider.swift b/TIUIKitCore/Sources/Localization/AlertsLocalization/DefaultAlertLocalizationProvider.swift similarity index 100% rename from TIUIElements/Sources/Alerts/Models/DefaultAlertLocalizationProvider.swift rename to TIUIKitCore/Sources/Localization/AlertsLocalization/DefaultAlertLocalizationProvider.swift diff --git a/TIUIKitCore/TIUIKitCore.podspec b/TIUIKitCore/TIUIKitCore.podspec index 93baeac2..2da9cae0 100644 --- a/TIUIKitCore/TIUIKitCore.podspec +++ b/TIUIKitCore/TIUIKitCore.podspec @@ -12,4 +12,6 @@ Pod::Spec.new do |s| s.source_files = s.name + '/Sources/**/*' s.framework = 'UIKit' + + s.dependency 'TISwiftUtils', s.version.to_s end From bf46b602a389c4f979d71c97affa7b7676f8f5fd Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Tue, 26 Jul 2022 15:20:33 +0300 Subject: [PATCH 12/17] fix: code review notes --- TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift | 2 +- .../Sources/Alerts/Protocols/SwiftUIAlertContext.swift | 2 +- TISwiftUICore/TISwiftUICore.podspec | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift b/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift index 1b3b4121..50c335fe 100644 --- a/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift +++ b/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift @@ -21,7 +21,7 @@ // import TISwiftUtils -import TIUIElements +import TIUIKitCore import SwiftUI @available(iOS 13, *) diff --git a/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift b/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift index 0ea6ad63..d490bef4 100644 --- a/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift +++ b/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift @@ -21,7 +21,7 @@ // import TISwiftUtils -import TIUIElements +import TIUIKitCore import UIKit public protocol SwiftUIAlertContext: AlertPresentationContext { diff --git a/TISwiftUICore/TISwiftUICore.podspec b/TISwiftUICore/TISwiftUICore.podspec index a844e1cc..9546161c 100644 --- a/TISwiftUICore/TISwiftUICore.podspec +++ b/TISwiftUICore/TISwiftUICore.podspec @@ -12,6 +12,6 @@ Pod::Spec.new do |s| s.source_files = s.name + '/Sources/**/*' - s.dependency 'TIUIElements', s.version.to_s + s.dependency 'TIUIKitCore', s.version.to_s s.dependency 'TISwiftUtils', s.version.to_s end From cfbf53faf8519d9937a4295307adaa121cb2407f Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Tue, 26 Jul 2022 15:33:50 +0300 Subject: [PATCH 13/17] fix: code review notes --- .../Sources/Extensions/Alerts/AlertDescriptor+Helpers.swift | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TIUIKitCore/Sources/Extensions/Alerts/AlertDescriptor+Helpers.swift b/TIUIKitCore/Sources/Extensions/Alerts/AlertDescriptor+Helpers.swift index 192f504e..716d2522 100644 --- a/TIUIKitCore/Sources/Extensions/Alerts/AlertDescriptor+Helpers.swift +++ b/TIUIKitCore/Sources/Extensions/Alerts/AlertDescriptor+Helpers.swift @@ -34,10 +34,10 @@ public extension AlertDescriptor { present(on: context, alertViewFactory: alertFactory, completion: completion) } - + func present(on context: AlertPresentationContext, - alertViewFactory: Closure, - completion: VoidClosure? = nil) { + alertViewFactory: Closure, + completion: VoidClosure? = nil) { alertViewFactory(self).present(on: context, completion: completion) } } From 9a427adab713b2d481b9907db5b4df77ff88f2b7 Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Wed, 27 Jul 2022 13:58:44 +0300 Subject: [PATCH 14/17] fix: code review notes + added custom modifier for alerts --- TISwiftUICore/README.md | 22 +++++--- .../Alerts/Modifiers/AlertModifier.swift | 51 +++++++++++++++++++ .../Alerts/Modifiers/View+Alerts.swift | 22 +++----- TIUIKitCore/README.md | 28 +++++++++- .../Alerts/Factories/AlertFactory.swift | 10 ++-- .../Sources/Alerts/Models/AlertAction.swift | 2 +- .../Alerts/Models/AlertDescriptor.swift | 2 +- .../Alerts/Protocols/AlertPresentable.swift | 1 + .../Protocols/AlertPresentationContext.swift | 1 + .../Alerts/Protocols/UIKitAlertContext.swift | 2 - .../DefaultAlertLocalizationProvider.swift | 2 +- 11 files changed, 111 insertions(+), 32 deletions(-) create mode 100644 TISwiftUICore/Sources/Alerts/Modifiers/AlertModifier.swift diff --git a/TISwiftUICore/README.md b/TISwiftUICore/README.md index c06adcf8..95ebf38e 100644 --- a/TISwiftUICore/README.md +++ b/TISwiftUICore/README.md @@ -3,16 +3,26 @@ Core UI elements: protocols, views and helpers. ## SwiftUI alerts -> SwiftUI views should conform to protocol `SwiftUIAlertContext` to present alert +> SwiftUI views should conform to protocol `SwiftUIAlertContext` to present alerts. This means that the view must implement the presentingViewController property. This controller is a context from which the alert will be shown. ```swift -var body: some View { - Button("Show custom alert with binding property") { - alertDescription = factory.okAlert(title: "Title", message: "Message") - isPresentedCustomAlert = true +struct ContentView: View, SwiftUIAlertContext { + + private let factory = AlertFactory() + + @State private var alertDescription: AlertDescriptor + @State private var isAlertPresented = false + + var presentingViewController: UIViewController + + var body: some View { + Button("Show custom alert with binding property") { + alertDescription = factory.okAlert(title: "Title", message: "Message") + isAlertPresented = true + } } + .alert(isPresented: $isAlertPresented, on: self, alert: alertDescription) } - .alert(isPresented: $isPresentedAlert, on: self, alert: alertDescription) } ``` diff --git a/TISwiftUICore/Sources/Alerts/Modifiers/AlertModifier.swift b/TISwiftUICore/Sources/Alerts/Modifiers/AlertModifier.swift new file mode 100644 index 00000000..c406ae15 --- /dev/null +++ b/TISwiftUICore/Sources/Alerts/Modifiers/AlertModifier.swift @@ -0,0 +1,51 @@ +// +// Copyright (c) 2022 Touch Instinct +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the Software), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// + +import SwiftUI +import TISwiftUtils +import TIUIKitCore + +@available(iOS 13, *) +struct AlertModifier: ViewModifier { + + @Binding var isPresented: Bool + + let context: AlertPresentationContext + let alertDescriptor: AlertDescriptor + let alertPresentable: AlertPresentable? + + func body(content: Content) -> some View { + if isPresented { + let completion: VoidClosure = { + isPresented = false + } + + if let alertPresentable = alertPresentable { + alertPresentable.present(on: context, completion: completion) + } else { + alertDescriptor.present(on: context, completion: completion) + } + } + + return content + } +} diff --git a/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift b/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift index 50c335fe..ed5cf6f2 100644 --- a/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift +++ b/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift @@ -36,13 +36,10 @@ public extension View { on context: AlertPresentationContext, alert: AlertDescriptor) -> some View { - if isPresented.wrappedValue { - alert.present(on: context) { - isPresented.wrappedValue = false - } - } - - return self + modifier(AlertModifier(isPresented: isPresented, + context: context, + alertDescriptor: alert, + alertPresentable: nil)) } /// Presents an alert with a description on a context with custom configuration of the alert when a given condition is true. @@ -56,12 +53,9 @@ public extension View { alertDescriptor descriptor: AlertDescriptor, alertViewFactory: Closure) -> some View { - if isPresented.wrappedValue { - alertViewFactory(descriptor).present(on: context) { - isPresented.wrappedValue = false - } - } - - return self + modifier(AlertModifier(isPresented: isPresented, + context: context, + alertDescriptor: descriptor, + alertPresentable: alertViewFactory(descriptor))) } } diff --git a/TIUIKitCore/README.md b/TIUIKitCore/README.md index bbd3408d..22f9601d 100644 --- a/TIUIKitCore/README.md +++ b/TIUIKitCore/README.md @@ -27,8 +27,32 @@ Core UI elements: protocols, views and helpers. Use to present alerts in a few lines of code. Can be used for UIKit and SwiftUI > You can initialize `AlertsFactory` with your own *LocalizationProvider* or use `DefaultAlertLocalizationProvider` -### Your view or view controller must implement PresentationContext protocol -There are `UIKitAlertContext` protocol that are designed to make it easier to work with `AlertPresentationContext` protocol. By default, no changes need to be made for UIKit view controllers to make them conform to `UIKitAlertContext`. +### Your view or view controller must implement AlertPresentationContext protocol +The implementation of the protocol says that an alert can be shown from this object. Also there is a `UIKitAlertContext` protocol designed to make it easier to work with `AlertPresentationContext` protocol. By default, no changes need to be made for UIKit view controllers to make them conform to `UIKitAlertContext`. + +### Your alert controller must implement AlertPresentable protocol +The implementation of this protocol says that an alert can be shown from the context. By default, the standard `UIAlertController` conforms to the protocol. Accordingly, when using a custom alert, it must also conform to the protocol: + +```swift +import PopupDialog + +extension PopupDialog: AlertPresentable { + @discardableResult + public func configured(with configuration: AlertDescriptor) -> Self { + title = configuration.title + + for action in configuration.actions { + addButton(DefaultButton(title: action.title, action: action.action)) + } + + return self + } + + public func present(on context: AlertPresentationContext, completion: VoidClosure?) { + context.present(self, animated: true, completion: completion) + } +} +``` ## Custom alerts ```swift diff --git a/TIUIKitCore/Sources/Alerts/Factories/AlertFactory.swift b/TIUIKitCore/Sources/Alerts/Factories/AlertFactory.swift index 9a50f530..9376a8ea 100644 --- a/TIUIKitCore/Sources/Alerts/Factories/AlertFactory.swift +++ b/TIUIKitCore/Sources/Alerts/Factories/AlertFactory.swift @@ -36,7 +36,7 @@ open class AlertFactory { /// - message: A text string used as the message of the alert. /// - tint: A color used as a tint color of the alert. Default color is UIColor.systemBlue. /// - actions: An array of actions of the alert. - /// - Returns: Alert descriptor, which can be used to present alert view. + /// - Returns: Alert descriptor which can be used to present alert view. open func alert(title: String? = nil, message: String? = nil, tint: UIColor = .systemBlue, @@ -54,7 +54,7 @@ open class AlertFactory { /// - message: A text string used as the message of the sheet alert. /// - tint: A color used as a tint color of the sheet alert. Default color is UIColor.systemBlue. /// - actions: An array of actions of the sheet alert. - /// - Returns: Alert descriptor, which can be used to present sheet alert view. + /// - Returns: Alert descriptor which can be used to present sheet alert view. open func sheetAlert(title: String? = nil, message: String? = nil, tint: UIColor = .systemBlue, @@ -72,7 +72,7 @@ open class AlertFactory { /// - title: A text string used as the title of the alert. /// - message: A text string used as the message of the alert. /// - tint: A color used as a tint color of the alert. Default color is UIColor.systemBlue. - /// - Returns: Alert descriptor, which can be used to present alert view. + /// - Returns: Alert descriptor which can be used to present alert view. open func okAlert(title: String? = nil, message: String? = nil, tint: UIColor = .systemBlue) -> AlertDescriptor { @@ -89,7 +89,7 @@ open class AlertFactory { /// - message: A text string used as the message of the alert. /// - tint: A color used as a tint color of the alert. Default color is UIColor.systemBlue. /// - retryAction: A closure called by tapping on the retry button of the alert. - /// - Returns: Alert descriptor, which can be used to present alert view. + /// - Returns: Alert descriptor which can be used to present alert view. open func retryAlert(title: String? = nil, message: String? = nil, tint: UIColor = .systemBlue, @@ -111,7 +111,7 @@ open class AlertFactory { /// - tint: A color used as a tint color of the alert. Default color is UIColor.systemBlue. /// - yesAction: A closure called by tapping on the yes button of the alert. /// - noAction: A closure called by tapping on the no button of the alert. - /// - Returns: Alert descriptor, which can be used to present alert view. + /// - Returns: Alert descriptor which can be used to present alert view. open func dialogueAlert(title: String? = nil, message: String? = nil, tint: UIColor = .systemBlue, diff --git a/TIUIKitCore/Sources/Alerts/Models/AlertAction.swift b/TIUIKitCore/Sources/Alerts/Models/AlertAction.swift index c90b8996..d919c7ee 100644 --- a/TIUIKitCore/Sources/Alerts/Models/AlertAction.swift +++ b/TIUIKitCore/Sources/Alerts/Models/AlertAction.swift @@ -23,7 +23,7 @@ import TISwiftUtils import UIKit -// struct describe alert button information +/// A struct describes an alert button information public struct AlertAction { public let id = UUID() diff --git a/TIUIKitCore/Sources/Alerts/Models/AlertDescriptor.swift b/TIUIKitCore/Sources/Alerts/Models/AlertDescriptor.swift index 2efb8190..2c6c81b8 100644 --- a/TIUIKitCore/Sources/Alerts/Models/AlertDescriptor.swift +++ b/TIUIKitCore/Sources/Alerts/Models/AlertDescriptor.swift @@ -22,7 +22,7 @@ import UIKit -/// Struct describes alert data +/// A struct describes alert data public struct AlertDescriptor { /// Alert title diff --git a/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift index 64eda4e1..163177a5 100644 --- a/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift +++ b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift @@ -22,6 +22,7 @@ import TISwiftUtils +/// A protocol represents an alert which can be presented on the given context public protocol AlertPresentable { func present(on context: AlertPresentationContext, completion: VoidClosure?) } diff --git a/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentationContext.swift b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentationContext.swift index c060a1ef..72dd720d 100644 --- a/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentationContext.swift +++ b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentationContext.swift @@ -23,6 +23,7 @@ import TISwiftUtils import UIKit +/// A context from where the alert can be presented public protocol AlertPresentationContext { func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: VoidClosure?) } diff --git a/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift b/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift index 3551febb..3652242b 100644 --- a/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift +++ b/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift @@ -20,6 +20,4 @@ // THE SOFTWARE. // -import UIKit - public protocol UIKitAlertContext: AlertPresentationContext { } diff --git a/TIUIKitCore/Sources/Localization/AlertsLocalization/DefaultAlertLocalizationProvider.swift b/TIUIKitCore/Sources/Localization/AlertsLocalization/DefaultAlertLocalizationProvider.swift index 9b506998..b3c0e95d 100644 --- a/TIUIKitCore/Sources/Localization/AlertsLocalization/DefaultAlertLocalizationProvider.swift +++ b/TIUIKitCore/Sources/Localization/AlertsLocalization/DefaultAlertLocalizationProvider.swift @@ -22,7 +22,7 @@ import Foundation -/// Provide default localization for alerts' buttons +/// Provides default localization for alerts' buttons open class DefaultAlertLocalizationProvider: AlertLocalizationProvider { public var bundle: Bundle From 174d472f1bd55d84c37af2e0dcdb412a9b096b0b Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Wed, 27 Jul 2022 14:40:38 +0300 Subject: [PATCH 15/17] revert: deleted alert modifier --- .../Alerts/Modifiers/AlertModifier.swift | 51 ------------------- .../Alerts/Modifiers/View+Alerts.swift | 22 +++++--- 2 files changed, 14 insertions(+), 59 deletions(-) delete mode 100644 TISwiftUICore/Sources/Alerts/Modifiers/AlertModifier.swift diff --git a/TISwiftUICore/Sources/Alerts/Modifiers/AlertModifier.swift b/TISwiftUICore/Sources/Alerts/Modifiers/AlertModifier.swift deleted file mode 100644 index c406ae15..00000000 --- a/TISwiftUICore/Sources/Alerts/Modifiers/AlertModifier.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// Copyright (c) 2022 Touch Instinct -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the Software), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -// - -import SwiftUI -import TISwiftUtils -import TIUIKitCore - -@available(iOS 13, *) -struct AlertModifier: ViewModifier { - - @Binding var isPresented: Bool - - let context: AlertPresentationContext - let alertDescriptor: AlertDescriptor - let alertPresentable: AlertPresentable? - - func body(content: Content) -> some View { - if isPresented { - let completion: VoidClosure = { - isPresented = false - } - - if let alertPresentable = alertPresentable { - alertPresentable.present(on: context, completion: completion) - } else { - alertDescriptor.present(on: context, completion: completion) - } - } - - return content - } -} diff --git a/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift b/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift index ed5cf6f2..50c335fe 100644 --- a/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift +++ b/TISwiftUICore/Sources/Alerts/Modifiers/View+Alerts.swift @@ -36,10 +36,13 @@ public extension View { on context: AlertPresentationContext, alert: AlertDescriptor) -> some View { - modifier(AlertModifier(isPresented: isPresented, - context: context, - alertDescriptor: alert, - alertPresentable: nil)) + if isPresented.wrappedValue { + alert.present(on: context) { + isPresented.wrappedValue = false + } + } + + return self } /// Presents an alert with a description on a context with custom configuration of the alert when a given condition is true. @@ -53,9 +56,12 @@ public extension View { alertDescriptor descriptor: AlertDescriptor, alertViewFactory: Closure) -> some View { - modifier(AlertModifier(isPresented: isPresented, - context: context, - alertDescriptor: descriptor, - alertPresentable: alertViewFactory(descriptor))) + if isPresented.wrappedValue { + alertViewFactory(descriptor).present(on: context) { + isPresented.wrappedValue = false + } + } + + return self } } From a917723dcb7faf2f7f52808a0dfb674694b63139 Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Wed, 27 Jul 2022 16:08:13 +0300 Subject: [PATCH 16/17] docs: code review notes --- .../Protocols/SwiftUIAlertContext.swift | 13 ++++++++++ .../Alerts/Protocols/AlertPresentable.swift | 24 ++++++++++++++++++- .../Protocols/AlertPresentationContext.swift | 2 +- .../Alerts/Protocols/UIKitAlertContext.swift | 8 +++++++ .../AlertLocalizationProvider.swift | 1 + 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift b/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift index d490bef4..b9585f52 100644 --- a/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift +++ b/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift @@ -24,7 +24,20 @@ import TISwiftUtils import TIUIKitCore import UIKit +/// A SwiftUI context from where the alert can be presented. +/// +/// ``` +/// // View that can present alerts. +/// struct ContentView: View, SwiftUIAlerContext { +/// var presentingViewController: UIViewController +/// +/// var body: some View { +/// // View realization. +/// } +/// } +/// ``` public protocol SwiftUIAlertContext: AlertPresentationContext { + /// A view controller that represents a context from which the alert will be shown. var presentingViewController: UIViewController { get set } } diff --git a/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift index 163177a5..e042b953 100644 --- a/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift +++ b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift @@ -22,7 +22,29 @@ import TISwiftUtils -/// A protocol represents an alert which can be presented on the given context +/// A protocol represents an alert which can be presented on the given context. +/// +/// ```import PopupDialog +/// +/// extension PopupDialog: AlertPresentable { +/// @discardableResult +/// public func configured(with configuration: AlertDescriptor) -> Self { +/// title = configuration.title +/// +/// for action in configuration.actions { +/// addButton(DefaultButton(title: action.title, action: action.action)) +/// } +/// +/// return self +/// } +/// +/// public func present(on context: AlertPresentationContext, completion: VoidClosure?) { +/// context.present(self, animated: true, completion: completion) +/// } +/// } +/// ``` +/// +/// The implementation of this protocol says that an alert can be shown from the context. By default, the standard `UIAlertController` conforms to the protocol. Accordingly, when using a custom alert, it must also conform to the protocol. public protocol AlertPresentable { func present(on context: AlertPresentationContext, completion: VoidClosure?) } diff --git a/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentationContext.swift b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentationContext.swift index 72dd720d..377a4086 100644 --- a/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentationContext.swift +++ b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentationContext.swift @@ -23,7 +23,7 @@ import TISwiftUtils import UIKit -/// A context from where the alert can be presented +/// A context from where the alert can be presented. public protocol AlertPresentationContext { func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: VoidClosure?) } diff --git a/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift b/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift index 3652242b..342f9a32 100644 --- a/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift +++ b/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift @@ -20,4 +20,12 @@ // THE SOFTWARE. // +/// An UIKit context from where the alert can be presented. +/// +/// ``` +/// // View controller that can present alerts. +/// class ViewController: UIViewController, UIKitAlerContext { +/// // Realization of the view controller +/// } +/// ``` public protocol UIKitAlertContext: AlertPresentationContext { } diff --git a/TIUIKitCore/Sources/Localization/AlertsLocalization/AlertLocalizationProvider.swift b/TIUIKitCore/Sources/Localization/AlertsLocalization/AlertLocalizationProvider.swift index 98795b27..85fb451a 100644 --- a/TIUIKitCore/Sources/Localization/AlertsLocalization/AlertLocalizationProvider.swift +++ b/TIUIKitCore/Sources/Localization/AlertsLocalization/AlertLocalizationProvider.swift @@ -20,6 +20,7 @@ // THE SOFTWARE. // +/// A provider of localization for common buttons' titles of the alerts. public protocol AlertLocalizationProvider { var okTitle: String { get } var cancelTitle: String { get } From 17a70d613b100c7a61b0b3ec6c783584b649f82e Mon Sep 17 00:00:00 2001 From: Nikita Semenov Date: Wed, 27 Jul 2022 17:37:34 +0300 Subject: [PATCH 17/17] docs: code review notes --- TISwiftUICore/README.md | 17 +++++++++++++- .../Protocols/SwiftUIAlertContext.swift | 11 --------- TIUIKitCore/README.md | 7 ++++++ .../Alerts/Protocols/AlertPresentable.swift | 23 +------------------ .../Alerts/Protocols/UIKitAlertContext.swift | 7 ------ 5 files changed, 24 insertions(+), 41 deletions(-) diff --git a/TISwiftUICore/README.md b/TISwiftUICore/README.md index 95ebf38e..98a9cb3a 100644 --- a/TISwiftUICore/README.md +++ b/TISwiftUICore/README.md @@ -3,7 +3,22 @@ Core UI elements: protocols, views and helpers. ## SwiftUI alerts -> SwiftUI views should conform to protocol `SwiftUIAlertContext` to present alerts. This means that the view must implement the presentingViewController property. This controller is a context from which the alert will be shown. + +### SwiftUI views should conform to protocol `SwiftUIAlertContext` to present alerts. +This means that the view must implement the presentingViewController property. This controller is a context from which the alert will be shown. + +```swift +// View that can present alerts. +struct ContentView: View, SwiftUIAlerContext { + var presentingViewController: UIViewController + + var body: some View { + // View realization. + } +} +``` + +## Alerts usage example ```swift struct ContentView: View, SwiftUIAlertContext { diff --git a/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift b/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift index b9585f52..68bad482 100644 --- a/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift +++ b/TISwiftUICore/Sources/Alerts/Protocols/SwiftUIAlertContext.swift @@ -25,17 +25,6 @@ import TIUIKitCore import UIKit /// A SwiftUI context from where the alert can be presented. -/// -/// ``` -/// // View that can present alerts. -/// struct ContentView: View, SwiftUIAlerContext { -/// var presentingViewController: UIViewController -/// -/// var body: some View { -/// // View realization. -/// } -/// } -/// ``` public protocol SwiftUIAlertContext: AlertPresentationContext { /// A view controller that represents a context from which the alert will be shown. var presentingViewController: UIViewController { get set } diff --git a/TIUIKitCore/README.md b/TIUIKitCore/README.md index 22f9601d..276ef7ff 100644 --- a/TIUIKitCore/README.md +++ b/TIUIKitCore/README.md @@ -30,6 +30,13 @@ Use to present alerts in a few lines of code. Can be used for UIKit and SwiftUI ### Your view or view controller must implement AlertPresentationContext protocol The implementation of the protocol says that an alert can be shown from this object. Also there is a `UIKitAlertContext` protocol designed to make it easier to work with `AlertPresentationContext` protocol. By default, no changes need to be made for UIKit view controllers to make them conform to `UIKitAlertContext`. +```swift +// View controller that can present alerts. +class ViewController: UIViewController, UIKitAlerContext { + // Realization of the view controller +} +``` + ### Your alert controller must implement AlertPresentable protocol The implementation of this protocol says that an alert can be shown from the context. By default, the standard `UIAlertController` conforms to the protocol. Accordingly, when using a custom alert, it must also conform to the protocol: diff --git a/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift index e042b953..b24d66cd 100644 --- a/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift +++ b/TIUIKitCore/Sources/Alerts/Protocols/AlertPresentable.swift @@ -23,28 +23,7 @@ import TISwiftUtils /// A protocol represents an alert which can be presented on the given context. -/// -/// ```import PopupDialog -/// -/// extension PopupDialog: AlertPresentable { -/// @discardableResult -/// public func configured(with configuration: AlertDescriptor) -> Self { -/// title = configuration.title -/// -/// for action in configuration.actions { -/// addButton(DefaultButton(title: action.title, action: action.action)) -/// } -/// -/// return self -/// } -/// -/// public func present(on context: AlertPresentationContext, completion: VoidClosure?) { -/// context.present(self, animated: true, completion: completion) -/// } -/// } -/// ``` -/// -/// The implementation of this protocol says that an alert can be shown from the context. By default, the standard `UIAlertController` conforms to the protocol. Accordingly, when using a custom alert, it must also conform to the protocol. +/// The implementation of this protocol says that an alert can be shown from the context. By default, the standard `UIAlertController` conforms to the protocol. public protocol AlertPresentable { func present(on context: AlertPresentationContext, completion: VoidClosure?) } diff --git a/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift b/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift index 342f9a32..7fdcf8e1 100644 --- a/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift +++ b/TIUIKitCore/Sources/Alerts/Protocols/UIKitAlertContext.swift @@ -21,11 +21,4 @@ // /// An UIKit context from where the alert can be presented. -/// -/// ``` -/// // View controller that can present alerts. -/// class ViewController: UIViewController, UIKitAlerContext { -/// // Realization of the view controller -/// } -/// ``` public protocol UIKitAlertContext: AlertPresentationContext { }