Coder Social home page Coder Social logo

jevonmao / permissionsswiftui Goto Github PK

View Code? Open in Web Editor NEW
1.4K 10.0 77.0 19.7 MB

A SwiftUI package to beautifully display and handle permissions.

Home Page: https://jevonmao.github.io/PermissionsSwiftUI/

License: MIT License

Swift 99.59% Ruby 0.41%
swiftui swiftui-learning learn-swift swift ios macos ios-swift package swiftpackage library

permissionsswiftui's Introduction



PermissionsSwiftUI: A SwiftUI package to handle permissions

PermissionsSwiftUI displays and handles permissions in SwiftUI. It is largely inspired by SPPermissions. The UI is highly customizable and resembles an Apple style. If you like the project, please star ★.

PermissionsSwiftUI looks equally gorgeous on both ☀️light and 🌑 dark mode.

🧭 Navigation

Usage
Additional Information

🖥️ Installation

Requirements

  • iOS 11 (SwiftUI require iOS 13.0) or iPadOS 13
  • Xcode 12 and Swift 5.3
  • tvOS support coming soon
  • No MacOS, and WatchOS support for now

Install

Swift Package Manager (Recommended)

You can install PermissionsSwiftUI into your Xcode project via SPM. To learn more about SPM, click here

  1. In Xcode 12, open your project and navigate to FileSwift PackagesAdd Package Dependency...

