Add location permission request
This commit is contained in:
@@ -11,6 +11,7 @@ import 'package:sfm_app/feature/home/home_bloc.dart';
|
|||||||
import 'package:sfm_app/product/constant/app/app_constants.dart';
|
import 'package:sfm_app/product/constant/app/app_constants.dart';
|
||||||
import 'package:sfm_app/product/constant/enums/app_route_enums.dart';
|
import 'package:sfm_app/product/constant/enums/app_route_enums.dart';
|
||||||
import 'package:sfm_app/product/constant/enums/role_enums.dart';
|
import 'package:sfm_app/product/constant/enums/role_enums.dart';
|
||||||
|
import 'package:sfm_app/product/permission/location_permission.dart';
|
||||||
import '../devices/devices_manager_bloc.dart';
|
import '../devices/devices_manager_bloc.dart';
|
||||||
import '../devices/devices_manager_screen.dart';
|
import '../devices/devices_manager_screen.dart';
|
||||||
import '../home/home_screen.dart';
|
import '../home/home_screen.dart';
|
||||||
@@ -39,7 +40,7 @@ class MainScreen extends StatefulWidget {
|
|||||||
State<MainScreen> createState() => _MainScreenState();
|
State<MainScreen> createState() => _MainScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MainScreenState extends State<MainScreen> {
|
class _MainScreenState extends State<MainScreen> with WidgetsBindingObserver {
|
||||||
APIServices apiServices = APIServices();
|
APIServices apiServices = APIServices();
|
||||||
late MainBloc mainBloc;
|
late MainBloc mainBloc;
|
||||||
bool isVN = true;
|
bool isVN = true;
|
||||||
@@ -68,16 +69,39 @@ class _MainScreenState extends State<MainScreen> {
|
|||||||
mainBloc.sinkIsVNIcon.add(isVN);
|
mainBloc.sinkIsVNIcon.add(isVN);
|
||||||
mainBloc.sinkThemeMode.add(isLight);
|
mainBloc.sinkThemeMode.add(isLight);
|
||||||
log("role: $role");
|
log("role: $role");
|
||||||
|
LocationPermissionRequest.instance.checkLocationPermission(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
mainBloc = BlocProvider.of(context);
|
mainBloc = BlocProvider.of(context);
|
||||||
|
WidgetsBinding.instance.addObserver(this);
|
||||||
initialCheck();
|
initialCheck();
|
||||||
getBellNotification();
|
getBellNotification();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void didChangeAppLifecycleState(AppLifecycleState state) {
|
||||||
|
super.didChangeAppLifecycleState(state);
|
||||||
|
if (state == AppLifecycleState.inactive) {
|
||||||
|
log("App Inactive");
|
||||||
|
} else if (state == AppLifecycleState.resumed) {
|
||||||
|
log("App Resumed");
|
||||||
|
LocationPermissionRequest.instance.checkLocationPermission(context);
|
||||||
|
} else if (state == AppLifecycleState.paused) {
|
||||||
|
log("App paused");
|
||||||
|
} else if (state == AppLifecycleState.detached) {
|
||||||
|
log("App detached");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
super.dispose();
|
||||||
|
WidgetsBinding.instance.removeObserver(this);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
ThemeNotifier themeNotifier = context.watch<ThemeNotifier>();
|
ThemeNotifier themeNotifier = context.watch<ThemeNotifier>();
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ class MapBloc extends BlocBase {
|
|||||||
void dispose() {}
|
void dispose() {}
|
||||||
|
|
||||||
final mapType = StreamController<MapType>.broadcast();
|
final mapType = StreamController<MapType>.broadcast();
|
||||||
StreamSink<MapType> get sinkmapType => mapType.sink;
|
StreamSink<MapType> get sinkMapType => mapType.sink;
|
||||||
Stream<MapType> get streammapType => mapType.stream;
|
Stream<MapType> get streamMapType => mapType.stream;
|
||||||
|
|
||||||
final mapController = StreamController<GoogleMapController>.broadcast();
|
final mapController = StreamController<GoogleMapController>.broadcast();
|
||||||
StreamSink<GoogleMapController> get sinkmapController => mapController.sink;
|
StreamSink<GoogleMapController> get sinkmapController => mapController.sink;
|
||||||
@@ -71,4 +71,6 @@ class MapBloc extends BlocBase {
|
|||||||
context, "Không tìm thấy đường", Colors.orange, Colors.white);
|
context, "Không tìm thấy đường", Colors.orange, Colors.white);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'dart:convert';
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:geolocator/geolocator.dart';
|
||||||
import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart';
|
import 'package:google_maps_cluster_manager/google_maps_cluster_manager.dart';
|
||||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
import 'package:sfm_app/feature/devices/device_model.dart';
|
import 'package:sfm_app/feature/devices/device_model.dart';
|
||||||
@@ -10,6 +11,7 @@ import 'package:sfm_app/feature/map/map_bloc.dart';
|
|||||||
import 'package:sfm_app/feature/map/widget/on_tap_marker_widget.dart';
|
import 'package:sfm_app/feature/map/widget/on_tap_marker_widget.dart';
|
||||||
import 'package:sfm_app/product/base/bloc/base_bloc.dart';
|
import 'package:sfm_app/product/base/bloc/base_bloc.dart';
|
||||||
import 'package:sfm_app/product/constant/icon/icon_constants.dart';
|
import 'package:sfm_app/product/constant/icon/icon_constants.dart';
|
||||||
|
import 'package:sfm_app/product/permission/location_permission.dart';
|
||||||
import 'package:sfm_app/product/services/api_services.dart';
|
import 'package:sfm_app/product/services/api_services.dart';
|
||||||
|
|
||||||
class MapScreen extends StatefulWidget {
|
class MapScreen extends StatefulWidget {
|
||||||
@@ -19,7 +21,7 @@ class MapScreen extends StatefulWidget {
|
|||||||
State<MapScreen> createState() => _MapScreenState();
|
State<MapScreen> createState() => _MapScreenState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _MapScreenState extends State<MapScreen> {
|
class _MapScreenState extends State<MapScreen> with WidgetsBindingObserver {
|
||||||
late BitmapDescriptor normalIcon;
|
late BitmapDescriptor normalIcon;
|
||||||
late BitmapDescriptor offlineIcon;
|
late BitmapDescriptor offlineIcon;
|
||||||
late BitmapDescriptor abnormalIcon;
|
late BitmapDescriptor abnormalIcon;
|
||||||
@@ -47,7 +49,8 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
Set<Marker> markersAll = {};
|
Set<Marker> markersAll = {};
|
||||||
List<Marker> markers = [];
|
List<Marker> markers = [];
|
||||||
LatLng myLocation = const LatLng(213761, 123123);
|
LatLng myLocation = const LatLng(213761, 123123);
|
||||||
|
Position? position;
|
||||||
|
bool isAllowLocationPermission = false;
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -143,17 +146,27 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
cluster.getId(),
|
cluster.getId(),
|
||||||
),
|
),
|
||||||
position: cluster.location,
|
position: cluster.location,
|
||||||
onTap: () {
|
onTap: () async {
|
||||||
onTapMarker(
|
bool check = await checkLocationPermission(context);
|
||||||
|
if (check == true) {
|
||||||
|
Position position = await Geolocator.getCurrentPosition();
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
|
onTapMarker(
|
||||||
context,
|
context,
|
||||||
_controller,
|
_controller,
|
||||||
mapBloc,
|
mapBloc,
|
||||||
myLocation,
|
LatLng(position.latitude, position.longitude),
|
||||||
cluster.items,
|
cluster.items,
|
||||||
imageAssets,
|
imageAssets,
|
||||||
markers,
|
markers,
|
||||||
hospitalIcon,
|
hospitalIcon,
|
||||||
fireStationIcon);
|
fireStationIcon,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// ignore: use_build_context_synchronously
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(content: Text("Cannot get your Location")));
|
||||||
|
}
|
||||||
},
|
},
|
||||||
icon: getMarkerIcon(cluster),
|
icon: getMarkerIcon(cluster),
|
||||||
);
|
);
|
||||||
@@ -234,4 +247,10 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<bool> checkLocationPermission(context) async {
|
||||||
|
bool check = await LocationPermissionRequest.instance
|
||||||
|
.checkLocationPermission(context);
|
||||||
|
return check;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
// ignore_for_file: use_build_context_synchronously
|
// ignore_for_file: use_build_context_synchronously
|
||||||
|
|
||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
import 'show_direction_widget.dart';
|
import 'show_direction_widget.dart';
|
||||||
@@ -26,7 +25,6 @@ onTapMarker(
|
|||||||
BitmapDescriptor hospitalIcon,
|
BitmapDescriptor hospitalIcon,
|
||||||
BitmapDescriptor fireStationIcon,
|
BitmapDescriptor fireStationIcon,
|
||||||
) {
|
) {
|
||||||
LatLng testLocation = const LatLng(20.985453, 105.738381);
|
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext modalBottomSheetContext) {
|
builder: (BuildContext modalBottomSheetContext) {
|
||||||
@@ -77,7 +75,7 @@ onTapMarker(
|
|||||||
mapBloc.findTheWay(
|
mapBloc.findTheWay(
|
||||||
context,
|
context,
|
||||||
controller,
|
controller,
|
||||||
testLocation,
|
myLocation,
|
||||||
destination,
|
destination,
|
||||||
);
|
);
|
||||||
String deviceLocations = await DeviceUtils.instance
|
String deviceLocations = await DeviceUtils.instance
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:firebase_core/firebase_core.dart';
|
import 'package:firebase_core/firebase_core.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:sfm_app/product/services/language_services.dart';
|
import 'product/services/language_services.dart';
|
||||||
import 'feature/main/main_bloc.dart';
|
import 'feature/main/main_bloc.dart';
|
||||||
import 'product/base/bloc/base_bloc.dart';
|
import 'product/base/bloc/base_bloc.dart';
|
||||||
import 'product/constant/navigation/navigation_router.dart';
|
import 'product/constant/navigation/navigation_router.dart';
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import 'package:app_settings/app_settings.dart';
|
import 'package:app_settings/app_settings.dart';
|
||||||
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import '../../../extention/context_extention.dart';
|
import '../../../extention/context_extention.dart';
|
||||||
import '../../../services/language_services.dart';
|
import '../../../services/language_services.dart';
|
||||||
|
|
||||||
class RequestPermissionDialog {
|
class RequestPermissionDialog {
|
||||||
showRequestPermissionDialog(BuildContext context, IconData icon,
|
RequestPermissionDialog._init();
|
||||||
String dialogContent, AppSettingsType type) {
|
static RequestPermissionDialog? _instance;
|
||||||
|
static RequestPermissionDialog get instance =>
|
||||||
|
_instance ??= RequestPermissionDialog._init();
|
||||||
|
|
||||||
|
requestPermissionDialogAndroid(BuildContext context, IconData icon,
|
||||||
|
String content, AppSettingsType type) {
|
||||||
showDialog(
|
showDialog(
|
||||||
useRootNavigator: false,
|
useRootNavigator: false,
|
||||||
context: context,
|
context: context,
|
||||||
@@ -20,36 +26,39 @@ class RequestPermissionDialog {
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: context.paddingNormalVertical,
|
padding: dialogContext.paddingNormalVertical,
|
||||||
child: Text(
|
child: Text(
|
||||||
dialogContent,
|
"Alow app to use $content permission",
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
fontWeight: FontWeight.bold, fontSize: 18),
|
fontWeight: FontWeight.bold, fontSize: 18),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Divider(height: context.lowValue),
|
Divider(height: dialogContext.lowValue),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
AppSettings.openAppSettings(type: type);
|
AppSettings.openAppSettings(type: type);
|
||||||
|
Navigator.of(dialogContext).pop();
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding: dialogContext.paddingNormalVertical,
|
||||||
context.paddingNormalVertical, // Cách giữa các phần tử
|
|
||||||
child: Text(appLocalization(context).allow_message,
|
child: Text(appLocalization(context).allow_message,
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold)),
|
style: const TextStyle(fontWeight: FontWeight.bold)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Divider(height: context.lowValue),
|
Divider(height: dialogContext.lowValue),
|
||||||
GestureDetector(
|
GestureDetector(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(dialogContext).pop(); // Đóng dialog
|
Navigator.of(dialogContext).pop();
|
||||||
},
|
},
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding:
|
padding: dialogContext.paddingNormalVertical,
|
||||||
context.paddingNormalVertical, // Cách giữa các phần tử
|
child: Text(
|
||||||
child: Text(appLocalization(context).decline_message,
|
appLocalization(dialogContext).decline_message,
|
||||||
style: const TextStyle(fontWeight: FontWeight.bold)),
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -58,4 +67,31 @@ class RequestPermissionDialog {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
requestPermissionDialogIOS(context, AppSettingsType appSettingsType, content,
|
||||||
|
AppSettingsType type) =>
|
||||||
|
showCupertinoDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (showCupertinoDialogContext) => CupertinoAlertDialog(
|
||||||
|
title: Text(appLocalization(showCupertinoDialogContext)
|
||||||
|
.permission_deny_message),
|
||||||
|
content: Text("Alow app to use $content permission"),
|
||||||
|
actions: <CupertinoDialogAction>[
|
||||||
|
CupertinoDialogAction(
|
||||||
|
child: Text(appLocalization(showCupertinoDialogContext)
|
||||||
|
.cancel_button_content),
|
||||||
|
onPressed: () => Navigator.pop(showCupertinoDialogContext),
|
||||||
|
),
|
||||||
|
CupertinoDialogAction(
|
||||||
|
isDefaultAction: true,
|
||||||
|
child: Text(
|
||||||
|
appLocalization(showCupertinoDialogContext).allow_message),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pop(showCupertinoDialogContext);
|
||||||
|
AppSettings.openAppSettings(type: appSettingsType);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -193,8 +193,9 @@
|
|||||||
"warning_message": "Warning: ",
|
"warning_message": "Warning: ",
|
||||||
"loading_message": "Loading...",
|
"loading_message": "Loading...",
|
||||||
"detail_message": "Detail",
|
"detail_message": "Detail",
|
||||||
"decline_message": "DECLINE",
|
"permission_deny_message": "Permission Denied",
|
||||||
"allow_message": "ALLOW",
|
"decline_message": "Decline",
|
||||||
|
"allow_message": "Allow",
|
||||||
"add_button_content": "Add",
|
"add_button_content": "Add",
|
||||||
"update_button_content": "Update",
|
"update_button_content": "Update",
|
||||||
"change_button_content": "Change",
|
"change_button_content": "Change",
|
||||||
|
|||||||
@@ -193,6 +193,7 @@
|
|||||||
"warning_message": "Cảnh báo:",
|
"warning_message": "Cảnh báo:",
|
||||||
"loading_message": "Đang tải...",
|
"loading_message": "Đang tải...",
|
||||||
"detail_message": "Chi tiết",
|
"detail_message": "Chi tiết",
|
||||||
|
"permission_deny_message":"Quyền bị từ chối",
|
||||||
"decline_message": "TỪ CHỐI",
|
"decline_message": "TỪ CHỐI",
|
||||||
"allow_message": "CHO PHÉP",
|
"allow_message": "CHO PHÉP",
|
||||||
"add_button_content": "Thêm",
|
"add_button_content": "Thêm",
|
||||||
|
|||||||
57
lib/product/permission/location_permission.dart
Normal file
57
lib/product/permission/location_permission.dart
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:app_settings/app_settings.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:sfm_app/product/base/widget/dialog/request_permission_dialog.dart';
|
||||||
|
|
||||||
|
class LocationPermissionRequest {
|
||||||
|
LocationPermissionRequest._init();
|
||||||
|
static LocationPermissionRequest? _instance;
|
||||||
|
static LocationPermissionRequest get instance =>
|
||||||
|
_instance ??= LocationPermissionRequest._init();
|
||||||
|
|
||||||
|
Future<bool> checkLocationPermission(context) async {
|
||||||
|
var status = await Permission.location.status;
|
||||||
|
log("Status: $status");
|
||||||
|
if (status.isDenied || status.isPermanentlyDenied) {
|
||||||
|
requestLocationPermisson(context, Icons.location_on_outlined,
|
||||||
|
Permission.location, AppSettingsType.location, "Location");
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void requestLocationPermisson(
|
||||||
|
context,
|
||||||
|
IconData icon,
|
||||||
|
Permission service,
|
||||||
|
AppSettingsType appSettingsType,
|
||||||
|
String serviceName,
|
||||||
|
) async {
|
||||||
|
var status = await service.status;
|
||||||
|
if (status.isDenied) {
|
||||||
|
await service.request();
|
||||||
|
} else if (status.isPermanentlyDenied) {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
RequestPermissionDialog.instance.requestPermissionDialogAndroid(
|
||||||
|
context,
|
||||||
|
icon,
|
||||||
|
serviceName,
|
||||||
|
appSettingsType,
|
||||||
|
);
|
||||||
|
} else if (Platform.isIOS) {
|
||||||
|
RequestPermissionDialog.instance.requestPermissionDialogIOS(
|
||||||
|
context,
|
||||||
|
appSettingsType,
|
||||||
|
serviceName,
|
||||||
|
appSettingsType,
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log("Location Permission: Undefined Platform");
|
||||||
|
}
|
||||||
|
} else {}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,7 +24,7 @@ class NotificationPermission {
|
|||||||
} else {
|
} else {
|
||||||
log("NotificationsPermission: User denied permission");
|
log("NotificationsPermission: User denied permission");
|
||||||
// ignore: use_build_context_synchronously
|
// ignore: use_build_context_synchronously
|
||||||
RequestPermissionDialog().showRequestPermissionDialog(context,
|
RequestPermissionDialog.instance.requestPermissionDialogAndroid(context,
|
||||||
Icons.location_on_outlined, "ABCDE", AppSettingsType.notification);
|
Icons.location_on_outlined, "ABCDE", AppSettingsType.notification);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ InputDecoration borderRadiusTopLeftAndBottomRight(
|
|||||||
BuildContext context, String hintText) =>
|
BuildContext context, String hintText) =>
|
||||||
InputDecoration(
|
InputDecoration(
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
border: OutlineInputBorder(
|
border: const OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.only(
|
borderRadius: BorderRadius.only(
|
||||||
topLeft: Radius.circular(12), bottomRight: Radius.circular(12)),
|
topLeft: Radius.circular(12), bottomRight: Radius.circular(12)),
|
||||||
));
|
));
|
||||||
|
|||||||
Reference in New Issue
Block a user