moxfyne
moxfyne

Reputation: 41

How do I properly handle requesting two permissions on the same screen?

I am developing a custom object detection app for Android using the camera package in conjunction with tflite. When the screen loads, it asks the user for camera and microphone permission using the permission_handler package. I'm also using a ChangeNotifier class to store the results after asking the user for permission. Then, depending on whether the user accepts these conditions, I'm conditionally rendering widgets. Now, there are a few cases here:

a. Neither is granted → request for both permission if it isn't permanently denied and if it is then ask the user to manually grant it from settings

b. Permission for the camera is granted, but the user denied mic permission → request for mic permission if it isn't permanently denied and if it is then ask the user to manually grant it from settings

c. Permission for the mic is granted, but camera permission is denied → request for camera permission if it isn't permanently denied and if it is then ask the user to manually grant it from settings

d. Neither is granted → request for both permission if they aren't permanently denied and if they are then ask the user to manually grant them from settings

Here is my current implementation.

https://codeshare.io/X8eKWE

The problem is that even when the user grants both the permissions, it shows: 'Camera permission was denied!', 'Request camera permission' widget. So, how can I handle all four different cases in a more elegant way?

Upvotes: 0

Views: 147

Answers (1)

rasityilmaz
rasityilmaz

Reputation: 1399

class _LiveFeedState extends State<LiveFeed> with  WidgetsBindingObserver {
  Widget? errWidget;

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    super.didChangeAppLifecycleState(state);
    switch (state) {
      case AppLifecycleState.resumed:
        log("App Resumed");
        _checkCameraPermissionStatus();

        break;
      case AppLifecycleState.inactive:
        log("App Inactive");

        break;
      case AppLifecycleState.paused:
        log("App Paused");
        break;
      case AppLifecycleState.detached:
        log("App Detached");
        break;
    }
  }

  @override
  void dispose() {
    super.dispose();

    WidgetsBinding.instance.removeObserver(this);
  }

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
  }

  Widget bodyWidget() {
    
     return CameraFeed...;
  }

  Widget permissionScreen(Function onPressedHandler, String titleText, String buttonText) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        Text(titleText),
        ElevatedButton(
            onPressed: () {
              onPressedHandler();
            },
            child: Text(buttonText)),
      ],
    );
  }

  Future<void> _checkCameraPermissionStatus() async {
    var status = await Permission.camera.request().then((value) => value);

    switch (status) {
      case PermissionStatus.granted:
        errWidget = await _checkMicPermissionStatus();
        setState(() {});

        break;

      case PermissionStatus.denied:
        setState(() {
          errWidget = permissionScreen(_checkCameraPermissionStatus, 'Camera permission was denied!', 'Request camera permission');
        });
        break;
      case PermissionStatus.permanentlyDenied:
        setState(() {
          errWidget = permissionScreen(openAppSettings, 'Camera permission was permanently denied! Open app setings and manually grant permission', 'Open app settings');
        });
        break;
      default:
        errWidget = await _checkMicPermissionStatus();
        setState(() {});

        break;
    }
  }

  Future<Widget> _checkMicPermissionStatus() async {
    var status = await Permission.microphone.request().then((value) => value);

    switch (status) {
      case PermissionStatus.granted:
        return bodyWidget();

      case PermissionStatus.denied:
        return permissionScreen(_checkCameraPermissionStatus, 'Microphone permission was denied!', 'Request Microphone permission');

      case PermissionStatus.permanentlyDenied:
        return permissionScreen(openAppSettings, 'Microphone permission was permanently denied! Open app setings and manually grant permission', 'Open app settings');

      default:
        return bodyWidget();
    }
  }

  @override
  Widget build(BuildContext context) {
    return SafeArea(
        child: Scaffold(
            
            appBar: isPortrait
                ? AppBar(
                    title: const Text("SpotHole"),
                  )
                : null,
            body: FutureBuilder(
              future: Future.wait([Permission.camera.status, Permission.microphone.status]),
              builder: (BuildContext context, AsyncSnapshot<List<PermissionStatus>> snapshot) {
                if (snapshot.hasData) {
                  if (snapshot.data![0] == PermissionStatus.granted ||
                      snapshot.data![0] == PermissionStatus.limited ||
                      snapshot.data![1] == PermissionStatus.granted ||
                      snapshot.data![1] == PermissionStatus.limited) {
                    return bodyWidget();
                  } else {
                    if (errWidget != null) {
                      return errWidget!;
                    } else {
                      if (snapshot.data![0] != PermissionStatus.granted || snapshot.data![0] != PermissionStatus.limited) {
                        return permissionScreen(_checkCameraPermissionStatus, 'Camera permission was denied!', 'Request camera permission');
                      } else {
                        return permissionScreen(_checkCameraPermissionStatus, 'Microphone permission was denied!', 'Request Microphone permission');
                      }
                    }
                  }
                } else {
                  return const CircularProgressIndicator.adaptive();
                }
              },
            )));
  }
}

Upvotes: 0

Related Questions