Skip to content

Commit

Permalink
feat: request background location permission (#86)
Browse files Browse the repository at this point in the history
  • Loading branch information
matejglejtek committed Jul 12, 2024
2 parents 210b5ed + 3c767f7 commit f0cd5d8
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 137 deletions.
2 changes: 1 addition & 1 deletion ios/Runner/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Application needs Your location to show nearby aircraft.</string>
<key>NSLocationAlwaysUsageDescription</key>
<string>Application needs Your location to show nearby aircraft.</string>
<string>Application needs background location for Drone Radar feature.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>Application needs Your location to show nearby aircraft.</string>
<key>UIApplicationSupportsIndirectInputEvents</key>
Expand Down
77 changes: 53 additions & 24 deletions lib/bloc/standards_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,25 @@ import 'package:logging/logging.dart';
import 'package:shared_preferences/shared_preferences.dart';

class StandardsState {
bool androidSystem = false;
bool btLegacy = false; // bt4
bool btExtended = false; // bt4
bool wifiBeacon = false;
bool wifiNaN = false; // aware on android
bool btExtendedClaimed = false; // can be claimed but still not work
final bool androidSystem;
final bool btLegacy; // bt4
final bool btExtended; // bt5
final bool wifiBeacon;
final bool wifiNaN; // aware on android
final bool btExtendedClaimed; // can be claimed but still not work
// if adv len is < 1000, we stronly suspect Bt long range scanning wont work
int maxAdvDataLen = 0;
final int maxAdvDataLen;
// permissions
bool btEnabled = false;
bool locationEnabled = false;
bool notificationsEnabled = false;
bool internetAvailable = false;
final bool btEnabled;
final bool locationEnabled;
final bool backgroundLocationEnabled;
// true if user was asked about background location and cancelled request
final bool backgroundLocationDenied;
final bool notificationsEnabled;
final bool internetAvailable;

static const logPlatformStandardsKey = 'logPlatformStandards';
static const backgroundLocationDeniedKey = 'backgroundLocationDenied';

StandardsState({
required this.androidSystem,
Expand All @@ -32,6 +38,8 @@ class StandardsState {
required this.maxAdvDataLen,
required this.btEnabled,
required this.locationEnabled,
required this.backgroundLocationEnabled,
required this.backgroundLocationDenied,
required this.notificationsEnabled,
required this.internetAvailable,
});
Expand All @@ -46,6 +54,8 @@ class StandardsState {
int? maxAdvDataLen,
bool? btEnabled,
bool? locationEnabled,
bool? backgroundLocationEnabled,
bool? backgroundLocationDenied,
bool? notificationsEnabled,
bool? internetAvailable,
}) =>
Expand All @@ -59,6 +69,10 @@ class StandardsState {
maxAdvDataLen: maxAdvDataLen ?? this.maxAdvDataLen,
btEnabled: btEnabled ?? this.btEnabled,
locationEnabled: locationEnabled ?? this.locationEnabled,
backgroundLocationDenied:
backgroundLocationDenied ?? this.backgroundLocationDenied,
backgroundLocationEnabled:
backgroundLocationEnabled ?? this.backgroundLocationEnabled,
notificationsEnabled: notificationsEnabled ?? this.notificationsEnabled,
internetAvailable: internetAvailable ?? this.internetAvailable,
);
Expand All @@ -79,6 +93,8 @@ class StandardsCubit extends Cubit<StandardsState> {
internetAvailable: false,
notificationsEnabled: false,
locationEnabled: false,
backgroundLocationEnabled: false,
backgroundLocationDenied: false,
),
);

Expand Down Expand Up @@ -128,7 +144,14 @@ class StandardsCubit extends Cubit<StandardsState> {
);

final preferences = await SharedPreferences.getInstance();
final logPlatformStatus = preferences.getBool('logPlatformStandards');

final backgroundLocationDenied =
preferences.getBool(StandardsState.backgroundLocationDeniedKey) ??
false;
emit(state.copyWith(backgroundLocationDenied: backgroundLocationDenied));

final logPlatformStatus =
preferences.getBool(StandardsState.logPlatformStandardsKey);
// skip if info was already logged
if (logPlatformStatus != null && !logPlatformStatus) {
return;
Expand Down Expand Up @@ -159,22 +182,28 @@ class StandardsCubit extends Cubit<StandardsState> {
Logger.root.info('maxAdvDataLen $maxAdvDataLen');

// set that platforms standards were already logged
await preferences.setBool('logPlatformStandards', true);
await preferences.setBool(StandardsState.logPlatformStandardsKey, true);
}

Future<void> setLocationEnabled({required bool enabled}) async {
emit(state.copyWith(locationEnabled: enabled));
}
void setLocationEnabled({required bool enabled}) =>
emit(state.copyWith(locationEnabled: enabled));

Future<void> setBluetoothEnabled({required bool enabled}) async {
emit(state.copyWith(btEnabled: enabled));
}
void setBackgroundLocationEnabled({required bool enabled}) async =>
emit(state.copyWith(backgroundLocationEnabled: enabled));

Future<void> setNotificationsEnabled({required bool enabled}) async {
emit(state.copyWith(notificationsEnabled: enabled));
Future<void> setBackgroundLocationDenied() async {
final preferences = await SharedPreferences.getInstance();
preferences.setBool(StandardsState.backgroundLocationDeniedKey, true);
emit(state.copyWith(
backgroundLocationEnabled: false, backgroundLocationDenied: true));
}

Future<void> setInternetAvailable({required bool available}) async {
emit(state.copyWith(internetAvailable: available));
}
void setBluetoothEnabled({required bool enabled}) =>
emit(state.copyWith(btEnabled: enabled));

void setNotificationsEnabled({required bool enabled}) =>
emit(state.copyWith(notificationsEnabled: enabled));

void setInternetAvailable({required bool available}) =>
emit(state.copyWith(internetAvailable: available));
}
94 changes: 71 additions & 23 deletions lib/widgets/app/dialogs.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:io';

import 'package:another_flushbar/flushbar.dart';
import 'package:app_settings/app_settings.dart';
import 'package:flutter/material.dart';
Expand Down Expand Up @@ -48,25 +50,7 @@ Future<bool> showLocationPermissionDialog({
required bool showWhileUsingPermissionExplanation,
}) async {
// set up the buttons
final Widget cancelButton = TextButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.pop(context, false);
},
);
final Widget appSettingsButton = TextButton(
child: const Text('App settings'),
onPressed: () {
Navigator.pop(context, false);
AppSettings.openAppSettings();
},
);
final Widget continueButton = TextButton(
child: const Text('Continue'),
onPressed: () {
Navigator.pop(context, true);
},
);
final actions = _getPermissionDialogActions(context);
// set up the AlertDialog
final alert = AlertDialog(
title: const Text('Location permission required'),
Expand All @@ -82,7 +66,8 @@ Future<bool> showLocationPermissionDialog({
style: TextStyle(fontWeight: FontWeight.w700),
),
const TextSpan(
text: 'option to enable scans in the background.\n\n',
text:
'option to enable scans while the app is in foreground.\n\n',
),
],
const TextSpan(
Expand All @@ -96,10 +81,49 @@ Future<bool> showLocationPermissionDialog({
],
),
),
actions: actions.values.toList(),
);
// show the dialog
final result = await showDialog<bool>(
context: context,
builder: (context) {
return alert;
},
);
return result ?? false;
}