For Xcode 13, navigate to FilesAdd Package

  1. Paste the repository URL (https://github.com/jevonmao/PermissionsSwiftUI) and click Next.
  2. For Version, verify it's Up to next major.
  3. Click Next and ONLY SELECT PERMISSIONS NEEDED else Apple will reject your app

(You don't need to add CorePermissionsSwiftUI or PermissionsSwiftUI)

image

  1. Click Finish
  2. You are all set, thank you for using PermissionsSwiftUI!

Cocoapods (Deprecated)

You can also install PermissionsSwiftUI with Cocoapods. Add pod 'PermissionsSwiftUI' in your podfile:

platform :ios, '14.0'

target 'test abstract' do
  use_frameworks!
  pod 'PermissionsSwiftUI'

end

🚀 Quickstart

Before you start, please star ★ this repository. Your star is my biggest motivation to pull all-nighters and maintain this open-source project.

⚠️ v1.4.0 Migration Guide

v1.4 is here! If you encounter any issues, please check out the migration guide designed to help developers resolve any deprecations and API updates.

Modal Style

To use PermissionsSwiftUI, simply add the JMModal modifier to any view:

.JMModal(showModal: $showModal, for: [.locationAlways, .photo, .microphone])`

Pass in a Binding<Bool> to show the modal view, and add whatever permissions you want to show. For example:

   struct ContentView: View {
       @State var showModal = false
       var body: some View {
           Button(action: {
               showModal=true
           }, label: {
               Text("Ask user for permissions")
           })
           .JMModal(showModal: $showModal, for: [.locationAlways, .photo, .microphone])
       }
   }

Alert Style

The alert style is equally gorgeous, and allows for more versatile use. It is recommended when you have less than 3 permissions.
To show a permission pop up alert, use:
.JMAlert(showModal: $showModal, for: [.locationAlways, .photo])

Similar to the previous JMPermissions, you need to pass in a Binding<Bool> to show the view, and add whatever permissions you want to show. To quickly glance at all of PermissionsSwiftUI's customization and configurations, check out the cheatsheet!





🛠️ Usage

Customize Permission Texts

To customize permission texts, use the modifier setPermissionComponent() For example, you can change title, description, and image icon:

.setPermissionComponent(for: .camera, 
                        image: AnyView(Image(systemName: "camera.fill")), 
                        title: "Camcorder",
                        description: "App needs to record videos")

and the result:


Or only change 1 of title and description:
setPermissionComponent(for: .tracking, title: "Trackers")
setPermissionComponent(for: .tracking, description: "Tracking description")

Note:

  • The parameters you don't provide will show the default text
  • Add the setPermissionComponent modifier on your root level view, after JMPermissions modifier

The image parameter accepts AnyView, so feel free to use SF Symbols or your custom asset:

.setPermissionComponent(for: .camera, 
                        image: AnyView(Image("Your-cool-image"))

Even full SwiftUI views will work😱:

.setPermissionComponent(for: .camera, 
                        image: AnyView(YourCoolView())

You can use custom text and icons for all the supported permissions, with a single line of code.

Customize Header Texts

To customize the header title, use the modifier changeHeaderTo: Annotated for headers screen

.JMPermissions(showModal: $showModal, for: [.camera, .location, .calendar])
.changeHeaderTo("App Permissions")

To customize the header description, use the modifier changeHeaderDescriptionTo:

.JMPermissions(showModal: $showModal, for: [.camera, .location, .photo])
.changeHeaderDescriptionTo("Instagram need certain permissions in order for all the features to work.")

To customize the bottom description, use the modifier changeBottomDescriptionTo:

.JMPermissions(showModal: $showModal, for: [.camera, .location, .photo])
.changeBottomDescriptionTo("If not allowed, you have to enable permissions in settings")

onAppear and onDisappear Override

You might find it incredibly useful to execute your code, or perform some update action when a PermissionsSwiftUI view appears and disappears.
You can perform some action when PermissionsSwiftUI view appears or disappears by:

.JMPermissions(showModal: $showModal, for: [.locationAlways, .photo, .microphone], onAppear: {}, onDisappear: {})

The onAppear and onDisappear closure parameters will be executed everytime PermissionsSwiftUI view appears and disappears.
The same view modifier closure for state changes are available for the JMAlert modifier:

.JMAlert(showModal: $showModal,
                     for: [.locationAlways, .photo],
                     onAppear: {print("Appeared")},
                     onDisappear: {print("Disappeared")})

Auto Check Authorization

PermissionsSwiftUI by default will automatically check for authorization status. It will only show permissions that are currently notDetermined status. (the iOS system prevents developers from asking for denied permissions. Allowed permissions will also be ignored by PermissionsSwiftUI). If all permissions are allowed or denied, PermissionsSwiftUI will not show the modal or alert at all. To set auto check authorization, use the autoCheckAuthorization parameter:

.JMModal(showModal: $showModal, for: [.camera], autoCheckAuthorization: false)

same applies for JMAlert

.JMAlert(showModal: $showModal, for: [.camera], autoCheckAuthorization: false)

Auto Dismiss

PermissionsSwiftUI by default will not have any auto dismiss behavior. You can override this behavior to make it automatically dismiss the modal or alert after the user allows the last permission item. (All permissions must be ALLOWED, if any is DENIED, it will not auto dismiss).

.JMModal(... autoDismiss: Bool) -> some View

Pass in true or false to select whether to automatically dismiss the view.

Customize Colors

Using PermissionSwiftUI's capabilities, developers and designers can customize all the UI colors with incredible flexibility. You can fully configure all color at all states with your custom colors.
To easily change the accent color:

.setAccentColor(to: Color(.sRGB, red: 56/255, green: 173/255,
                                  blue: 169/255, opacity: 1))

To change the primary (default Apple blue) and tertiary (default Apple red) colors:

.setAccentColor(toPrimary: Color(.sRGB, red: 56/255, green: 173/255,
                                  blue: 169/255, opacity: 1),
                toTertiary: Color(.systemPink))

⚠️ .setAccentColor() and .setAllowButtonColor() should never be used at the same time.

To unleash the full customization of all button colors under all states, you need to pass in the AllButtonColors struct:

.setAllowButtonColor(to: .init(buttonIdle: ButtonColor(foregroundColor: Color,
                                                               backgroundColor: Color),
                                       buttonAllowed: ButtonColor(foregroundColor: Color,
                                                                  backgroundColor: Color),
                                       buttonDenied: ButtonColor(foregroundColor: Color,
                                                                 backgroundColor: Color)))

For more information regarding the above method, reference the official documentation.

Restrict Dismissal

PermissionsSwiftUI will by default, prevent the user from dismissing the modal and alert before all permissions have been interacted with. This means if the user has not explicitly denied or allowed EVERY permission shown, they will not be able to dismiss the PermissionsSwiftUI view. This restricts dismissal behavior can be overridden by the var restrictModalDismissal: Bool or var restrictAlertDismissal: Bool properties. To disable the default restrict dismiss behavior:

.JMModal(showModal: $show, for permissions: [.camera], restrictDismissal: false)

You can also configure with the model:

let model: PermissionStore = {
        var model = PermissionStore()
        model.permissions = [.camera]
        model.restrictModalDismissal = false
        model.restrictAlertDismissal = false
        return model
    }
    ......

    .JMModal(showModal: $showModal, forModel: model)

Configuring Health Permissions

Unlike all the other permissions, the configuration for health permission is a little different. Because Apple requires developers to explicitly set read and write types, PermissionsSwiftUI greatly simplifies the process.

HKAccess

The structure HKAccess is required when initializing health permission’s enum associated values. It encapsulates the read and write type permissions for the health permission.

To set read and write health types (activeEnergyBurned is used as example here):

let healthTypes = Set([HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!])
.JMModal(showModal: $show, for: [.health(categories: .init(readAndWrite: healthTypes))])

//Same exact syntax for JMAlert styles
.JMAlert(showModal: $show, for: [.health(categories: .init(readAndWrite: healthTypes))])

To set read or write individually:

let readTypes = Set([HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!])
let writeTypes = Set([HKSampleType.quantityType(forIdentifier: .appleStandTime)!])
.JMModal(showModal: $showModal, for: [.health(categories: .init(read: readTypes, write: writeTypes))])

You may also set only read or write type:

let readTypes = Set([HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!])
.JMModal(showModal: $showModal, for: [.health(categories: .init(read: readTypes))])

📖 Cheatsheet

Modifiers

Customize overall accent color:

setAccentColor(to:)
setAccentColor(toPrimary:toTertiary:)

Customize title:

changeHeaderTo(_:)

Customize top description:

changeHeaderDescriptionTo(_:)

Customize bottom description:

changeBottomDescriptionTo(_:)

Customize each permission's displayed text & image:

setPermissionComponent(for:image:title:description:)

setPermissionComponent(for:title:)

setPermissionComponent(for:description:)

Customize allow button's colors:

setAllowButtonColor(to:)

Automatically dismiss after last

autoDismiss: Bool

Parameters of JMModal and JMAlert

Check authorization before showing modal or alert

autoCheckAuthorization: Bool

Prevent dismissing before all permissions interacted

restrictDismissal: Bool

Do something right before view appear

onAppear: () -> Void

Do something right before view disappear

onDisappear: (() -> Void

🧰 Supported Permissions

Here is a list of all the permissions PermissionsSwiftUI supports. Yup, even the newest tracking permission for iOS 14 so you can stay on top of your game. All permissions in PermissionsSwiftUI come with a default name, description, and a stunning Apple native SF Symbols icon.

Support for FaceID permission is work in progress and coming soon! If you don't find a permission you need, open an issue. Even better, build it yourself and open a pull request, you can follow this step-by-step guide on adding new permissions.


A card of all the permissions

💪 Contribute

Contributions are welcome here for coders and non-coders alike. No matter what your skill level is, you can for certain contribute to PermissionSwiftUI's open source community. Please read contributing.md before starting, and if you are looking to contributing a new type of iOS permission, be sure to read this step-by-step guide.

If you encounter ANY issue, have ANY concerns, or ANY comments, please do NOT hesitate to let me know. Open a discussion, issue, or email me. As a developer, I feel you when you don't understand something in the codebase. I try to comment and document as best as I can, but if you happen to encounter any issues, I will be happy to assist in any way I can.

Additional Information

Acknowledgement

SPPermissions is in large a SwiftUI remake of the famous Swift library SPPermissions by @verabeis. SPPermissions was initially created in 2017, and today on GitHub has over 4000 stars. PermissionsSwiftUI aims to deliver a just as beautiful and powerful library in SwiftUI. If you star ★ my project PermissionsSwiftUI, be sure to check out the original project SPPermissions where I borrowed the UI Design, some parts of README.md page, and important source code references along the way.

License

PermissionsSwiftUI is created by Jingwen (Jevon) Mao and licensed under the MIT License

permissionsswiftui's People

Contributors

binzinz avatar charlessnow avatar connyhald avatar delvinwidjaja avatar derech1e avatar e-001 avatar fnazarios avatar forgot avatar halilibrahimoztekin avatar itsliamdowd avatar jevonmao avatar khuffie avatar n3v1 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

permissionsswiftui's Issues

[BUG] - Using .JMModal with .sheet cause modal not to show

Describe the bug
A clear and concise description of what the bug is.

I'm using .JMModal on my login view and also in this view I have .sheet but .JMModal won't show when I have .sheet.
If I delete that lines of code, then .JMModal show perfectly.

Screen Shot 2021-03-31 at 11 09 24 PM

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [e.g. iOS] MacOS 11.2.3
  • Browser [e.g. chrome, safari] Safari
  • Version [e.g. 22]

Smartphone (please complete the following information):

  • Device: [e.g. iPhone6] iPhone 8, Simulator (iPhone 12 Pro)
  • OS: [e.g. iOS8.1] iOS 14.5
  • Browser [e.g. stock browser, safari] safari
  • Version [e.g. 22]

Additional context
Add any other context about the problem here.

Social media promotion checklist

  • Post on my personal Instagram
  • Post on my personal Twitter
  • Reddit preview video - Swift
  • Reddit preview video - SwiftUI
  • Reddit preview video - iOS Developer
  • Reddit promo post - Swift
  • Reddit promo post - SwiftUI
  • Reddit promo post - iOS Developer
  • Project Hunt
  • Beta Page
  • Email the Redditor who talked about a SwiftUI lecture session
  • Hackathons
  • HackerNews (Sunday)

[Action] - Create a structure to encapsulate health permission read, write, and both

Overview

We should use a struct to encapsulate health permission case in PermissionType enum's associated value.

Because health permission is special and involves specific read and write permissions, the associated values for the health enum case can have different possibilities. Swift does not allow enum overloading, so its best to use a structure to encapsulate the information. Reference code snippets in Visual References section.

Action items

  • Create new structure for encapsulating
  • Modify PermissionType enum
  • Modify related permission manager code to get information from new struct
  • Run all unit tests, write new tests (as required)
  • Commit & PR!

Visual References

The current declaration for health permission case looks like this:

case health(toShare: Set<HKSampleType>, read: Set<HKSampleType>)

Both toShare and read are non-optional associated values. However, this unnecessarily complicates situations where developers want read and write permission for all the enum cases.
Currently, there is no flexibility and toShare and read parameter must have values, even if they duplicate

//Duplicated code for toShare and read parameters
[.health(toShare: Set([HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!]),
                                              read: Set([HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!]))]

This is the goal:

//Overloading HKAccess initializer
[.health(HKAccess(read: ..., write: ...)]
[.health(HKAccess(write: ...)]
[.health(HKAccess(readAndWrite: ...)]

Special Instructions

N/A

[Action] - Refactor all view properties into proper MVVM view model

Overview

An overview description of this task, along with a reference to the actual bug or feature issue like: tracking feature #72.

Action items

  • Step 1...
  • Step 2...
  • Step 3...

Visual References

Put all the instructional images, visuals, and prototypes here for reference.

Special Instructions

Add special instructions, warnings, previous issues, and other related stuff here, if applicable.

Add ability to customize accent colour

The default colour is blue for PermissionsSwiftUI, which doesn't quite work with my app's design.

For the permission images, I can pass in custom images and provide them with my preferred accent colour.

For the buttons, there seems to be no way to customize them. I see in the source code "ButtonStatusColor", but as it's not a public class I cannot extend it and over-ride it.

Being able to pass in an accent colour that when calling .JMModal would be great!

[Action] - Refactor JMHealthPermissionManager to avoid a force unwrap in intializers

Overview

An overview description of this task, along with a reference to the actual bug or feature issue like: tracking feature #72.

Action items

  • Step 1...
  • Step 2...
  • Step 3...

Visual References

Put all the instructional images, visuals, and prototypes here for reference.

Special Instructions

Add special instructions, warnings, previous issues, and other related stuff here, if applicable.

[Action] Finish implementing common interface for modal and alert modifier API

Overview

An overview description of this task, along with a reference to the actual bug or feature issue like: tracking feature #72.

Action items

  • Step 1...
  • Step 2...
  • Step 3...

Visual References

Put all the instructional images, visuals, and prototypes here for reference.

Special Instructions

Add special instructions, warnings, previous issues, and other related stuff here, if applicable.

[BUG] - restrictDismissal not working

Hello,

My app got rejected because the X button in the modal doesn't work. Looking at 1.3.0, I see restrictDismissal is a setting that's available.

Unfortunately, it doesn't seem to work.

Here's my code:

                .JMModal(
                    showModal: $appState.showPermissionsDialogue,
                    
                    for: [.locationAlways, .calendar, .reminders, .health(categories: .init(read: HealthKitHelper.shared.permissionGroups.allTypes, write: HealthKitHelper.shared.permissionGroups.toWrite) )],
                    autoDismiss: true,
                    autoCheckAuthorization: true,
                    restrictDismissal: false,
                    onAppear: {},
                    onDisappear: {
                        EventsHelper.shared.getAuthorizationStatus()
                        
                    }
                )

Closure to deliver back permission authorization status

Is your feature request related to a problem? Please describe.
It will be really helpful if there can be a closure to deliver back the results of the permission request. I might want to program certain actions to take place after the permission request, and I want to know what permissions are denied, and what permissions are allowed, along with any error in the process.

Describe the solution you'd like
Ideal closure would be integrated with the onDisappear, pass back a structure of JMResult which encapsulates each individual permission's authorization status, and error if any error were to occur.

Describe alternatives you've considered
N/A

Additional context
Ideal implementation:

        .JMAlert(showModal: $showModal,
                 for: [.camera, .locationAlways],
                 autoDismiss: true,
                 onAppear: {},
                 onDisappear: {(result: [JMResult], error: Error) in
                    guard error == nil else {print(error)}
                    if cameraAuth = result[0].authorizationStatus
                 })
    }

[BUG] - Health authorization read only crash

Describe the bug
A clear and concise description of what the bug is.

PermissionSwiftUI 1.4.1
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Must request authorization for at least one data type'

To Reproduce

let readData = Set([HKObjectType.workoutType(),
                                    HKObjectType.quantityType(forIdentifier: .stepCount)!,
                                    HKObjectType.quantityType(forIdentifier: .distanceWalkingRunning)!,
                                    HKObjectType.quantityType(forIdentifier: .activeEnergyBurned)!
                                    ,HKObjectType.quantityType(forIdentifier: .appleStandTime)!
                                    ])

.JMModal(showModal:$showPermission,for:[.locationAlways,.health(categories: .init(read: readData)),.notification])

Expected behavior
A clear and concise description of what you expected to happen.

in mapPermissionAuthorizationStatus, input is Set<HKSampleType>, however I'm using HKObjectType and it cause error

***Update:
Tried with HKSampleType but still crash as I click to allow permission of Health.

*** update:
tried to downcast to PermissionSwiftUI 1.3.0, everything working fine!

[Action] - Fix awkward "compute once only" property in ModalMainView and PermissionSection

Overview

An overview description of this task, along with a reference to the actual bug or feature issue like: tracking feature #72.

Action items

  • Step 1...
  • Step 2...
  • Step 3...

Visual References

Put all the instructional images, visuals, and prototypes here for reference.

Special Instructions

Add special instructions, warnings, previous issues, and other related stuff here, if applicable.

[BUG] - On click of Allow push notifications fails

Hi, I've set up my iOS app to ask for permissions like so:
.JMModal(showModal: self.$showModal, for: [.locationAlways, .notification])
Allowing location successfully changes button to allowed, but allowing push notifications does not change the button to allowed, therefore, I cannot exit the modal.

However, I do see printouts in my appDelegate's didRegisterForRemoteNotificationsWithDeviceToken: saying that I have successfully registered? Everytime I click allow I see the button. I only see the Apple alert for allowing push notifications the very first time. But, button does not change to allowed.

To Reproduce
Steps to reproduce the behavior:

  1. Show JMModal with .locationAlways and .notification
  2. Allow Notifications
  3. See error

push notifications should change button to allowed and be able to dismiss.

Desktop (please complete the following information):

  • OS: iOS
  • Version 1.4

Smartphone (please complete the following information):

  • Device: iPhone 12 Pro device

Additional context
Add any other context about the problem here.

[Action] - JMModal custom configurations are not working

Overview

An overview description of this task, along with a reference to the actual bug or feature issue like: tracking feature #72.

Action items

  • Step 1...
  • Step 2...
  • Step 3...

Visual References

Put all the instructional images, visuals, and prototypes here for reference.

Special Instructions

Add special instructions, warnings, previous issues, and other related stuff here, if applicable.

[Action] - Debug location permission that is not working

Overview

An overview description of this task, along with a reference to the actual bug or feature issue like: tracking feature #72.

Action items

  • Step 1...
  • Step 2...
  • Step 3...

Visual References

Put all the instructional images, visuals, and prototypes here for reference.

Special Instructions

Add special instructions, warnings, previous issues, and other related stuff here, if applicable.

Update to platform iOS 14

Is your feature request related to a problem? Please describe.
I am building an app for iOS 14 but this package is only available for iOS 13.

Describe the solution you'd like
Update this package for use with iOS 14 in Package.swift.

Describe alternatives you've considered
No alternatives yet.

Additional context
N/A.

[Action] Fix initializer default implementation in PermissionManagerProtocol

Overview

An overview description of this task, along with a reference to the actual bug or feature issue like: tracking feature #72.

Action items

  • Step 1...
  • Step 2...
  • Step 3...

Visual References

Put all the instructional images, visuals, and prototypes here for reference.

Special Instructions

Add special instructions, warnings, previous issues, and other related stuff here, if applicable.

[Action] - Create new enum for selecting permission type in customizing components

Overview

Currently, the one and only PermissionType enum is used to designate a specific type of iOS system permission. However, the health permission require an associated value to be passed in, and lead to unnecessary complications when customizing the health component. Please see visual references section. No tracking issue.

Action items

  • Create new enum (name it meaningfully)
  • Add a conformance to shared enum protocol, and define default value for currentPermission so it can be extracted
  • Replace the PermissionType usage in custom modifiers with the new enum
  • Create test Xcode project to test, run unit test, commit and PR!

Visual References

For example, here I use a JMAlert popup with health and camera permission. I customize health permission with a title.

//Here the associated value is used to specify types of health permission.
.JMAlert(showModal: .constant(true),
         for: [.health(([HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!])),
               .camera])
//There is no point in passing in the entire HKSample type here again. Too much clutter.
.setPermissionComponent(for: .health([HKSampleType.quantityType(forIdentifier: .activeEnergyBurned)!]),
                        title: "My New Title")

Special Instructions

Easy task here. I highly recommend you contribute, even if you barely have any experience with Swift or SwiftUI.

[Refactor] Simplify custom text and image modifiers

If possible, we should refactor over 40 modifiers for customizing the title and description of individual permissions into 1 single modifier. Ex. .setPermissionTextTo(for permission:[Enum], to title:String) The enum should reflect a type for all permissions.
However, we won't fix this until ready for a major release. This will cause major API changes.

[Feature] - Automatically check if permission already granted, and only show alert if not granted

Is your feature request related to a problem? Please describe.
No.

Describe the solution you'd like
When developers are using the powerful feature of PermissionsSwiftUI in their iOS app, they might want to show the JMModal only on first app launch. Or, they might only want to show the JMAlert for camera permission right before user needs to use the camera. However, the alert and modal should not pop up, if permission is already granted.

Describe alternatives you've considered
Currently, without a built in auto permission authorization check, developers will have to implement their own authorization checking. That means importing all the related Apple modules, and interfacing with things like HealthKit and EventKit which defeats the purpose of PermissionsSwiftUI.

Additional context
This issue is tracked by #28

[Feature] - Make transition animation for JMAlert smoother

Is your feature request related to a problem? Please describe.
The popup animation for JMAlert is not smooth and fluid like Apple's native alert, especially when closing it.

Describe the solution you'd like
Custom implementation of AnyTransition.

Unsafe Flags - Can't build any longer

Describe the bug
Here is the alert I get when trying to build:
The package product 'PermissionsSwiftUI' cannot be used as a dependency of this target because it uses unsafe build flags.
This happens when updating to versions 1.4.0 or 1.4.1.
Version 1.3.0 still builds.

To Reproduce
Steps to reproduce the behavior:
Just build & run

Expected behavior
A clear and concise description of what you expected to happen.

Screenshots
If applicable, add screenshots to help explain your problem.

Desktop (please complete the following information):

  • OS: [iOS 14]

Additional context
Add any other context about the problem here.

[Action] Write unit tests for the new, redesigned code base for above 80% coverage

Overview

An overview description of this task, along with a reference to the actual bug or feature issue like: tracking feature #72.

Action items

  • Step 1...
  • Step 2...
  • Step 3...

Visual References

Put all the instructional images, visuals, and prototypes here for reference.

Special Instructions

Add special instructions, warnings, previous issues, and other related stuff here, if applicable.

[Action] Prepare for next version release. Write new documentation, update existing README, and migration guide

Overview

An overview description of this task, along with a reference to the actual bug or feature issue like: tracking feature #72.

Action items

  • Step 1...
  • Step 2...
  • Step 3...

Visual References

Put all the instructional images, visuals, and prototypes here for reference.

Special Instructions

Add special instructions, warnings, previous issues, and other related stuff here, if applicable.

Use if #available version checking to conditionally create the tracking permission case

Currently, the PermissionModel enum includes tracking as an accessible enum case for all versions (13.0). However, the tracking permission is only available in iOS 14+, thus it does not make sense to show a tracking permission in targets below 14.0.

Need to figure out a way to conditionally include the tracking enum case. The requestPermission method also need to have a version check if the current enum case is tracking.

[Action] - Allow some kind of data model to customize behaviors

Overview

A Redditor suggested that we provide a data model to be passed in to customize behaviors. When developers need to customize multiple, complex behaviors of PermissionsSwiftUI, they will have to write a stack of messy modifiers. However, a PermissionStore model that can be extracted into a view model will allow more efficient and cleaner customization. Tracking #20.

Reference code snippet 1 and code snippet 2 for a direct comparison.

Action items

  • Mark PermissionStore as public. Extract the shared and mutableShared into a private extension, not accessible by API.
  • Make JMPermission's authorized property private, inaccessible from API.
  • Add a new function to PermissionStore that updates the entire model in shared property
  • Add new view modifier APIs under ../JMPermission API/MainModifiers.swift
  • Implement logic in the modifier's method, update PermissionStore source of truth
  • DOCUMENT every single new public API added
  • Create new Xcode test app to test, run unit test (only if required), commit, and pull request.

Visual References

Code Snippets

Currently, this is how you would customize PermissionsSwiftUI components:

        .JMModal(showModal: $showModal,
                 for: [.health(healthPermissions),.calendar,
                       .bluetooth,.locationAlways, .microphone],
                 autoDismiss: true,
                 onAppear: {
                    
                 },
                 onDisappear: {
                    
                 })
        .changeHeaderTo("New Header!")
        .changeHeaderDescriptionTo("PermissionsSwiftUI is the best iOS library!")
        .changeBottomDescriptionTo("PermissionsSwiftUI is the best iOS library!")
        .setPermissionComponent(for: .health(healthPermissions), image: AnyView, title: String?, description: String?)
        .setPermissionComponent(for: .calendar, image: AnyView, title: String?, description: String?)
        .setPermissionComponent(for: .bluetooth, image: AnyView, title: String?, description: String?)
        .setPermissionComponent(for: .locationAlways, image: AnyView, title: String?, description: String?)
        .setPermissionComponent(for: .microphone, image: AnyView, title: String?, description: String?)

This is the ideal result, a data model that supplement the modifier method:

    let model: PermissionStore = {
        var model = PermissionStore()
        model.permissions = [.camera, .health]
        model.mainTexts.headerText = "Some title"
        model.mainTexts.headerDescription = "Some description to be shown"
        model.mainTexts.bottomDescription = "Some description to be shown"
        model.healthPermission = JMPermission(imageIcon: AnyView(Image(systemName: "heart.fill")),
                                              title: "Health",
                                              description: "Allow to access your health information",
                                              authorized: false)
        return model
    }
    ......
    
    .JMModal(showModal: $showModal, forModel: model)

Special Instructions

N/A

[BUG] - For Health permissions, read and write permissions are switched.

I was getting the following error when trying to authorize HealthKit permissions:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Authorization to share the following types is disallowed: HKQuantityTypeIdentifierAppleExerciseTime, HKQuantityTypeIdentifierAppleStandTime'
I was pretty sure that I was initializing HKAccess with the correct permissions for read and write (aka toShare).

Digging into the code, In HMHealthPermissionManager.requestPermission, line 93 and 94 are as follows:

        healthStore.requestAuthorization(toShare: Set(healthPermission?.readPermissions ?? []),
                                         read: Set(healthPermission?.writePermissions ?? [])) { authorized, error in

"toShare" should be looking at the .writePermissions, not the readPermissions, so it should be:

        healthStore.requestAuthorization(toShare: Set(healthPermission?.writePermissions ?? []),
                                         read: Set(healthPermission?.readPermissions ?? [])) { authorized, error in

Btw: it would be good to add documentation on how to request health permissions in the README, I had to dig into the source code to figure it out :)

Use generics to replace AnyView

Using AnyView is bad practice, and if it can be replaced (and I believe it can in this case) it should be. With just a few changes, MainView.swift would be modified to look like this:

struct MainView<BodyView: View>: View {
    private var showModal: Binding<Bool>
    private var bodyView: BodyView
    init(for bodyView: BodyView, show showModal: Binding<Bool>) {
        self.bodyView = bodyView
        self.showModal = showModal
    }

    var body: some View {
        bodyView
            .sheet(isPresented: showModal, content: {
                ModalView(showModal: showModal)
            })
            
    }
}

AnyView is used in many places and most (if not all) of them can be replaced with generics. This won't break anyone's existing code either, the type will not be MainView, it will be MainView<AnyView>. AnyView should be switched for generics in JMPermission (for the imageIcon) as well. This helps SwiftUI update views more efficiently and prevents always casting the image to AnyView like is currently in the README:

.setPermissionComponent(for: .camera, 
                        image: AnyView(Image(systemName: "camera.fill")), 
                        title: "Camcorder",
                        description: "App needs to record videos")

[Action] - Automatically check if permission already granted, and only show alert if not granted

Overview

The JMModal might be shown once at initial launch, and the JMAlert should only show if permission is not granted. PermissionsSwiftUI will awkwardly show a pop-up every single time. There needs to be an automatic checking for permission granted status before built into PermissionsSwiftUI. Tracking #26

Action items

  • Expose authorization status in permission managers
  • Expose a property for access in PermissionType
  • Add new parameter for auto checking in public API
  • Check for authorization, and display PermissionsSwiftUI view accordingly
  • DOCUMENT every single new API added
  • Create new Xcode test app to test, write unit tests, commit, and pull request.

Visual References

Put all the instructional images, visuals, and prototypes here for reference.

Special Instructions

⚠️ One potential problem I see:
First, Apple's APIs for permission authorization status checking are asynchronous. It might introduce a delay to the PermissionsSwiftUI modal or alert.

✅ ❌ Be sure to write new unit tests, and ensure all unit tests pass.

[Action] Add media player (Apple Music) permission

Overview

Suggested by Gilles through email. Add the media player (Apple Music) permission into PermissionsSwiftUI's supported permissions. The media player permission is needed to play music through Apple Music.

Action items

  • Create new permission manager class and related functions implementation
  • Create public API for new permission
  • Run all unit tests, write tests
  • Commit & PR!

Visual References

Media Player Framework
Permission description

Special Instructions

To contributors: please hold off on taking this issue for now. I am in progress of MAJOR refactoring that will change a lot of the code base. The refactoring should be finished by 3/25.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.