sparrowcode / PermissionsKit

Universal API for request permission and get its statuses.
https://x.com/sparrowcode_ios
MIT License
5.64k stars 462 forks source link

SwiftUI Implementation #176

Closed doronkatz closed 3 years ago

doronkatz commented 4 years ago

Hi there,

I am trying to get this to work with SwiftUI using UIViewControllerRepresentable. I have the following:

struct PermissionsView: UIViewControllerRepresentable {

    func makeUIViewController(context: UIViewControllerRepresentableContext<PermissionsView>) -> SPPermissionsDialogController {
        let permissionsVC = SPPermissions.dialog([.locationAlwaysAndWhenInUse, .photoLibrary])
        permissionsVC.delegate = context.coordinator
        permissionsVC.present(on: PermissionsView)
        return permissionsVC
    }

    func updateUIViewController(_ uiViewController: SPPermissionsDialogController,
                                                            context: UIViewControllerRepresentableContext<PermissionsView>) {

    }

    func makeCoordinator() -> Coordinator {
        return Coordinator()
    }

I am calling it from ContentView but not sure why its not showing anything. Fairly new to using UIViewControllers within SwiftUI

dmitrym0 commented 4 years ago

@doronkatz you should present your VC in updateUIViewController method

struct PermissionsWrapperView: UIViewControllerRepresentable {
    func makeUIViewController(context: Context) -> SPPermissionsListController {
        let permissionsController = SPPermissions.list([.locationWhenInUse, .locationAlwaysAndWhenInUse])

        return permissionsController
    }

    func updateUIViewController(_ permissionController: SPPermissionsListController, context: Context) {
        permissionController.present(on: UIApplication.shared.keyWindow?.rootViewController! as! UIViewController)
    }
}

How are you showing PermissionsView? I'm getting some artifacts right now and incorrect behavior.

dmitrym0 commented 4 years ago

This is what I see when I invoke the above code from a Table View (see the unattached header):

image
OscarHedeby commented 4 years ago

Hey, here is my implementation:

` import SPPermissions import UIKit import SwiftUI

final class PermissionView: UIViewControllerRepresentable, SPPermissionsDelegate, SPPermissionsDataSource { func makeUIViewController(context: Context) -> SPPermissionsListController { let controller = SPPermissions.list([.photoLibrary, .locationWhenInUse, .notification])

    controller.dataSource = self
    controller.delegate = self

    return controller
}

func updateUIViewController(_ uiViewController: SPPermissionsListController, context: UIViewControllerRepresentableContext<PermissionView>) {

}

/**
Configure permission cell here.
You can return permission if want use default values.

- parameter cell: Cell for configure. You can change all data.
- parameter permission: Configure cell for it permission.
*/
func configure(_ cell: SPPermissionTableViewCell, for permission: SPPermission) -> SPPermissionTableViewCell {
    return cell
}

/**
Call when controller closed.

- parameter ids: Permissions ids, which using this controller.
*/
func didHide(permissions ids: [Int]) {
    let permissions = ids.map { SPPermission(rawValue: $0)! }
    print("Did hide with permissions: ", permissions.map { $0.name })
}

/**
Call when permission allowed.
Also call if you try request allowed permission.

- parameter permission: Permission which allowed.
*/
func didAllow(permission: SPPermission) {
    print("Did allow: ", permission.name)
}

/**
Call when permission denied.
Also call if you try request denied permission.

- parameter permission: Permission which denied.
*/
func didDenied(permission: SPPermission) {
    print("Did denied: ", permission.name)
}

/**
 Alert if permission denied. For disable alert return `nil`.
 If this method not implement, alert will be show with default titles.

 - parameter permission: Denied alert data for this permission.
 */
func deniedData(for permission: SPPermission) -> SPPermissionDeniedAlertData? {
    if permission == .notification {
        let data = SPPermissionDeniedAlertData()
        data.alertOpenSettingsDeniedPermissionTitle = "Permission denied"
        data.alertOpenSettingsDeniedPermissionDescription = "Please, go to Settings and allow permission."
        data.alertOpenSettingsDeniedPermissionButtonTitle = "Settings"
        data.alertOpenSettingsDeniedPermissionCancelTitle = "Cancel"
        return data
    } else {
        // If returned nil, alert will not show.
        print("Alert for \(permission.name) not show, becouse in datasource returned nil for configure data. If you need alert, configure this.")
        return nil
    }
}

} `

Then I can just implement it in SwiftUI like this: View().sheet(isPresented: $missingPermissions) { PermissionView() }

dmitrym0 commented 4 years ago

Yeah, I stand corrected, I used a similar approach:

struct PermissionsWrapperView: UIViewControllerRepresentable {
    @Binding var isShown: Bool

    func makeCoordinator() -> PermissionsWrapperView.Coordinator {
        return Coordinator(self, isShown: $isShown)
    }

    @State var isPresenting = false
    func makeUIViewController(context: Context) -> SPPermissionsListController {
        let permissionsController = SPPermissions.list([.reminders])
        permissionsController.delegate = context.coordinator
        permissionsController.present(on: UIApplication.shared.windows.first?.rootViewController as! UIViewController)
        return permissionsController
    }

     func updateUIViewController(_ permissionController: SPPermissionsListController, context: Context) {
        if (self.isShown) {

        }
    }

    class Coordinator: NSObject, SPPermissionsDelegate {
        var parent: PermissionsWrapperView
        @Binding var isCoordinatorShown: Bool

        init(_ parent: PermissionsWrapperView, isShown: Binding<Bool>) {
            self.parent = parent
            _isCoordinatorShown = isShown

        }

        func didHide(permissions ids: [Int]) {
            print("------------ Hide controller!!!")
            isCoordinatorShown = false
        }

        func didAllow(permission: SPPermission) {
            print("Did allow: ", permission.name)
        }

    }
}

and this is how I present it:

struct PermissionsCell: View {
    @State private var isPresented = false

    var body: some View {
        ZStack {
            Button(action: {
                self.isPresented.toggle()
            }) {
                Text("Permissions").padding()
            }
            if (isPresented) {
                PermissionsWrapperView(isShown: $isPresented)
            }
        }
    }
}
ivanvorobei commented 3 years ago

Thanks for provided code @dmitrym0 @OscarHedeby ! I added SPPermissionsList for ready-use with SwiftUI. Also was released new 6.x version with support SPM.