Merge pull request #315 from TouchInstinct/feature/alerts_api

alerts api
This commit is contained in:
Nikita Semenov 2022-07-28 11:55:33 +03:00 committed by GitHub
commit 0803060787
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
34 changed files with 806 additions and 26 deletions

View File

@ -1,5 +1,9 @@
# Changelog
### 1.24.0
- **Add**: `AlertFactory` for presenting alerts in SwiftUI and UIKit.
### 1.23.0
- **Update**: `UITextView` now support configuration with `BaseTextAttributes`

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = "LeadKit"
s.version = "1.23.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"

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIAppleMapUtils'
s.version = '1.23.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' }

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIAuth'
s.version = '1.23.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' }

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIFoundationUtils'
s.version = '1.23.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' }

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIGoogleMapUtils'
s.version = '1.23.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' }

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIKeychainUtils'
s.version = '1.23.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' }

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIMapUtils'
s.version = '1.23.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' }

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIMoyaNetworking'
s.version = '1.23.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' }

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TINetworking'
s.version = '1.23.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' }

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TINetworkingCache'
s.version = '1.23.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' }

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIPagination'
s.version = '1.23.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' }

View File

@ -1,3 +1,46 @@
# TISwiftUICore
Core UI elements: protocols, views and helpers.
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.
```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 {
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)
}
}
```
# Installation via SPM
You can install this framework as a target of LeadKit.

View File

@ -0,0 +1,67 @@
//
// 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 TIUIKitCore
import SwiftUI
@available(iOS 13, *)
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 alerts 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<Bool>,
on context: AlertPresentationContext,
alert: AlertDescriptor) -> some View {
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.
/// - Parameters:
/// - isPresented: A binding to a Boolean value that determines whether to present the alert. When the user presses or taps one of the alerts 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<Bool>,
on context: AlertPresentationContext,
alertDescriptor descriptor: AlertDescriptor,
alertViewFactory: Closure<AlertDescriptor, AlertPresentable>) -> some View {
if isPresented.wrappedValue {
alertViewFactory(descriptor).present(on: context) {
isPresented.wrappedValue = false
}
}
return self
}
}

View File

@ -0,0 +1,37 @@
//
// 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 TIUIKitCore
import UIKit
/// A SwiftUI context from where the alert can be presented.
public protocol SwiftUIAlertContext: AlertPresentationContext {
/// A view controller that represents a context from which the alert will be shown.
var presentingViewController: UIViewController { get set }
}
public extension SwiftUIAlertContext {
func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: VoidClosure?) {
presentingViewController.present(viewControllerToPresent, animated: flag, completion: completion)
}
}

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TISwiftUICore'
s.version = '1.23.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' }
@ -12,4 +12,6 @@ Pod::Spec.new do |s|
s.source_files = s.name + '/Sources/**/*'
s.dependency 'TIUIKitCore', s.version.to_s
s.dependency 'TISwiftUtils', s.version.to_s
end

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TISwiftUtils'
s.version = '1.23.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' }

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TITableKitUtils'
s.version = '1.23.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' }

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TITransitions'
s.version = '1.23.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' }

View File

@ -126,7 +126,7 @@ class ViewController: UITableViewController, CollapsibleViewsContainer {
<p align="left">
<img src="Assets/paralaxWithScale.gif" width=300 height=600>
</p>
# Installation via SPM
You can install this framework as a target of LeadKit.

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIUIElements'
s.version = '1.23.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' }

View File

@ -4,11 +4,118 @@ 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 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:
```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
// 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.

View File

@ -0,0 +1,143 @@
//
// 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 {
public var localizationProvider: AlertLocalizationProvider
public init(localizationProvider: AlertLocalizationProvider = DefaultAlertLocalizationProvider()) {
self.localizationProvider = localizationProvider
}
/// 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 {
AlertDescriptor(title: title,
message: message,
tintColor: tint,
actions: actions)
}
/// 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,
yesAction: VoidClosure? = nil,
noAction: VoidClosure? = nil) -> AlertDescriptor {
AlertDescriptor(title: title,
message: message,
tintColor: tint,
actions: [
.init(title: localizationProvider.yesTitle, action: yesAction),
.init(title: localizationProvider.noTitle, style: .destructive, action: noAction)
])
}
}
// MARK: - AlertAction + Helpers
private extension AlertAction {
static func simpleAction(_ title: String,
style: UIAlertAction.Style = .default) -> AlertAction {
AlertAction(title: title, style: style, action: nil)
}
static func cancelAction(_ title: String) -> AlertAction {
.simpleAction(title, style: .cancel)
}
}

View File

@ -0,0 +1,66 @@
//
// 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
/// A struct describes an alert button information
public struct AlertAction {
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?
public 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 + Identifiable
@available(iOS 13, *)
extension AlertAction: Identifiable { }
// MARK: - AlertAction + Helpers
extension AlertAction {
var asUIAlertAction: UIAlertAction {
UIAlertAction(title: title, style: style, handler: { _ in action?() })
}
}

View File

@ -0,0 +1,55 @@
//
// 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
/// A 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
}
}

View File

@ -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.
//
import TISwiftUtils
/// A protocol represents an alert which can be presented on the given context.
/// 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?)
}

View File

@ -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.
//
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?)
}

View File

@ -0,0 +1,24 @@
//
// 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.
//
/// An UIKit context from where the alert can be presented.
public protocol UIKitAlertContext: AlertPresentationContext { }

View File

@ -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
public extension AlertDescriptor {
func present(on context: AlertPresentationContext, completion: VoidClosure? = nil) {
let alertFactory: Closure<Self, UIAlertController> = { configuration in
UIAlertController(title: configuration.title,
message: configuration.message,
preferredStyle: configuration.style)
.configured(with: configuration)
}
present(on: context, alertViewFactory: alertFactory, completion: completion)
}
func present(on context: AlertPresentationContext,
alertViewFactory: Closure<Self, AlertPresentable>,
completion: VoidClosure? = nil) {
alertViewFactory(self).present(on: context, completion: completion)
}
}

View File

@ -0,0 +1,46 @@
//
// 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
public extension UIAlertController {
@discardableResult
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: AlertPresentationContext, completion: VoidClosure?) {
context.present(self, animated: true, completion: completion)
}
}

View File

@ -0,0 +1,30 @@
//
// 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.
//
/// A provider of localization for common buttons' titles of the alerts.
public protocol AlertLocalizationProvider {
var okTitle: String { get }
var cancelTitle: String { get }
var retryTitle: String { get }
var yesTitle: String { get }
var noTitle: String { get }
}

View File

@ -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
/// Provides default localization for alerts' buttons
open class DefaultAlertLocalizationProvider: AlertLocalizationProvider {
public 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)
}
}

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIUIKitCore'
s.version = '1.23.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' }
@ -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

View File

@ -1,6 +1,6 @@
Pod::Spec.new do |s|
s.name = 'TIYandexMapUtils'
s.version = '1.23.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' }