mimic google behavior with location icon button

This commit is contained in:
bytedream 2024-03-27 22:08:09 +01:00
parent 507b321311
commit c00d2fac05
4 changed files with 89 additions and 58 deletions

View File

@ -0,0 +1,8 @@
import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart';
extension LatLngPositionExtension on Position {
LatLng latlng() {
return LatLng(latitude, longitude);
}
}

View File

@ -4,13 +4,13 @@ import 'package:geolocator/geolocator.dart';
import 'package:latlong2/latlong.dart';
class MapState extends ChangeNotifier {
bool _isCurrentlyLoading = false;
bool _isLocationLive = false;
LatLng? _currentLocation;
LatLng? _activeMarker;
final MapController _mapController = MapController();
final Geolocator _geolocator = Geolocator();
bool get isCurrentlyLoading => _isCurrentlyLoading;
bool get isLocationLive => _isLocationLive;
LatLng? get getCurrentLocation => _currentLocation;
LatLng? get getActiveMarker => _activeMarker;
MapController get getMapController => _mapController;
@ -18,16 +18,21 @@ class MapState extends ChangeNotifier {
void setCurrentLocation(LatLng? currentLocation) {
_currentLocation = currentLocation;
if (currentLocation != null) _mapController.move(currentLocation, 16);
notifyListeners();
}
void setActiveMarker(LatLng? marker) {
_activeMarker = marker;
if (marker != null) {
_isLocationLive = false;
_mapController.move(marker, 16);
}
notifyListeners();
}
void setLoading(bool loading) {
_isCurrentlyLoading = loading;
void setLocationLive(bool live) {
_isLocationLive = live;
notifyListeners();
}
}

View File

@ -1,4 +1,5 @@
import 'package:app/extensions/obtainProviderExtension.dart';
import 'package:app/extensions/positionLatLngExtension.dart';
import 'package:app/state/mapState.dart';
import 'package:app/state/timeStatusState.dart';
import 'package:app/util/watchState.dart';
@ -19,41 +20,70 @@ class HomeView extends StatefulWidget {
class _HomePageState extends State<HomeView> {
bool locationEnabled = false;
Future<LatLng?> getLatLng() async {
LocationPermission permission = await Geolocator.checkPermission();
if (permission == LocationPermission.denied) {
permission = await Geolocator.requestPermission();
if (permission == LocationPermission.denied || permission == LocationPermission.deniedForever) {
return null;
}
}
setState(() {
locationEnabled = true;
});
Position? position;
try {
position = await Geolocator.getCurrentPosition();
} catch (e) {
position = await Geolocator.getLastKnownPosition();
}
if (position != null) {
return LatLng(position.latitude, position.longitude);
}
return null;
}
bool locationLoading = false;
@override
void initState() {
super.initState();
Geolocator.checkPermission().then((permission) => setState(() {
locationEnabled = permission != LocationPermission.denied && permission != LocationPermission.deniedForever;
}));
Geolocator.getServiceStatusStream().listen((status) {
setState(() {
locationEnabled = status == ServiceStatus.enabled;
});
});
requestLiveLocation(context.obtainState<MapState>(), false, true, true);
}
Future<void> requestLiveLocation(MapState mapState, bool ask, bool orLast, bool loadingIndicator) async {
Position? position;
LocationPermission permission = await Geolocator.checkPermission();
if (loadingIndicator && permission != LocationPermission.deniedForever) {
setState(() {
locationLoading = true;
});
}
if (permission == LocationPermission.denied || permission == LocationPermission.deniedForever) {
if (ask && permission != LocationPermission.deniedForever) {
permission = await Geolocator.requestPermission();
}
if (permission == LocationPermission.denied || permission == LocationPermission.deniedForever) {
if (orLast) position = await Geolocator.getLastKnownPosition();
}
}
if (permission == LocationPermission.denied || permission == LocationPermission.deniedForever) {
if (position != null) {
setState(() => locationEnabled = true);
mapState.setCurrentLocation(position.latlng());
}
setState(() => locationLoading = false);
return;
}
try {
position = await Geolocator.getCurrentPosition();
setState(() {
locationEnabled = true;
});
mapState.setLocationLive(true);
mapState.setCurrentLocation(position.latlng());
Geolocator.getServiceStatusStream().first.then((_) => setState(() {
mapState.setLocationLive(false);
}));
} catch (_) {
if (orLast) {
position = await Geolocator.getLastKnownPosition();
if (position != null) {
setState(() => locationEnabled = true);
mapState.setCurrentLocation(position.latlng());
}
}
}
setState(() => locationLoading = false);
}
@override
@ -72,9 +102,6 @@ class _HomePageState extends State<HomeView> {
delegate: LocationSearchDelegate(),
);
mapState.setActiveMarker(latLng);
if (latLng != null) {
mapState.getMapController.move(latLng, 16);
}
},
),
IconButton(
@ -90,26 +117,15 @@ class _HomePageState extends State<HomeView> {
),
floatingActionButton: FloatingActionButton(
child: WatchState<MapState>((context, state) {
if(locationEnabled) {
if(state.isCurrentlyLoading) {
return const Padding(padding: EdgeInsets.all(15), child: CircularProgressIndicator(strokeWidth: 3));
} else {
return const Icon(Icons.my_location);
}
if (locationLoading) {
return const Padding(padding: EdgeInsets.all(15), child: CircularProgressIndicator(strokeWidth: 3));
}
if (locationEnabled) {
return Icon(state.isLocationLive ? Icons.my_location : Icons.location_searching);
}
return const Icon(Icons.location_disabled);
}),
onPressed: () async {
MapState mapState = context.obtainState<MapState>();
mapState.setLoading(true);
LatLng? latLng = await getLatLng();
if (latLng != null) {
mapState.setCurrentLocation(latLng);
mapState.getMapController.move(latLng, 16);
}
mapState.setLoading(false);
},
onPressed: () => requestLiveLocation(context.obtainState<MapState>(), true, false, true),
),
body: Column(
children: [

View File

@ -1,7 +1,6 @@
import 'package:app/extensions/obtainProviderExtension.dart';
import 'package:app/state/mapState.dart';
import 'package:app/util/watchState.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:http/http.dart';
@ -20,10 +19,13 @@ class _MapViewState extends State<MapView> {
Widget build(BuildContext context) {
return FlutterMap(
mapController: context.obtainState<MapState>().getMapController,
options: const MapOptions(
initialCenter: LatLng(50.354, 7.5845),
options: MapOptions(
onPositionChanged: (position, hasGesture) => {
if (hasGesture) context.obtainState<MapState>().setLocationLive(false)
},
initialCenter: const LatLng(50.354, 7.5845),
initialZoom: 16,
interactionOptions: InteractionOptions(
interactionOptions: const InteractionOptions(
flags: InteractiveFlag.all & ~InteractiveFlag.rotate
)
),