Skip to content

Commit

Permalink
feat: Revise permissions & display dialog explaining location perms (#51
Browse files Browse the repository at this point in the history
)
  • Loading branch information
matejglejtek committed Jun 26, 2023
1 parent fede9fa commit ebfa2a2
Show file tree
Hide file tree
Showing 7 changed files with 220 additions and 55 deletions.
1 change: 1 addition & 0 deletions android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
Expand Down
54 changes: 20 additions & 34 deletions lib/bloc/showcase_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,30 +9,7 @@ import 'aircraft/selected_aircraft_cubit.dart';
import 'opendroneid_cubit.dart';
import 'sliders_cubit.dart';

class ShowcaseState {
bool showcaseActive;
bool showcaseAlreadyPlayed;
// keep aircraft state and apply it after showcase ends
// so user wont lose data when starting showcase with data already gathered
AircraftState? aircraftState;

ShowcaseState(
{required this.showcaseActive,
required this.showcaseAlreadyPlayed,
this.aircraftState});

ShowcaseState copyWith({
bool? showcaseActive,
bool? showcaseAlreadyPlayed,
AircraftState? aircraftState,
}) =>
ShowcaseState(
showcaseActive: showcaseActive ?? this.showcaseActive,
showcaseAlreadyPlayed:
showcaseAlreadyPlayed ?? this.showcaseAlreadyPlayed,
aircraftState: aircraftState ?? this.aircraftState,
);
}
part 'showcase_state.dart';

