mimic google behavior with location icon button
This commit is contained in:
parent
507b321311
commit
c00d2fac05
8
lib/extensions/positionLatLngExtension.dart
Normal file
8
lib/extensions/positionLatLngExtension.dart
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
@ -4,13 +4,13 @@ import 'package:geolocator/geolocator.dart';
|
|||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
|
|
||||||
class MapState extends ChangeNotifier {
|
class MapState extends ChangeNotifier {
|
||||||
bool _isCurrentlyLoading = false;
|
bool _isLocationLive = false;
|
||||||
LatLng? _currentLocation;
|
LatLng? _currentLocation;
|
||||||
LatLng? _activeMarker;
|
LatLng? _activeMarker;
|
||||||
final MapController _mapController = MapController();
|
final MapController _mapController = MapController();
|
||||||
final Geolocator _geolocator = Geolocator();
|
final Geolocator _geolocator = Geolocator();
|
||||||
|
|
||||||
bool get isCurrentlyLoading => _isCurrentlyLoading;
|
bool get isLocationLive => _isLocationLive;
|
||||||
LatLng? get getCurrentLocation => _currentLocation;
|
LatLng? get getCurrentLocation => _currentLocation;
|
||||||
LatLng? get getActiveMarker => _activeMarker;
|
LatLng? get getActiveMarker => _activeMarker;
|
||||||
MapController get getMapController => _mapController;
|
MapController get getMapController => _mapController;
|
||||||
@ -18,16 +18,21 @@ class MapState extends ChangeNotifier {
|
|||||||
|
|
||||||
void setCurrentLocation(LatLng? currentLocation) {
|
void setCurrentLocation(LatLng? currentLocation) {
|
||||||
_currentLocation = currentLocation;
|
_currentLocation = currentLocation;
|
||||||
|
if (currentLocation != null) _mapController.move(currentLocation, 16);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setActiveMarker(LatLng? marker) {
|
void setActiveMarker(LatLng? marker) {
|
||||||
_activeMarker = marker;
|
_activeMarker = marker;
|
||||||
|
if (marker != null) {
|
||||||
|
_isLocationLive = false;
|
||||||
|
_mapController.move(marker, 16);
|
||||||
|
}
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void setLoading(bool loading) {
|
void setLocationLive(bool live) {
|
||||||
_isCurrentlyLoading = loading;
|
_isLocationLive = live;
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:app/extensions/obtainProviderExtension.dart';
|
import 'package:app/extensions/obtainProviderExtension.dart';
|
||||||
|
import 'package:app/extensions/positionLatLngExtension.dart';
|
||||||
import 'package:app/state/mapState.dart';
|
import 'package:app/state/mapState.dart';
|
||||||
import 'package:app/state/timeStatusState.dart';
|
import 'package:app/state/timeStatusState.dart';
|
||||||
import 'package:app/util/watchState.dart';
|
import 'package:app/util/watchState.dart';
|
||||||
@ -19,41 +20,70 @@ class HomeView extends StatefulWidget {
|
|||||||
|
|
||||||
class _HomePageState extends State<HomeView> {
|
class _HomePageState extends State<HomeView> {
|
||||||
bool locationEnabled = false;
|
bool locationEnabled = false;
|
||||||
|
bool locationLoading = 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
Geolocator.checkPermission().then((permission) => setState(() {
|
Geolocator.getServiceStatusStream().listen((status) {
|
||||||
locationEnabled = permission != LocationPermission.denied && permission != LocationPermission.deniedForever;
|
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
|
@override
|
||||||
@ -72,9 +102,6 @@ class _HomePageState extends State<HomeView> {
|
|||||||
delegate: LocationSearchDelegate(),
|
delegate: LocationSearchDelegate(),
|
||||||
);
|
);
|
||||||
mapState.setActiveMarker(latLng);
|
mapState.setActiveMarker(latLng);
|
||||||
if (latLng != null) {
|
|
||||||
mapState.getMapController.move(latLng, 16);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
@ -90,26 +117,15 @@ class _HomePageState extends State<HomeView> {
|
|||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
floatingActionButton: FloatingActionButton(
|
||||||
child: WatchState<MapState>((context, state) {
|
child: WatchState<MapState>((context, state) {
|
||||||
if(locationEnabled) {
|
if (locationLoading) {
|
||||||
if(state.isCurrentlyLoading) {
|
|
||||||
return const Padding(padding: EdgeInsets.all(15), child: CircularProgressIndicator(strokeWidth: 3));
|
return const Padding(padding: EdgeInsets.all(15), child: CircularProgressIndicator(strokeWidth: 3));
|
||||||
} else {
|
|
||||||
return const Icon(Icons.my_location);
|
|
||||||
}
|
}
|
||||||
|
if (locationEnabled) {
|
||||||
|
return Icon(state.isLocationLive ? Icons.my_location : Icons.location_searching);
|
||||||
}
|
}
|
||||||
|
|
||||||
return const Icon(Icons.location_disabled);
|
return const Icon(Icons.location_disabled);
|
||||||
}),
|
}),
|
||||||
onPressed: () async {
|
onPressed: () => requestLiveLocation(context.obtainState<MapState>(), true, false, true),
|
||||||
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);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:app/extensions/obtainProviderExtension.dart';
|
import 'package:app/extensions/obtainProviderExtension.dart';
|
||||||
import 'package:app/state/mapState.dart';
|
import 'package:app/state/mapState.dart';
|
||||||
import 'package:app/util/watchState.dart';
|
import 'package:app/util/watchState.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_map/flutter_map.dart';
|
import 'package:flutter_map/flutter_map.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
@ -20,10 +19,13 @@ class _MapViewState extends State<MapView> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FlutterMap(
|
return FlutterMap(
|
||||||
mapController: context.obtainState<MapState>().getMapController,
|
mapController: context.obtainState<MapState>().getMapController,
|
||||||
options: const MapOptions(
|
options: MapOptions(
|
||||||
initialCenter: LatLng(50.354, 7.5845),
|
onPositionChanged: (position, hasGesture) => {
|
||||||
|
if (hasGesture) context.obtainState<MapState>().setLocationLive(false)
|
||||||
|
},
|
||||||
|
initialCenter: const LatLng(50.354, 7.5845),
|
||||||
initialZoom: 16,
|
initialZoom: 16,
|
||||||
interactionOptions: InteractionOptions(
|
interactionOptions: const InteractionOptions(
|
||||||
flags: InteractiveFlag.all & ~InteractiveFlag.rotate
|
flags: InteractiveFlag.all & ~InteractiveFlag.rotate
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
Reference in New Issue
Block a user