From e48d20f2a0e41f15df6dc1c2743a7be82cf0debc Mon Sep 17 00:00:00 2001 From: damien Date: Sat, 17 Aug 2019 21:37:21 +0200 Subject: [PATCH] Trim whitespace-only lines --- Source/Permission.swift | 128 +++++++-------- Source/PermissionAlert.swift | 54 +++---- Source/PermissionButton.swift | 148 +++++++++--------- Source/PermissionSet.swift | 38 ++--- Source/PermissionStatus.swift | 2 +- Source/PermissionType.swift | 54 +++---- Source/PermissionTypes/AddressBook.swift | 4 +- Source/PermissionTypes/Bluetooth.swift | 16 +- Source/PermissionTypes/Camera.swift | 6 +- Source/PermissionTypes/Contacts.swift | 8 +- Source/PermissionTypes/Events.swift | 6 +- Source/PermissionTypes/Location.swift | 7 +- Source/PermissionTypes/LocationAlways.swift | 10 +- .../PermissionTypes/LocationWhenInUse.swift | 8 +- Source/PermissionTypes/MediaLibrary.swift | 8 +- Source/PermissionTypes/Microphone.swift | 4 +- Source/PermissionTypes/Motion.swift | 39 +++-- Source/PermissionTypes/Notifications.swift | 16 +- Source/PermissionTypes/Photos.swift | 4 +- Source/PermissionTypes/Reminders.swift | 6 +- Source/PermissionTypes/Siri.swift | 4 +- Source/PermissionTypes/SpeechRecognizer.swift | 12 +- Source/Supporting Files/Utilities.swift | 19 ++- Tests/PermissionTests.swift | 2 +- 24 files changed, 300 insertions(+), 303 deletions(-) diff --git a/Source/Permission.swift b/Source/Permission.swift index e13df71..20ca5de 100644 --- a/Source/Permission.swift +++ b/Source/Permission.swift @@ -30,67 +30,67 @@ open class Permission: NSObject { @available(iOS 9.0, *) public static let contacts = Permission(type: .contacts) #endif - + #if PERMISSION_ADDRESS_BOOK /// The permission to access the user's address book. (Deprecated in iOS 9.0) public static let addressBook = Permission(type: .addressBook) #endif - + #if PERMISSION_LOCATION /// The permission to access the user's location when the app is in background. public static let locationAlways = Permission(type: .locationAlways) - + /// The permission to access the user's location when the app is in use. public static let locationWhenInUse = Permission(type: .locationWhenInUse) #endif - + #if PERMISSION_MICROPHONE /// The permission to access the microphone. public static let microphone = Permission(type: .microphone) #endif - + #if PERMISSION_CAMERA /// The permission to access the camera. public static let camera = Permission(type: .camera) #endif - + #if PERMISSION_PHOTOS /// The permission to access the user's photos. public static let photos = Permission(type: .photos) #endif - + #if PERMISSION_REMINDERS /// The permission to access the user's reminders. public static let reminders = Permission(type: .reminders) #endif - + #if PERMISSION_EVENTS /// The permission to access the user's events. public static let events = Permission(type: .events) #endif - + #if PERMISSION_BLUETOOTH /// The permission to access the user's bluetooth. public static let bluetooth = Permission(type: .bluetooth) #endif - + #if PERMISSION_MOTION /// The permission to access the user's motion. public static let motion = Permission(type: .motion) #endif - + #if PERMISSION_SPEECH_RECOGNIZER /// The permission to access the user's SpeechRecognizer. @available(iOS 10.0, *) public static let speechRecognizer = Permission(type: .speechRecognizer) #endif - + #if PERMISSION_MEDIA_LIBRARY /// The permission to access the user's MediaLibrary. @available(iOS 9.3, *) public static let mediaLibrary = Permission(type: .mediaLibrary) #endif - + #if PERMISSION_SIRI /// The permission to access the user's Siri. @available(iOS 10.0, *) @@ -103,10 +103,10 @@ open class Permission: NSObject { let settings = UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: nil) return Permission(type: .notifications(settings)) }() - + /// Variable used to retain the notifications permission. fileprivate static var _notifications: Permission? - + /// The permission to send notifications. public static func notifications(types: UIUserNotificationType, categories: Set?) -> Permission { let settings = UIUserNotificationSettings(types: types, categories: categories) @@ -114,7 +114,7 @@ open class Permission: NSObject { _notifications = permission return permission } - + /// The permission to send notifications. public static func notifications(types: UIUserNotificationType) -> Permission { let settings = UIUserNotificationSettings(types: types, categories: nil) @@ -122,7 +122,7 @@ open class Permission: NSObject { _notifications = permission return permission } - + /// The permission to send notifications. public static func notifications(categories: Set?) -> Permission { let settings = UIUserNotificationSettings(types: [.badge, .sound, .alert], categories: categories) @@ -131,100 +131,100 @@ open class Permission: NSObject { return permission } #endif - + /// The permission domain. public let type: PermissionType - + /// The permission status. open var status: PermissionStatus { #if PERMISSION_CONTACTS if case .contacts = type { return statusContacts } #endif - + #if PERMISSION_ADDRESS_BOOK if case .addressBook = type { return statusAddressBook } #endif - + #if PERMISSION_LOCATION if case .locationAlways = type { return statusLocationAlways } if case .locationWhenInUse = type { return statusLocationWhenInUse } #endif - + #if PERMISSION_NOTIFICATIONS if case .notifications = type { return statusNotifications } #endif - + #if PERMISSION_MICROPHONE if case .microphone = type { return statusMicrophone } #endif - + #if PERMISSION_CAMERA if case .camera = type { return statusCamera } #endif - + #if PERMISSION_PHOTOS if case .photos = type { return statusPhotos } #endif - + #if PERMISSION_REMINDERS if case .reminders = type { return statusReminders } #endif - + #if PERMISSION_EVENTS if case .events = type { return statusEvents } #endif - + #if PERMISSION_BLUETOOTH if case .bluetooth = type { return statusBluetooth } #endif - + #if PERMISSION_MOTION if case .motion = type { return statusMotion } #endif - + #if PERMISSION_SPEECH_RECOGNIZER if case .speechRecognizer = type { return statusSpeechRecognizer } #endif - + #if PERMISSION_MEDIA_LIBRARY if case .mediaLibrary = type { return statusMediaLibrary } #endif - + #if PERMISSION_SIRI if case .siri = type { return statusSiri } #endif - + fatalError() } - + /// Determines whether to present the pre-permission alert. open var presentPrePermissionAlert = false - + /// The pre-permission alert. open lazy var prePermissionAlert: PermissionAlert = { return PrePermissionAlert(permission: self) }() - + /// Determines whether to present the denied alert. open var presentDeniedAlert = true - + /// The alert when the permission was denied. open lazy var deniedAlert: PermissionAlert = { return DeniedAlert(permission: self) }() - + /// Determines whether to present the disabled alert. open var presentDisabledAlert = true - + /// The alert when the permission is disabled. open lazy var disabledAlert: PermissionAlert = { return DisabledAlert(permission: self) }() - + internal var callback: Callback? - + internal var permissionSets: [PermissionSet] = [] - + /** Creates and return a new permission for the specified domain. @@ -235,7 +235,7 @@ open class Permission: NSObject { fileprivate init(type: PermissionType) { self.type = type } - + /** Requests the permission. @@ -243,13 +243,13 @@ open class Permission: NSObject { */ open func request(_ callback: @escaping Callback) { self.callback = callback - + DispatchQueue.main.async { self.permissionSets.forEach { $0.willRequestPermission(self) } } - + let status = self.status - + switch status { case .authorized: callbacks(status) case .notDetermined: presentPrePermissionAlert ? prePermissionAlert.present() : requestAuthorization(callbacks) @@ -257,7 +257,7 @@ open class Permission: NSObject { case .disabled: presentDisabledAlert ? disabledAlert.present() : callbacks(status) } } - + internal func requestAuthorization(_ callback: @escaping Callback) { #if PERMISSION_CONTACTS if case .contacts = type { @@ -265,106 +265,106 @@ open class Permission: NSObject { return } #endif - + #if PERMISSION_ADDRESS_BOOK if case .addressBook = type { requestAddressBook(callback) return } #endif - + #if PERMISSION_LOCATION if case .locationAlways = type { requestLocationAlways(callback) return } - + if case .locationWhenInUse = type { requestLocationWhenInUse(callback) return } #endif - + #if PERMISSION_NOTIFICATIONS if case .notifications = type { requestNotifications(callback) return } #endif - + #if PERMISSION_MICROPHONE if case .microphone = type { requestMicrophone(callback) return } #endif - + #if PERMISSION_CAMERA if case .camera = type { requestCamera(callback) return } #endif - + #if PERMISSION_PHOTOS if case .photos = type { requestPhotos(callback) return } #endif - + #if PERMISSION_REMINDERS if case .reminders = type { requestReminders(callback) return } #endif - + #if PERMISSION_EVENTS if case .events = type { requestEvents(callback) return } #endif - + #if PERMISSION_BLUETOOTH if case .bluetooth = type { requestBluetooth(self.callback) return } #endif - + #if PERMISSION_MOTION if case .motion = type { requestMotion(self.callback) return } #endif - + #if PERMISSION_SPEECH_RECOGNIZER if case .speechRecognizer = type { requestSpeechRecognizer(callback) return } #endif - + #if PERMISSION_MEDIA_LIBRARY if case .mediaLibrary = type { requestMediaLibrary(callback) return } #endif - + #if PERMISSION_SIRI if case .siri = type { requestSiri(callback) return } #endif - + fatalError() } - + internal func callbacks(_ with: PermissionStatus) { DispatchQueue.main.async { self.callback?(self.status) @@ -378,7 +378,7 @@ extension Permission { override open var description: String { return type.description } - + /// A textual representation of this instance, suitable for debugging. override open var debugDescription: String { return "\(type): \(status)" diff --git a/Source/PermissionAlert.swift b/Source/PermissionAlert.swift index 86bc837..3f12366 100644 --- a/Source/PermissionAlert.swift +++ b/Source/PermissionAlert.swift @@ -25,55 +25,55 @@ open class PermissionAlert { /// The permission. fileprivate let permission: Permission - + /// The status of the permission. fileprivate var status: PermissionStatus { return permission.status } - + /// The domain of the permission. fileprivate var type: PermissionType { return permission.type } - + fileprivate var callbacks: Permission.Callback { return permission.callbacks } - + /// The title of the alert. open var title: String? - + /// Descriptive text that provides more details about the reason for the alert. open var message: String? - + /// The title of the cancel action. open var cancel: String? { get { return cancelActionTitle } set { cancelActionTitle = newValue } } - + /// The title of the settings action. open var settings: String? { get { return defaultActionTitle } set { defaultActionTitle = newValue } } - + /// The title of the confirm action. open var confirm: String? { get { return defaultActionTitle } set { defaultActionTitle = newValue } } - + fileprivate var cancelActionTitle: String? fileprivate var defaultActionTitle: String? - + var controller: UIAlertController { let controller = UIAlertController(title: title, message: message, preferredStyle: .alert) - + let action = UIAlertAction(title: cancelActionTitle, style: .cancel, handler: cancelHandler) controller.addAction(action) - + return controller } - + internal init(permission: Permission) { self.permission = permission } - + internal func present() { DispatchQueue.main.async { UIApplication.shared.presentViewController(self.controller) @@ -88,7 +88,7 @@ open class PermissionAlert { internal class DisabledAlert: PermissionAlert { override init(permission: Permission) { super.init(permission: permission) - + title = "\(permission) is currently disabled" message = "Please enable access to \(permission) in the Settings app." cancel = "OK" @@ -98,34 +98,34 @@ internal class DisabledAlert: PermissionAlert { internal class DeniedAlert: PermissionAlert { override var controller: UIAlertController { let controller = super.controller - + let action = UIAlertAction(title: defaultActionTitle, style: .default, handler: settingsHandler) controller.addAction(action) if #available(iOS 9.0, *) { controller.preferredAction = action } - + return controller } - + override init(permission: Permission) { super.init(permission: permission) - + title = "Permission for \(permission) was denied" message = "Please enable access to \(permission) in the Settings app." cancel = "Cancel" settings = "Settings" } - + @objc func settingsHandler() { NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification) callbacks(status) } - + private func settingsHandler(_ action: UIAlertAction) { NotificationCenter.default.addObserver(self, selector: .settingsHandler, name: UIApplication.didBecomeActiveNotification) - + if let URL = URL(string: UIApplication.openSettingsURLString) { UIApplication.shared.openURL(URL) } @@ -135,26 +135,26 @@ internal class DeniedAlert: PermissionAlert { internal class PrePermissionAlert: PermissionAlert { override var controller: UIAlertController { let controller = super.controller - + let action = UIAlertAction(title: defaultActionTitle, style: .default, handler: confirmHandler) controller.addAction(action) if #available(iOS 9.0, *) { controller.preferredAction = action } - + return controller } - + override init(permission: Permission) { super.init(permission: permission) - + title = "\(Bundle.main.name) would like to access your \(permission)" message = "Please enable access to \(permission)." cancel = "Cancel" confirm = "Confirm" } - + fileprivate func confirmHandler(_ action: UIAlertAction) { permission.requestAuthorization(callbacks) } diff --git a/Source/PermissionButton.swift b/Source/PermissionButton.swift index a76b376..5a041f5 100644 --- a/Source/PermissionButton.swift +++ b/Source/PermissionButton.swift @@ -26,37 +26,37 @@ open class PermissionButton: UIButton { /// The permission of the button. public let permission: Permission - + /// The permission domain of the button. open var domain: PermissionType { return permission.type } - + /// The permission status of the button. open var status: PermissionStatus { return permission.status } - + fileprivate var titles: [UIControl.State: [PermissionStatus: String]] = [:] fileprivate var attributedTitles: [UIControl.State: [PermissionStatus: NSAttributedString]] = [:] fileprivate var titleColors: [UIControl.State: [PermissionStatus: UIColor]] = [:] fileprivate var titleShadowColors: [UIControl.State: [PermissionStatus: UIColor]] = [:] fileprivate var images: [UIControl.State: [PermissionStatus: UIImage]] = [:] fileprivate var backgroundImages: [UIControl.State: [PermissionStatus: UIImage]] = [:] - + /// The alert when the permission was denied. open var deniedAlert: PermissionAlert { return permission.deniedAlert } - + /// The alert when the permission is disabled. open var disabledAlert: PermissionAlert { return permission.disabledAlert } - + /// The textual representation of self. open override var description: String { return permission.description } - + // MARK: - Initialization - + /** Creates and returns a new button for the specified permission. @@ -66,13 +66,13 @@ open class PermissionButton: UIButton { */ public init(_ permission: Permission) { self.permission = permission - + super.init(frame: .zero) - + self.addTarget(self, action: .tapped, for: .touchUpInside) self.addTarget(self, action: .highlight, for: .touchDown) } - + /** Returns an object initialized from data in a given unarchiver. @@ -83,9 +83,9 @@ open class PermissionButton: UIButton { public required init?(coder aDecoder: NSCoder) { fatalError("init(coder:) has not been implemented") } - + // MARK: - Titles - + /** Returns the title associated with the specified permission status and state. @@ -97,7 +97,7 @@ open class PermissionButton: UIButton { open func titleForStatus(_ status: PermissionStatus, andState state: UIControl.State = .normal) -> String? { return titles[state]?[status] } - + /** Sets the title to use for the specified state. @@ -108,7 +108,7 @@ open class PermissionButton: UIButton { titles[state] = nil super.setTitle(title, for: state) } - + /** Sets the title to use for the specified permission status and state. @@ -118,14 +118,14 @@ open class PermissionButton: UIButton { */ open func setTitle(_ title: String?, forStatus status: PermissionStatus, andState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if titles[state] == nil { titles[state] = [:] } - + titles[state]?[status] = title } - + /** Sets the titles to use for the specified permission statuses and state. @@ -134,18 +134,18 @@ open class PermissionButton: UIButton { */ open func setTitles(_ titles: [PermissionStatus: String?], forState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if self.titles[state] == nil { self.titles[state] = [:] } - + for (status, title) in titles { self.titles[state]?[status] = title } } - + // MARK: - Attributed titles - + /** Returns the styled title associated with the specified permission status and state. @@ -157,7 +157,7 @@ open class PermissionButton: UIButton { open func attributedTitleForStatus(_ status: PermissionStatus, andState state: UIControl.State = .normal) -> NSAttributedString? { return attributedTitles[state]?[status] } - + /** Sets the styled title to use for the specified state. @@ -168,7 +168,7 @@ open class PermissionButton: UIButton { attributedTitles[state] = nil super.setAttributedTitle(title, for: state) } - + /** Sets the styled title to use for the specifed permission status and state. @@ -178,14 +178,14 @@ open class PermissionButton: UIButton { */ open func setAttributedTitle(_ title: NSAttributedString?, forStatus status: PermissionStatus, andState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if attributedTitles[state] == nil { attributedTitles[state] = [:] } - + attributedTitles[state]?[status] = title } - + /** Sets the styled titles to use for the specified permission statuses and state. @@ -194,18 +194,18 @@ open class PermissionButton: UIButton { */ open func setAttributedTitles(_ titles: [PermissionStatus: NSAttributedString?], forState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if attributedTitles[state] == nil { attributedTitles[state] = [:] } - + for (status, title) in titles { attributedTitles[state]?[status] = title } } - + // MARK: - Title colors - + /** Returns the title color used for a permission status and state. @@ -217,7 +217,7 @@ open class PermissionButton: UIButton { open func titleColorForStatus(_ status: PermissionStatus, andState state: UIControl.State = .normal) -> UIColor? { return titleColors[state]?[status] } - + /** Sets the color of the title to use for the specified state. @@ -228,7 +228,7 @@ open class PermissionButton: UIButton { titleColors[state] = nil super.setTitleColor(color, for: state) } - + /** Sets the color of the title to use for the specified permission status and state. @@ -238,14 +238,14 @@ open class PermissionButton: UIButton { */ open func setTitleColor(_ color: UIColor?, forStatus status: PermissionStatus, andState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if titleColors[state] == nil { titleColors[state] = [:] } - + titleColors[state]?[status] = color } - + /** Sets the colors of the title to use for the specified permission statuses and state. @@ -254,18 +254,18 @@ open class PermissionButton: UIButton { */ open func setTitleColors(_ colors: [PermissionStatus: UIColor?], forState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if titleColors[state] == nil { titleColors[state] = [:] } - + for (status, color) in colors { titleColors[state]?[status] = color } } - + // MARK: - Title shadow colors - + /** Returns the shadow color of the title used for a permission status and state. @@ -277,7 +277,7 @@ open class PermissionButton: UIButton { open func titleShadowColorForStatus(_ status: PermissionStatus, andState state: UIControl.State = .normal) -> UIColor? { return titleShadowColors[state]?[status] } - + /** Sets the color of the title shadow to use for the specified state. @@ -288,7 +288,7 @@ open class PermissionButton: UIButton { titleShadowColors[state] = nil super.setTitleShadowColor(color, for: state) } - + /** Sets the color of the title shadow to use for the specified permission status and state. @@ -298,14 +298,14 @@ open class PermissionButton: UIButton { */ open func setTitleShadowColor(_ color: UIColor?, forStatus status: PermissionStatus, andState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if titleShadowColors[state] == nil { titleShadowColors[state] = [:] } - + titleShadowColors[state]?[status] = color } - + /** Sets the colors of the title shadow to use for the specified permission statuses and state. @@ -314,18 +314,18 @@ open class PermissionButton: UIButton { */ open func setTitleShadowColors(_ colors: [PermissionStatus: UIColor?], forState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if titleShadowColors[state] == nil { titleShadowColors[state] = [:] } - + for (status, color) in colors { titleShadowColors[state]?[status] = color } } - + // MARK: - Images - + /** Returns the image used for a permission status and state @@ -337,7 +337,7 @@ open class PermissionButton: UIButton { open func imageForStatus(_ status: PermissionStatus, andState state: UIControl.State = .normal) -> UIImage? { return images[state]?[status] } - + /** Sets the image to use for the specified state. @@ -348,7 +348,7 @@ open class PermissionButton: UIButton { images[state] = nil super.setImage(image, for: state) } - + /** Sets the image to use for the specified permission status and state. @@ -358,14 +358,14 @@ open class PermissionButton: UIButton { */ open func setImage(_ image: UIImage?, forStatus status: PermissionStatus, andState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if images[state] == nil { images[state] = [:] } - + images[state]?[status] = image } - + /** Sets the images for the specified permission statuses and state. @@ -374,18 +374,18 @@ open class PermissionButton: UIButton { */ open func setImages(_ images: [PermissionStatus: UIImage], forState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if self.images[state] == nil { self.images[state] = [:] } - + for (status, image) in images { self.images[state]?[status] = image } } - + // MARK: - Background images - + /** Returns the background image used for a permission status and a button state. @@ -397,7 +397,7 @@ open class PermissionButton: UIButton { open func backgroundImageForStatus(_ status: PermissionStatus, andState state: UIControl.State = .normal) -> UIImage? { return backgroundImages[state]?[status] } - + /** Sets the background image to use for the specified button state. @@ -408,7 +408,7 @@ open class PermissionButton: UIButton { backgroundImages[state] = nil super.setBackgroundImage(image, for: state) } - + /** Sets the background image to use for the specified permission status and button state. @@ -418,14 +418,14 @@ open class PermissionButton: UIButton { */ open func setBackgroundImage(_ image: UIImage?, forStatus status: PermissionStatus, andState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if backgroundImages[state] == nil { backgroundImages[state] = [:] } - + backgroundImages[state]?[status] = image } - + /** Set the background images to use for the specified permission statuses and button state. @@ -434,18 +434,18 @@ open class PermissionButton: UIButton { */ open func setBackgroundImages(_ images: [PermissionStatus: UIImage], forState state: UIControl.State = .normal) { guard [.normal, .highlighted].contains(state) else { return } - + if backgroundImages[state] == nil { backgroundImages[state] = [:] } - + for (status, image) in images { backgroundImages[state]?[status] = image } } - + // MARK: - UIView - + /** Tells the view that its superview changed. */ @@ -458,9 +458,9 @@ internal extension PermissionButton { @objc func highlight(_ button: PermissionButton) { render(.highlighted) } - + @objc func tapped(_ button: PermissionButton) { - permission.request { [weak self] status in + permission.request { [weak self] _ in self?.render() } } @@ -471,23 +471,23 @@ private extension PermissionButton { if let title = titleForStatus(status, andState: state) { super.setTitle(title, for: state) } - + if let title = attributedTitleForStatus(status, andState: state) { super.setAttributedTitle(title, for: state) } - + if let color = titleColorForStatus(status, andState: state) { super.setTitleColor(color, for: state) } - + if let color = titleShadowColorForStatus(status, andState: state) { super.setTitleShadowColor(color, for: state) } - + if let image = imageForStatus(status, andState: state) { super.setImage(image, for: state) } - + if let image = backgroundImageForStatus(status, andState: state) { super.setBackgroundImage(image, for: state) } diff --git a/Source/PermissionSet.swift b/Source/PermissionSet.swift index 6f8c5bb..0f62e26 100644 --- a/Source/PermissionSet.swift +++ b/Source/PermissionSet.swift @@ -23,32 +23,32 @@ // open class PermissionSet { - + /// The permissions in the set. public let permissions: Set - + /// The delegate of the permission set. open weak var delegate: PermissionSetDelegate? - + /// The permission set status open var status: PermissionStatus { let statuses = permissions.map({ $0.status }) - + for status in statuses where status == .denied { return .denied } - + for status in statuses where status == .disabled { return .disabled } - + for status in statuses where status == .notDetermined { return .notDetermined } - + return .authorized } - + /** Creates and returns a new permission set containing the specified buttons. @@ -59,7 +59,7 @@ open class PermissionSet { public convenience init(_ buttons: PermissionButton...) { self.init(buttons: buttons) } - + /** Creates and returns a new permission set containing the specified buttons. @@ -70,7 +70,7 @@ open class PermissionSet { public convenience init(_ buttons: [PermissionButton]) { self.init(buttons: buttons) } - + /** Creates and returns a new permission set containing the specified buttons. @@ -81,7 +81,7 @@ open class PermissionSet { public convenience init(_ permissions: Permission...) { self.init(permissions: permissions) } - + /** Creates and returns a new permission set containing the specified buttons. @@ -92,22 +92,22 @@ open class PermissionSet { public convenience init(_ permissions: [Permission]) { self.init(permissions: permissions) } - + fileprivate convenience init(buttons: [PermissionButton]) { let permissions = buttons.map({ $0.permission }) - + self.init(permissions: permissions) } - + fileprivate init(permissions: [Permission]) { self.permissions = Set(permissions) self.permissions.forEach { $0.permissionSets.append(self) } } - + internal func willRequestPermission(_ permission: Permission) { delegate?.permissionSet(self, willRequestPermission: permission) } - + internal func didRequestPermission(_ permission: Permission) { delegate?.permissionSet(self, didRequestPermission: permission) } @@ -118,7 +118,7 @@ extension PermissionSet: CustomStringConvertible { public var description: String { return [ "\(status): [", - permissions.map{ "\t\($0)" }.joined(separator: ",\n"), + permissions.map { "\t\($0)" }.joined(separator: ",\n"), "]" ].joined(separator: "\n") } @@ -132,7 +132,7 @@ public protocol PermissionSetDelegate: class { - parameter permission: The requested permission. */ func permissionSet(_ permissionSet: PermissionSet, didRequestPermission permission: Permission) - + /** Tells the delegate that the specified permission will be requested. @@ -150,7 +150,7 @@ public extension PermissionSetDelegate { - parameter permission: The requested permission. */ func permissionSet(_ permissionSet: PermissionSet, didRequestPermission permission: Permission) {} - + /** Tells the delegate that the specified permission will be requested. diff --git a/Source/PermissionStatus.swift b/Source/PermissionStatus.swift index fc8a77b..a4c3827 100644 --- a/Source/PermissionStatus.swift +++ b/Source/PermissionStatus.swift @@ -27,7 +27,7 @@ public enum PermissionStatus: String { case denied = "Denied" case disabled = "Disabled" case notDetermined = "Not Determined" - + internal init?(string: String?) { guard let string = string else { return nil } self.init(rawValue: string) diff --git a/Source/PermissionType.swift b/Source/PermissionType.swift index ba10853..09f77a1 100644 --- a/Source/PermissionType.swift +++ b/Source/PermissionType.swift @@ -26,56 +26,56 @@ public enum PermissionType { #if PERMISSION_CONTACTS @available(iOS 9.0, *) case contacts #endif - + #if PERMISSION_ADDRESS_BOOK case addressBook // Deprecated in iOS 9.0 #endif - + #if PERMISSION_LOCATION case locationAlways case locationWhenInUse #endif - + #if PERMISSION_NOTIFICATIONS case notifications(UIUserNotificationSettings) #endif - + #if PERMISSION_MICROPHONE case microphone #endif - + #if PERMISSION_CAMERA case camera #endif - + #if PERMISSION_PHOTOS case photos #endif - + #if PERMISSION_REMINDERS case reminders #endif - + #if PERMISSION_EVENTS case events #endif - + #if PERMISSION_BLUETOOTH case bluetooth #endif - + #if PERMISSION_MOTION case motion #endif - + #if PERMISSION_SPEECH_RECOGNIZER @available(iOS 10.0, *) case speechRecognizer #endif - + #if PERMISSION_MEDIA_LIBRARY @available(iOS 9.3, *) case mediaLibrary #endif - + #if PERMISSION_SIRI @available(iOS 10.0, *) case siri #endif @@ -86,60 +86,60 @@ extension PermissionType: CustomStringConvertible { #if PERMISSION_CONTACTS if case .contacts = self { return "Contacts" } #endif - + #if PERMISSION_ADDRESS_BOOK if case .addressBook = self { return "Address Book" } #endif - + #if PERMISSION_LOCATION if case .locationAlways = self { return "Location" } if case .locationWhenInUse = self { return "Location" } #endif - + #if PERMISSION_NOTIFICATIONS if case .notifications = self { return "Notifications" } #endif - + #if PERMISSION_MICROPHONE if case .microphone = self { return "Microphone" } #endif - + #if PERMISSION_CAMERA if case .camera = self { return "Camera" } #endif - + #if PERMISSION_PHOTOS if case .photos = self { return "Photos" } #endif - + #if PERMISSION_REMINDERS if case .reminders = self { return "Reminders" } #endif - + #if PERMISSION_EVENTS if case .events = self { return "Events" } #endif - + #if PERMISSION_BLUETOOTH if case .bluetooth = self { return "Bluetooth" } #endif - + #if PERMISSION_MOTION if case .motion = self { return "Motion" } #endif - + #if PERMISSION_SPEECH_RECOGNIZER if case .speechRecognizer = self { return "Speech Recognizer" } #endif - + #if PERMISSION_SIRI if case .siri = self { return "SiriKit" } #endif - + #if PERMISSION_MEDIA_LIBRARY if case .mediaLibrary = self { return "Media Library" } #endif - + fatalError() } } diff --git a/Source/PermissionTypes/AddressBook.swift b/Source/PermissionTypes/AddressBook.swift index 44e221d..dc5231e 100644 --- a/Source/PermissionTypes/AddressBook.swift +++ b/Source/PermissionTypes/AddressBook.swift @@ -28,7 +28,7 @@ import AddressBook internal extension Permission { var statusAddressBook: PermissionStatus { let status = ABAddressBookGetAuthorizationStatus() - + switch status { case .authorized: return .authorized case .restricted, .denied: return .denied @@ -36,7 +36,7 @@ internal extension Permission { @unknown default: return .notDetermined } } - + func requestAddressBook(_ callback: @escaping Callback) { ABAddressBookRequestAccessWithCompletion(nil) { _, _ in callback(self.statusAddressBook) diff --git a/Source/PermissionTypes/Bluetooth.swift b/Source/PermissionTypes/Bluetooth.swift index ad6a8ac..eac3c40 100644 --- a/Source/PermissionTypes/Bluetooth.swift +++ b/Source/PermissionTypes/Bluetooth.swift @@ -39,9 +39,9 @@ extension Permission { case .notDetermined, .authorized: break @unknown default: return .notDetermined } - + guard UserDefaults.standard.stateBluetoothManagerDetermined else { return .notDetermined } - + switch BluetoothManager.state { case .unsupported, .poweredOff: return .disabled case .unauthorized: return .denied @@ -51,10 +51,10 @@ extension Permission { @unknown default: return .notDetermined } } - + func requestBluetooth(_ callback: Callback?) { UserDefaults.standard.requestedBluetooth = true - + BluetoothManager.request(self) } } @@ -63,11 +63,11 @@ extension Permission: CBPeripheralManagerDelegate { public func peripheralManagerDidUpdateState(_ peripheral: CBPeripheralManager) { UserDefaults.standard.stateBluetoothManagerDetermined = true UserDefaults.standard.statusBluetooth = statusBluetooth - + guard UserDefaults.standard.requestedBluetooth else { return } - + callback?(statusBluetooth) - + UserDefaults.standard.requestedBluetooth = false } } @@ -75,7 +75,7 @@ extension Permission: CBPeripheralManagerDelegate { extension CBPeripheralManager { func request(_ permission: Permission) { guard case .poweredOn = state else { return } - + startAdvertising(nil) stopAdvertising() } diff --git a/Source/PermissionTypes/Camera.swift b/Source/PermissionTypes/Camera.swift index aa8c153..8b3f111 100644 --- a/Source/PermissionTypes/Camera.swift +++ b/Source/PermissionTypes/Camera.swift @@ -28,7 +28,7 @@ import AVFoundation internal extension Permission { var statusCamera: PermissionStatus { let status = AVCaptureDevice.authorizationStatus(for: AVMediaType.video) - + switch status { case .authorized: return .authorized case .restricted, .denied: return .denied @@ -36,13 +36,13 @@ internal extension Permission { @unknown default: return .notDetermined } } - + func requestCamera(_ callback: @escaping Callback) { guard let _ = Bundle.main.object(forInfoDictionaryKey: .cameraUsageDescription) else { print("WARNING: \(String.cameraUsageDescription) not found in Info.plist") return } - + AVCaptureDevice.requestAccess(for: AVMediaType.video) { _ in callback(self.statusCamera) } diff --git a/Source/PermissionTypes/Contacts.swift b/Source/PermissionTypes/Contacts.swift index 4bb612d..d2b4326 100644 --- a/Source/PermissionTypes/Contacts.swift +++ b/Source/PermissionTypes/Contacts.swift @@ -28,9 +28,9 @@ import Contacts internal extension Permission { var statusContacts: PermissionStatus { guard #available(iOS 9.0, *) else { fatalError() } - + let status = CNContactStore.authorizationStatus(for: .contacts) - + switch status { case .authorized: return .authorized case .restricted, .denied: return .denied @@ -38,10 +38,10 @@ internal extension Permission { @unknown default: return .notDetermined } } - + func requestContacts(_ callback: @escaping Callback) { guard #available(iOS 9.0, *) else { fatalError() } - + CNContactStore().requestAccess(for: .contacts) { _, _ in callback(self.statusContacts) } diff --git a/Source/PermissionTypes/Events.swift b/Source/PermissionTypes/Events.swift index a3ef083..334685d 100644 --- a/Source/PermissionTypes/Events.swift +++ b/Source/PermissionTypes/Events.swift @@ -28,7 +28,7 @@ import EventKit internal extension Permission { var statusEvents: PermissionStatus { let status = EKEventStore.authorizationStatus(for: .event) - + switch status { case .authorized: return .authorized case .restricted, .denied: return .denied @@ -36,9 +36,9 @@ internal extension Permission { @unknown default: return .notDetermined } } - + func requestEvents(_ callback: @escaping Callback) { - EKEventStore().requestAccess(to: .event) { _,_ in + EKEventStore().requestAccess(to: .event) { _, _ in callback(self.statusEvents) } } diff --git a/Source/PermissionTypes/Location.swift b/Source/PermissionTypes/Location.swift index 6e6ffd4..7128179 100644 --- a/Source/PermissionTypes/Location.swift +++ b/Source/PermissionTypes/Location.swift @@ -45,18 +45,17 @@ extension Permission: CLLocationManagerDelegate { } } - extension CLLocationManager { func request(_ permission: Permission) { delegate = permission - + requestedLocation = true - + if case .locationAlways = permission.type { requestAlwaysAuthorization() return } - + if case .locationWhenInUse = permission.type { requestWhenInUseAuthorization() return diff --git a/Source/PermissionTypes/LocationAlways.swift b/Source/PermissionTypes/LocationAlways.swift index ae88910..d4a9fe5 100644 --- a/Source/PermissionTypes/LocationAlways.swift +++ b/Source/PermissionTypes/LocationAlways.swift @@ -28,9 +28,9 @@ import CoreLocation internal extension Permission { var statusLocationAlways: PermissionStatus { guard CLLocationManager.locationServicesEnabled() else { return .disabled } - + let status = CLLocationManager.authorizationStatus() - + switch status { case .authorizedAlways: return .authorized case .authorizedWhenInUse: @@ -40,17 +40,17 @@ internal extension Permission { @unknown default: return .notDetermined } } - + func requestLocationAlways(_ callback: Callback) { guard let _ = Foundation.Bundle.main.object(forInfoDictionaryKey: .locationAlwaysUsageDescription) else { print("WARNING: \(String.locationAlwaysUsageDescription) not found in Info.plist") return } - + if CLLocationManager.authorizationStatus() == .authorizedWhenInUse { UserDefaults.standard.requestedLocationAlwaysWithWhenInUse = true } - + LocationManager.request(self) } } diff --git a/Source/PermissionTypes/LocationWhenInUse.swift b/Source/PermissionTypes/LocationWhenInUse.swift index f34b5f0..570101f 100644 --- a/Source/PermissionTypes/LocationWhenInUse.swift +++ b/Source/PermissionTypes/LocationWhenInUse.swift @@ -28,9 +28,9 @@ import CoreLocation internal extension Permission { var statusLocationWhenInUse: PermissionStatus { guard CLLocationManager.locationServicesEnabled() else { return .disabled } - + let status = CLLocationManager.authorizationStatus() - + switch status { case .authorizedWhenInUse, .authorizedAlways: return .authorized case .restricted, .denied: return .denied @@ -38,13 +38,13 @@ internal extension Permission { @unknown default: return .notDetermined } } - + func requestLocationWhenInUse(_ callback: Callback) { guard let _ = Foundation.Bundle.main.object(forInfoDictionaryKey: .locationWhenInUseUsageDescription) else { print("WARNING: \(String.locationWhenInUseUsageDescription) not found in Info.plist") return } - + LocationManager.request(self) } } diff --git a/Source/PermissionTypes/MediaLibrary.swift b/Source/PermissionTypes/MediaLibrary.swift index 86f76ee..1987a18 100644 --- a/Source/PermissionTypes/MediaLibrary.swift +++ b/Source/PermissionTypes/MediaLibrary.swift @@ -28,9 +28,9 @@ import MediaPlayer internal extension Permission { var statusMediaLibrary: PermissionStatus { guard #available(iOS 9.3, *) else { fatalError() } - + let status = MPMediaLibrary.authorizationStatus() - + switch status { case .authorized: return .authorized case .restricted, .denied: return .denied @@ -38,10 +38,10 @@ internal extension Permission { @unknown default: return .notDetermined } } - + func requestMediaLibrary(_ callback: @escaping Callback) { guard #available(iOS 9.3, *) else { fatalError() } - + guard let _ = Bundle.main.object(forInfoDictionaryKey: .mediaLibraryUsageDescription) else { print("WARNING: \(String.mediaLibraryUsageDescription) not found in Info.plist") return diff --git a/Source/PermissionTypes/Microphone.swift b/Source/PermissionTypes/Microphone.swift index 13a9f62..2e4c956 100644 --- a/Source/PermissionTypes/Microphone.swift +++ b/Source/PermissionTypes/Microphone.swift @@ -28,14 +28,14 @@ import AVFoundation internal extension Permission { var statusMicrophone: PermissionStatus { let status = AVAudioSession.sharedInstance().recordPermission - + switch status { case AVAudioSessionRecordPermission.denied: return .denied case AVAudioSessionRecordPermission.granted: return .authorized default: return .notDetermined } } - + func requestMicrophone(_ callback: @escaping Callback) { AVAudioSession.sharedInstance().requestRecordPermission { _ in callback(self.statusMicrophone) diff --git a/Source/PermissionTypes/Motion.swift b/Source/PermissionTypes/Motion.swift index 7036fea..8dfbdf6 100644 --- a/Source/PermissionTypes/Motion.swift +++ b/Source/PermissionTypes/Motion.swift @@ -32,52 +32,51 @@ extension Permission { if UserDefaults.standard.requestedMotion { return synchronousStatusMotion } - + return .notDetermined } - + func requestMotion(_ callback: Callback?) { UserDefaults.standard.requestedMotion = true - + let now = Date() - - MotionManager.queryActivityStarting(from: now, to: now, to: OperationQueue.main) { activities, error in + + MotionManager.queryActivityStarting(from: now, to: now, to: OperationQueue.main) { _, error in let status: PermissionStatus - - if let error = error , error._code == Int(CMErrorMotionActivityNotAuthorized.rawValue) { + + if let error = error, error._code == Int(CMErrorMotionActivityNotAuthorized.rawValue) { status = .denied } else { status = .authorized } - + MotionManager.stopActivityUpdates() - + callback?(status) } } - + fileprivate var synchronousStatusMotion: PermissionStatus { let semaphore = DispatchSemaphore(value: 0) - + var status: PermissionStatus = .notDetermined - + let now = Date() - - MotionManager.queryActivityStarting(from: now, to: now, to: OperationQueue(.background)) { activities, error in - if let error = error , error._code == Int(CMErrorMotionActivityNotAuthorized.rawValue) { + + MotionManager.queryActivityStarting(from: now, to: now, to: OperationQueue(.background)) { _, error in + if let error = error, error._code == Int(CMErrorMotionActivityNotAuthorized.rawValue) { status = .denied } else { status = .authorized } - + MotionManager.stopActivityUpdates() - + semaphore.signal() } - - + _ = semaphore.wait(timeout: DispatchTime.distantFuture) - + return status } } diff --git a/Source/PermissionTypes/Notifications.swift b/Source/PermissionTypes/Notifications.swift index ad0b6e4..01c8bb2 100644 --- a/Source/PermissionTypes/Notifications.swift +++ b/Source/PermissionTypes/Notifications.swift @@ -28,29 +28,29 @@ internal extension Permission { if UIApplication.shared.currentUserNotificationSettings?.types.isEmpty == false { return .authorized } - + return UserDefaults.standard.requestedNotifications ? .denied : .notDetermined } - + func requestNotifications(_ callback: Callback) { guard case .notifications(let settings) = type else { fatalError() } - + NotificationCenter.default.addObserver(self, selector: #selector(requestingNotifications), name: UIApplication.willResignActiveNotification) - + UIApplication.shared.registerUserNotificationSettings(settings) } - + @objc func requestingNotifications() { NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification) NotificationCenter.default.addObserver(self, selector: #selector(finishedRequestingNotifications), name: UIApplication.didBecomeActiveNotification) } - + @objc func finishedRequestingNotifications() { NotificationCenter.default.removeObserver(self, name: UIApplication.willResignActiveNotification) NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification) - + UserDefaults.standard.requestedNotifications = true - + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1) { self.callbacks(self.statusNotifications) } diff --git a/Source/PermissionTypes/Photos.swift b/Source/PermissionTypes/Photos.swift index 7ed2dc0..aab3fab 100644 --- a/Source/PermissionTypes/Photos.swift +++ b/Source/PermissionTypes/Photos.swift @@ -28,7 +28,7 @@ import Photos internal extension Permission { var statusPhotos: PermissionStatus { let status = PHPhotoLibrary.authorizationStatus() - + switch status { case .authorized: return .authorized case .denied, .restricted: return .denied @@ -36,7 +36,7 @@ internal extension Permission { @unknown default: return .notDetermined } } - + func requestPhotos(_ callback: @escaping Callback) { guard let _ = Bundle.main.object(forInfoDictionaryKey: .photoLibraryUsageDescription) else { print("WARNING: \(String.photoLibraryUsageDescription) not found in Info.plist") diff --git a/Source/PermissionTypes/Reminders.swift b/Source/PermissionTypes/Reminders.swift index 4207878..b41a892 100644 --- a/Source/PermissionTypes/Reminders.swift +++ b/Source/PermissionTypes/Reminders.swift @@ -28,7 +28,7 @@ import EventKit internal extension Permission { var statusReminders: PermissionStatus { let status = EKEventStore.authorizationStatus(for: .reminder) - + switch status { case .authorized: return .authorized case .restricted, .denied: return .denied @@ -36,9 +36,9 @@ internal extension Permission { @unknown default: return .notDetermined } } - + func requestReminders(_ callback: @escaping Callback) { - EKEventStore().requestAccess(to: .reminder) { _,_ in + EKEventStore().requestAccess(to: .reminder) { _, _ in callback(self.statusReminders) } } diff --git a/Source/PermissionTypes/Siri.swift b/Source/PermissionTypes/Siri.swift index 767d5c8..83f2e6f 100644 --- a/Source/PermissionTypes/Siri.swift +++ b/Source/PermissionTypes/Siri.swift @@ -24,7 +24,7 @@ #if PERMISSION_SIRI import Intents - + internal extension Permission { var statusSiri: PermissionStatus { guard #available(iOS 10.0, *) else { fatalError() } @@ -42,7 +42,7 @@ internal extension Permission { print("WARNING: \(String.siriUsageDescription) not found in Info.plist") return } - INPreferences.requestSiriAuthorization({ (status) in + INPreferences.requestSiriAuthorization({ (_) in callback(self.statusSiri) }) } diff --git a/Source/PermissionTypes/SpeechRecognizer.swift b/Source/PermissionTypes/SpeechRecognizer.swift index e3afaa1..b1c273e 100644 --- a/Source/PermissionTypes/SpeechRecognizer.swift +++ b/Source/PermissionTypes/SpeechRecognizer.swift @@ -28,9 +28,9 @@ import Speech internal extension Permission { var statusSpeechRecognizer: PermissionStatus { guard #available(iOS 10.0, *) else { fatalError() } - + let status = SFSpeechRecognizer.authorizationStatus() - + switch status { case .authorized: return .authorized case .restricted, .denied: return .denied @@ -38,20 +38,20 @@ internal extension Permission { @unknown default: return .notDetermined } } - + func requestSpeechRecognizer(_ callback: @escaping Callback) { guard #available(iOS 10.0, *) else { fatalError() } - + guard let _ = Bundle.main.object(forInfoDictionaryKey: .microphoneUsageDescription) else { print("WARNING: \(String.microphoneUsageDescription) not found in Info.plist") return } - + guard let _ = Bundle.main.object(forInfoDictionaryKey: .speechRecognitionUsageDescription) else { print("WARNING: \(String.speechRecognitionUsageDescription) not found in Info.plist") return } - + SFSpeechRecognizer.requestAuthorization { _ in callback(self.statusSpeechRecognizer) } diff --git a/Source/Supporting Files/Utilities.swift b/Source/Supporting Files/Utilities.swift index eadb17a..aaea188 100644 --- a/Source/Supporting Files/Utilities.swift +++ b/Source/Supporting Files/Utilities.swift @@ -25,14 +25,14 @@ extension UIApplication { fileprivate var topViewController: UIViewController? { var vc = delegate?.window??.rootViewController - + while let presentedVC = vc?.presentedViewController { vc = presentedVC } return vc } - + internal func presentViewController(_ viewController: UIViewController, animated: Bool = true, completion: (() -> Void)? = nil) { topViewController?.present(viewController, animated: animated, completion: completion) } @@ -57,8 +57,7 @@ internal extension String { static let cameraUsageDescription = "NSCameraUsageDescription" static let mediaLibraryUsageDescription = "NSAppleMusicUsageDescription" static let siriUsageDescription = "NSSiriUsageDescription" - - + static let requestedNotifications = "permission.requestedNotifications" static let requestedLocationAlwaysWithWhenInUse = "permission.requestedLocationAlwaysWithWhenInUse" static let requestedMotion = "permission.requestedMotion" @@ -78,27 +77,27 @@ extension UserDefaults { get { return bool(forKey: .requestedLocationAlwaysWithWhenInUse) } set { set(newValue, forKey: .requestedLocationAlwaysWithWhenInUse) } } - + var requestedNotifications: Bool { get { return bool(forKey: .requestedNotifications) } set { set(newValue, forKey: .requestedNotifications) } } - + var requestedMotion: Bool { get { return bool(forKey: .requestedMotion) } set { set(newValue, forKey: .requestedMotion) } } - + var requestedBluetooth: Bool { get { return bool(forKey: .requestedBluetooth) } set { set(newValue, forKey: .requestedBluetooth) } } - + var statusBluetooth: PermissionStatus? { get { return PermissionStatus(string: string(forKey: .statusBluetooth)) } set { set(newValue?.rawValue, forKey: .statusBluetooth) } } - + var stateBluetoothManagerDetermined: Bool { get { return bool(forKey: .stateBluetoothManagerDetermined) } set { set(newValue, forKey: .stateBluetoothManagerDetermined) } @@ -116,7 +115,7 @@ internal extension NotificationCenter { func addObserver(_ observer: AnyObject, selector: Selector, name: NSNotification.Name?) { addObserver(observer, selector: selector, name: name!, object: nil) } - + func removeObserver(_ observer: AnyObject, name: NSNotification.Name?) { removeObserver(observer, name: name, object: nil) } diff --git a/Tests/PermissionTests.swift b/Tests/PermissionTests.swift index 63dada3..5afcbac 100644 --- a/Tests/PermissionTests.swift +++ b/Tests/PermissionTests.swift @@ -25,5 +25,5 @@ import XCTest class PermissionTests: XCTestCase { - + }