Files
Jevon MaoandGitHub fbb88cf279 Release 1.5.8 (#138)
* Add API boilerplate for new calendar and reminder

Addresses iOS 17 API changes

* Abstract calendar/reminder into event manager

* Fix obsolete API mark and revise message

* Squashed commit of the following:

commit 5ecef99e3b2ef04a2a05b34509e8a449031d92c4
Author: Jevon Mao <woodburyjevonmao@gmail.com>
Date:   Tue Aug 8 20:13:01 2023 -0400

    Add documentation snippet for permission managers

commit 44e3f41313
Author: Jevon Mao <woodburyjevonmao@gmail.com>
Date:   Mon Aug 7 14:41:46 2023 -0400

    Implement custom permission description color (#137)

commit f3ed32ce20
Author: Jevon Mao <woodburyjevonmao@gmail.com>
Date:   Mon Aug 7 12:58:42 2023 -0400

    Disable stale check CICD

* Erase type for custom foreground color

* Add NSLog warning deprecated EventKit permissisons

* Remove available limitation
2023-08-26 12:18:25 -07:00

95 lines
3.8 KiB
Swift

//
// JMPermissionsView.swift
//
//
// Created by Jevon Mao on 1/30/21.
//
import SwiftUI
import Introspect
@available(iOS 13.0, tvOS 13.0, *)
@usableFromInline struct ModalViewWrapper<Body: View>: View, CustomizableView {
//store contains static configurations and customizations
@usableFromInline var store: PermissionStore
//schemaStore contains dynamically computed properties, and internal methods/properties
@usableFromInline var schemaStore: PermissionSchemaStore
//Keep track of whether modal as already been shown for 1st time
@State var isModalNotShown = true
@usableFromInline var showing: Binding<Bool>
@usableFromInline var bodyView: Body
//Placeholder to make sure permissionsToAsk only get computed value once
//Otherwise, the list of permissions will change while the modal is still open, which is not good
var _permissionsToAsk: [PermissionManager]?
var permissionsToAsk: [PermissionManager] {
guard _permissionsToAsk == nil else {
return _permissionsToAsk!
}
return schemaStore.undeterminedPermissions
}
var shouldShowPermission: Binding<Bool>{
Binding(get: {
//configStore.autoCheckAuth is added in newer version. autoCheckModalAuth is backward compatibility
if (store.configStore.autoCheckAuth ||
(store.autoCheckModalAuth || store.autoCheckAlertAuth)) &&
//Prevent modal from unwanted dismiss while still presented
isModalNotShown {
//underterminedPermissions.isEmpty => No askable permissions => should not show modal
return !permissionsToAsk.isEmpty
}
//Always show the modal regardless of permission status
return true
}, set: {_ in})
}
@usableFromInline init(for bodyView: Body,
showing: Binding<Bool>,
store: PermissionStore,
permissionsToAsk: [PermissionManager]?=nil) {
self.bodyView = bodyView
self.showing = showing
self._permissionsToAsk = permissionsToAsk
self.store = store
self.schemaStore = PermissionSchemaStore(store: store,
permissionViewStyle: .modal)
}
@usableFromInline var body: some View {
Group {
bodyView
.sheet(isPresented: showing.combine(with: shouldShowPermission), content: {
ModalView(showModal: showing)
//Possible nil, to account for backward compatibility
.onAppear(perform: store.onAppear ?? store.configStore.onAppear)
.onDisappear(perform: store.onDisappear ?? store.configStore.onDisappear)
//Writing duplicate onAppear and OnDisappear is actually less lines of code
.onAppear{isModalNotShown=false}
.onDisappear{showing.wrappedValue = false; isModalNotShown=true}
})
}
.withEnvironmentObjects(store: store, permissionStyle: .modal)
}
//if DEBUG to ensure these functions are never used in production. They are for unit testing only.
#if DEBUG
func testCallOnAppear(){
guard let onAppear = store.configStore.onAppear else {return}
onAppear()
}
func testCallOnDisappear(){
guard let onDisappear = store.configStore.onDisappear else {return}
onDisappear()
}
#endif
}
//Extension Binding wrapper for Binding booleans
@available(iOS 13.0, tvOS 13.0, *)
extension Binding where Value == Bool{
func combine(with value2: Binding<Bool>) -> Binding<Bool>{
//Combine two Binding Bool conditions with AND operator
return self.wrappedValue && value2.wrappedValue ? .constant(true) : .constant(false)
}
}