diff --git a/packages/core/lib/presentation/widget/map/logic.dart b/packages/core/lib/presentation/widget/map/logic.dart index 4435248..0824b14 100644 --- a/packages/core/lib/presentation/widget/map/logic.dart +++ b/packages/core/lib/presentation/widget/map/logic.dart @@ -6,6 +6,9 @@ import 'package:flutter_map_animations/flutter_map_animations.dart'; import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; import 'package:latlong2/latlong.dart'; +import 'package:rasadyar_core/utils/logger_utils.dart'; + +enum ErrorLocationType { serviceDisabled, permissionDenied, none } class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { Rx currentLocation = LatLng(35.824891, 50.948025).obs; @@ -14,7 +17,7 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { RxList markers = [].obs; RxList allMarkers = [].obs; Rx mapController = MapController().obs; - + RxList errorLocationType = RxList(); late final AnimatedMapController animatedMapController; Timer? _debounceTimer; RxBool isLoading = false.obs; @@ -28,6 +31,30 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { curve: Curves.easeInOut, cancelPreviousAnimations: true, ); + locationServiceEnabled().then((value) { + if (!value) { + errorLocationType.add(ErrorLocationType.serviceDisabled); + } + }); + + checkPermission().then((value) { + if (!value) { + errorLocationType.add(ErrorLocationType.permissionDenied); + } + }); + + listenToLocationServiceStatus().listen((event) { + if (!event) { + errorLocationType.add(ErrorLocationType.serviceDisabled); + } else { + errorLocationType.remove(ErrorLocationType.serviceDisabled); + } + }); + } + + @override + void onReady() { + super.onReady(); determineCurrentPosition(); } @@ -38,6 +65,47 @@ class MapWidgetLogic extends GetxController with GetTickerProviderStateMixin { mapController.close(); } + Stream listenToLocationServiceStatus() { + return Geolocator.getServiceStatusStream().map((status) { + return status == ServiceStatus.enabled; + }); + } + + Future locationServiceEnabled() async { + bool serviceEnabled = await Geolocator.isLocationServiceEnabled(); + if (!serviceEnabled) { + return false; + } + return true; + } + + Future checkPermission({bool request = false}) async { + try { + final LocationPermission permission = await Geolocator.checkPermission(); + + switch (permission) { + case LocationPermission.denied: + final LocationPermission requestResult = + await Geolocator.requestPermission(); + return requestResult != LocationPermission.denied && + requestResult != LocationPermission.deniedForever; + + case LocationPermission.deniedForever: + return request ? await Geolocator.openAppSettings() : false; + + case LocationPermission.always: + case LocationPermission.whileInUse: + return true; + + default: + return false; + } + } catch (e) { + eLog(e); + return await Geolocator.openLocationSettings(); + } + } + Future determineCurrentPosition() async { final position = await Geolocator.getCurrentPosition( locationSettings: AndroidSettings(accuracy: LocationAccuracy.best), diff --git a/packages/core/lib/presentation/widget/map/view.dart b/packages/core/lib/presentation/widget/map/view.dart index aa9e2cf..8fe6cc2 100644 --- a/packages/core/lib/presentation/widget/map/view.dart +++ b/packages/core/lib/presentation/widget/map/view.dart @@ -1,9 +1,14 @@ import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; +import 'package:geolocator/geolocator.dart'; import 'package:get/get.dart'; +import 'package:latlong2/latlong.dart'; import 'package:rasadyar_core/presentation/common/app_color.dart'; +import 'package:rasadyar_core/presentation/common/app_fonts.dart'; import 'package:rasadyar_core/presentation/common/assets.gen.dart'; +import 'package:rasadyar_core/presentation/widget/buttons/elevated.dart'; import 'package:rasadyar_core/presentation/widget/buttons/fab.dart'; +import 'package:rasadyar_core/presentation/widget/buttons/outline_elevated.dart'; import 'logic.dart'; @@ -13,7 +18,99 @@ class MapWidget extends GetView { @override Widget build(BuildContext context) { return Stack( - children: [_buildMap(), _buildGpsButton(), _buildFilterButton()], + children: [ + ObxValue((errorType) { + if (errorType.isNotEmpty) { + if (errorType.contains(ErrorLocationType.serviceDisabled)) { + Future.microtask(() { + Get.defaultDialog( + title: 'خطا', + content: const Text('سرویس مکان‌یابی غیرفعال است'), + cancel: ROutlinedElevated( + text: 'بررسی مجدد', + width: 120, + textStyle: AppFonts.yekan16, + onPressed: () async { + var service = await controller.locationServiceEnabled(); + if (service) { + controller.errorLocationType.remove( + ErrorLocationType.serviceDisabled, + ); + Get.back(); + } + // Don't call Get.back() if service is still disabled + }, + ), + confirm: RElevated( + text: 'روشن کردن', + textStyle: AppFonts.yekan16, + width: 120, + onPressed: () async { + var res = await Geolocator.openLocationSettings(); + if (res) { + var service = + await controller.locationServiceEnabled(); + if (service) { + controller.errorLocationType.remove( + ErrorLocationType.serviceDisabled, + ); + Get.back(); + } + } + }, + ), + + contentPadding: EdgeInsets.all(8), + onWillPop: () async { + return controller.errorLocationType.isEmpty; + }, + barrierDismissible: false, + ); + }); + } else { + Future.microtask(() { + Get.defaultDialog( + title: 'خطا', + content: const Text( + ' دسترسی به سرویس مکان‌یابی غیرفعال است', + ), + cancel: ROutlinedElevated( + text: 'بررسی مجدد', + width: 120, + textStyle: AppFonts.yekan16, + onPressed: () async { + await controller.checkPermission(); + }, + ), + confirm: RElevated( + text: 'اجازه دادن', + textStyle: AppFonts.yekan16, + width: 120, + onPressed: () async { + var res = await controller.checkPermission( + request: true, + ); + if (res) { + controller.errorLocationType.remove( + ErrorLocationType.permissionDenied, + ); + Get.back(); + } + }, + ), + + contentPadding: EdgeInsets.all(8), + onWillPop: () async { + return controller.errorLocationType.isEmpty; + }, + barrierDismissible: false, + ); + }); + } + } + return const SizedBox.shrink(); + }, controller.errorLocationType), + _buildMap(), _buildGpsButton(), _buildFilterButton()], ); } @@ -30,14 +127,14 @@ class MapWidget extends GetView { ), children: [ TileLayer(urlTemplate: controller.tileType), - /* ObxValue((markers) { + ObxValue((markers) { return MarkerLayer( markers: markers .map((e) => markerWidget(marker: e, onTap: () {})) .toList(), ); - }, controller.markers),*/ + }, controller.markers), ], ); }, controller.currentLocation); @@ -73,4 +170,22 @@ class MapWidget extends GetView { ), ); } + + Marker markerWidget({required LatLng marker, required VoidCallback onTap}) { + return Marker( + point: marker, + child: GestureDetector( + onTap: onTap, + behavior: HitTestBehavior.opaque, + child: SizedBox( + width: 36, + height: 36, + child:Assets.vec.mapMarkerSvg.svg( + width: 30, + height: 30, + ) + ), + ), + ); + } }