class ShowcaseCubit extends Cubit<ShowcaseState> {
final GlobalKey rootKey = GlobalKey();
Expand Down Expand Up @@ -92,7 +69,8 @@ class ShowcaseCubit extends Cubit<ShowcaseState> {
'You can replay this showcase from the About page. Enjoy!';
ShowcaseCubit()
: super(
ShowcaseState(showcaseActive: false, showcaseAlreadyPlayed: false),
ShowcaseStateNotInitialized(
showcaseActive: false, showcaseAlreadyPlayed: false),
);

List<GlobalKey> get keys {
Expand All @@ -115,21 +93,27 @@ class ShowcaseCubit extends Cubit<ShowcaseState> {
];
}

Future<bool> displayShowcase() async {
Future<bool> shouldDisplayShowcase() async {
final preferences = await SharedPreferences.getInstance();
final showcasePlayed = preferences.getBool('showcasePlayed');
var shouldDisplayShowcase = false;
// emit initialized if was not read before
if (state is ShowcaseStateNotInitialized) {
emit(ShowcaseStateInitialized(
showcaseActive: showcasePlayed == null ? true : !showcasePlayed,
showcaseAlreadyPlayed: showcasePlayed ?? false,
));
}
if (showcasePlayed == null || !showcasePlayed) {
await preferences.setBool('showcasePlayed', true);
emit(state.copyWith(showcaseAlreadyPlayed: true));
return true;
shouldDisplayShowcase = true;
}
return false;
return shouldDisplayShowcase;
}

Future<void> restartShowcase() async {
final preferences = await SharedPreferences.getInstance();
await preferences.setBool('showcasePlayed', false);
emit(state.copyWith(showcaseActive: true));
}

Future<void> setShowcaseActive({
Expand Down Expand Up @@ -175,14 +159,16 @@ class ShowcaseCubit extends Cubit<ShowcaseState> {
);
}

void onShowcaseFinish(BuildContext context) {
context.read<AircraftCubit>().removeShowcaseDummyPack();
void onShowcaseFinish(BuildContext context) async {
await context.read<AircraftCubit>().removeShowcaseDummyPack();
if (state.aircraftState != null) {
context.read<AircraftCubit>().applyState(state.aircraftState!);
}
final odidCubit = context.read<OpendroneIdCubit>();
odidCubit.start(odidCubit.state.usedTechnologies);
emit(state.copyWith(showcaseActive: false));
await odidCubit.start(odidCubit.state.usedTechnologies);
final preferences = await SharedPreferences.getInstance();
await preferences.setBool('showcasePlayed', true);
emit(state.copyWith(showcaseActive: false, showcaseAlreadyPlayed: true));
}

void onKeyComplete(
Expand Down
67 changes: 67 additions & 0 deletions lib/bloc/showcase_state.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
part of 'showcase_cubit.dart';

class ShowcaseState {
bool showcaseActive;
bool showcaseAlreadyPlayed;
// keep aircraft state and apply it after showcase ends
// so user wont lose data when starting showcase with data already gathered
AircraftState? aircraftState;

ShowcaseState(
{required this.showcaseActive,
required this.showcaseAlreadyPlayed,
this.aircraftState});

ShowcaseState copyWith({
bool? showcaseActive,
bool? showcaseAlreadyPlayed,
AircraftState? aircraftState,
}) =>
ShowcaseState(
showcaseActive: showcaseActive ?? this.showcaseActive,
showcaseAlreadyPlayed:
showcaseAlreadyPlayed ?? this.showcaseAlreadyPlayed,
aircraftState: aircraftState ?? this.aircraftState,
);
}

class ShowcaseStateNotInitialized extends ShowcaseState {
ShowcaseStateNotInitialized({
required super.showcaseActive,
required super.showcaseAlreadyPlayed,
super.aircraftState,
});

@override
ShowcaseStateNotInitialized copyWith({
bool? showcaseActive,
bool? showcaseAlreadyPlayed,
AircraftState? aircraftState,
}) =>
ShowcaseStateNotInitialized(
showcaseActive: showcaseActive ?? this.showcaseActive,
showcaseAlreadyPlayed:
showcaseAlreadyPlayed ?? this.showcaseAlreadyPlayed,
aircraftState: aircraftState ?? this.aircraftState,
);
}

class ShowcaseStateInitialized extends ShowcaseState {
ShowcaseStateInitialized({
required super.showcaseActive,
required super.showcaseAlreadyPlayed,
super.aircraftState,
});
@override
ShowcaseStateInitialized copyWith({
bool? showcaseActive,
bool? showcaseAlreadyPlayed,
AircraftState? aircraftState,
}) =>
ShowcaseStateInitialized(
showcaseActive: showcaseActive ?? this.showcaseActive,
showcaseAlreadyPlayed:
showcaseAlreadyPlayed ?? this.showcaseAlreadyPlayed,
aircraftState: aircraftState ?? this.aircraftState,
);
}
12 changes: 6 additions & 6 deletions lib/widgets/app/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ class App extends StatefulWidget {
class _AppState extends State<App> {
@override
Widget build(BuildContext context) {
return LifeCycleManager(
child: MaterialApp(
theme: AppTheme.lightTheme,
themeMode: ThemeMode.light,
home: const MyHomePage(),
navigatorObservers: [NavigationHistoryObserver()],
return MaterialApp(
theme: AppTheme.lightTheme,
themeMode: ThemeMode.light,
home: LifeCycleManager(
child: const MyHomePage(),
),
navigatorObservers: [NavigationHistoryObserver()],
);
}
}
70 changes: 70 additions & 0 deletions lib/widgets/app/dialogs.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:another_flushbar/flushbar.dart';
import 'package:app_settings/app_settings.dart';
import 'package:flutter/material.dart';

import '../../constants/colors.dart';
Expand Down Expand Up @@ -42,6 +43,75 @@ void showAlertDialog(
);
}

Future<bool> showLocationPermissionDialog({
required BuildContext context,
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);
},
);
// set up the AlertDialog
final alert = AlertDialog(
title: const Text('Location permission required'),
content: Text.rich(
TextSpan(
text: 'Drone Scanner requires a location permission to scan for '
'Bluetooth devices.\n\n',
children: [
if (showWhileUsingPermissionExplanation) ...[
TextSpan(text: 'Please choose\nthe '),
TextSpan(
text: '\"While using the app\"\n',
style: TextStyle(fontWeight: FontWeight.w700),
),
TextSpan(
text: 'option to enable scans in the background.\n\n',
),
],
TextSpan(
text: 'If you already denied the permission request,'
' please go to\nthe '),
TextSpan(
text: '\"App settings\"\n',
style: TextStyle(fontWeight: FontWeight.w700),
),
TextSpan(text: 'and enable location manually.'),
],
),
),
actions: [
cancelButton,
appSettingsButton,
continueButton,
],
);
// show the dialog
final result = await showDialog<bool>(
context: context,
builder: (context) {
return alert;
},
);
return result ?? false;
}

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

0 comments on commit ebfa2a2

Please sign in to comment.