Future<bool> showBackgroundPermissionDialog({
required BuildContext context,
}) async {
// set up the buttons
final actions = _getPermissionDialogActions(context);
final isAndroid = Platform.isAndroid;
// set up the AlertDialog
final alert = AlertDialog(
title: const Text('Background location permission'),
content: const Text.rich(
TextSpan(
text: 'Drone Scanner requires background location permission to scan '
'for nearby aircraft while in the background.\n\n',
children: [
TextSpan(
text: 'If you wish to use the Drone Radar feature or gather data '
'while the app is minimized, please select\nthe '),
TextSpan(
text: '"Allow all the time"\n',
style: TextStyle(fontWeight: FontWeight.w700),
),
TextSpan(
text: 'option in application settings.\n\n',
),
],
),
),
actions: [
cancelButton,
appSettingsButton,
continueButton,
actions['cancel']!,
if (isAndroid) actions['continue']!,
if (!isAndroid) actions['appSettings']!,
],
);
// show the dialog
Expand All @@ -112,6 +136,30 @@ Future<bool> showLocationPermissionDialog({
return result ?? false;
}

Map<String, Widget> _getPermissionDialogActions(BuildContext context) {
return {
'cancel': TextButton(
child: const Text('Cancel'),
onPressed: () {
Navigator.pop(context, false);
},
),
'appSettings': TextButton(
child: const Text('App settings'),
onPressed: () {
Navigator.pop(context, true);
AppSettings.openAppSettings();
},
),
'continue': TextButton(
child: const Text('Continue'),
onPressed: () {
Navigator.pop(context, true);
},
),
};
}

void showSnackBar(
BuildContext context,
String snackBarText, {
Expand Down
Loading

0 comments on commit f0cd5d8

Please sign in to comment.