Hibok
Non puoi selezionare più di 25 argomenti Gli argomenti devono iniziare con una lettera o un numero, possono includere trattini ('-') e possono essere lunghi fino a 35 caratteri.
 
 
 
 
 
 

364 righe
11 KiB

  1. import 'dart:async';
  2. import 'dart:convert';
  3. import 'dart:ui';
  4. import 'package:android_intent/android_intent.dart';
  5. import 'package:chat/utils/loading_builder.dart';
  6. import 'package:chat/utils/log.dart';
  7. import 'package:chat/utils/screen_shot.dart';
  8. import 'package:flutter/material.dart';
  9. import 'package:flutter/rendering.dart';
  10. import 'package:flutter/services.dart';
  11. import 'package:geolocator/geolocator.dart';
  12. import 'package:google_maps_flutter/google_maps_flutter.dart';
  13. import 'package:provider/provider.dart';
  14. import 'location_provider.dart';
  15. import 'location_result.dart';
  16. import 'package:http/http.dart' as http;
  17. class MapPicker extends StatefulWidget {
  18. final LatLng initialCenter;
  19. final String apiKey;
  20. final bool requiredGPS;
  21. const MapPicker({
  22. Key key,
  23. this.initialCenter,
  24. this.apiKey,
  25. this.requiredGPS,
  26. }) : super(key: key);
  27. @override
  28. MapPickerState createState() => MapPickerState();
  29. }
  30. class MapPickerState extends State<MapPicker> {
  31. Completer<GoogleMapController> mapController = Completer();
  32. GlobalKey rootWidgetKey = GlobalKey();
  33. LatLng _lastMapPosition;
  34. Position _currentPosition;
  35. String _address;
  36. // void _onToggleMapTypePressed() {
  37. // final MapType nextType =
  38. // MapType.values[(_currentMapType.index + 1) % MapType.values.length];
  39. // setState(() => _currentMapType = nextType);
  40. // }
  41. // this also checks for location permission.
  42. Future<void> _initCurrentLocation() async {
  43. Position currentPosition;
  44. try {
  45. currentPosition = await Geolocator()
  46. .getCurrentPosition(desiredAccuracy: LocationAccuracy.best);
  47. d("position = $currentPosition");
  48. setState(() => _currentPosition = currentPosition);
  49. } on PlatformException catch (e) {
  50. currentPosition = null;
  51. d("_initCurrentLocation#e = $e");
  52. }
  53. if (!mounted) return;
  54. setState(() => _currentPosition = currentPosition);
  55. if (currentPosition != null)
  56. moveToCurrentLocation(
  57. LatLng(currentPosition.latitude, currentPosition.longitude));
  58. }
  59. @override
  60. void initState() {
  61. super.initState();
  62. _initCurrentLocation();
  63. }
  64. @override
  65. void dispose() {
  66. rootWidgetKey = null;
  67. super.dispose();
  68. }
  69. @override
  70. Widget build(BuildContext context) {
  71. if (widget.requiredGPS) {
  72. _checkGps();
  73. _checkGeolocationPermission();
  74. }
  75. return Scaffold(
  76. body: Builder(builder: (context) {
  77. if (_currentPosition == null && widget.requiredGPS)
  78. return const Center(child: CircularProgressIndicator());
  79. return buildMap();
  80. }),
  81. );
  82. }
  83. Widget buildMap() {
  84. return Center(
  85. child: Stack(
  86. children: <Widget>[
  87. GoogleMap(
  88. onMapCreated: (GoogleMapController controller) {
  89. mapController.complete(controller);
  90. _lastMapPosition = widget.initialCenter;
  91. LocationProvider.of(context)
  92. .setLastIdleLocation(_lastMapPosition);
  93. },
  94. initialCameraPosition: CameraPosition(
  95. target: widget.initialCenter,
  96. zoom: 18.0,
  97. ),
  98. onCameraMove: (CameraPosition position) {
  99. _lastMapPosition = position.target;
  100. },
  101. onCameraIdle: () async {
  102. LocationProvider.of(context)
  103. .setLastIdleLocation(_lastMapPosition);
  104. },
  105. myLocationEnabled: true,
  106. myLocationButtonEnabled: true),
  107. // _MapFabs(
  108. // onToggleMapTypePressed: _onToggleMapTypePressed,
  109. // ),
  110. pin(),
  111. locationCard(),
  112. ],
  113. ),
  114. );
  115. }
  116. Widget locationCard() {
  117. return Align(
  118. alignment: Alignment.bottomCenter,
  119. child: Padding(
  120. padding: const EdgeInsets.fromLTRB(8, 8, 8, 24),
  121. child: Card(
  122. child: Padding(
  123. padding: const EdgeInsets.all(8),
  124. child: Consumer<LocationProvider>(
  125. builder: (context, locationProvider, _) {
  126. return Row(
  127. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  128. children: <Widget>[
  129. Flexible(
  130. flex: 20,
  131. child: FutureLoadingBuilder<String>(
  132. future: getAddress(locationProvider.lastIdleLocation),
  133. mutable: true,
  134. loadingIndicator: Row(
  135. mainAxisAlignment: MainAxisAlignment.center,
  136. children: <Widget>[
  137. CircularProgressIndicator(),
  138. ],
  139. ),
  140. builder: (context, address) {
  141. _address = address;
  142. return Column(
  143. mainAxisSize: MainAxisSize.min,
  144. children: [
  145. Text(
  146. address ?? 'Unnamed place',
  147. style: TextStyle(
  148. fontSize: 18,
  149. ),
  150. ),
  151. ],
  152. );
  153. }),
  154. ),
  155. Spacer(),
  156. FloatingActionButton(
  157. onPressed: () async {
  158. var capture = await ScreenShot.takeScreenshotImage();
  159. Navigator.of(context).pop({
  160. 'location': LocationResult(
  161. latLng: locationProvider.lastIdleLocation,
  162. address: _address,
  163. screen: capture),
  164. });
  165. },
  166. child: Icon(Icons.send, color: Colors.white),
  167. ),
  168. ],
  169. );
  170. }),
  171. ),
  172. ),
  173. ),
  174. );
  175. }
  176. Future<String> getAddress(LatLng latLng) async {
  177. try {
  178. /*
  179. var placeMarks = await Geolocator()
  180. .placemarkFromCoordinates(latLng.latitude, latLng.longitude);
  181. if (placeMarks == null) {
  182. return null;
  183. }
  184. var place = placeMarks.first;
  185. print('place ${place.toJson()}');
  186. return place.name;
  187. */
  188. var endPoint =
  189. 'https://maps.googleapis.com/maps/api/geocode/json?latlng=${latLng?.latitude},${latLng?.longitude}&key=${widget.apiKey}';
  190. var response = jsonDecode((await http.get(endPoint)).body);
  191. return response['results'][0]['formatted_address'];
  192. } catch (e) {
  193. print(e);
  194. }
  195. return null;
  196. }
  197. Center pin() {
  198. return Center(
  199. child: Column(
  200. mainAxisAlignment: MainAxisAlignment.center,
  201. children: <Widget>[
  202. Icon(Icons.place, size: 56, color: Colors.lightBlue),
  203. Container(
  204. decoration: ShapeDecoration(
  205. shadows: [
  206. BoxShadow(
  207. color: Colors.black38,
  208. blurRadius: 4,
  209. ),
  210. ],
  211. shape: CircleBorder(
  212. side: BorderSide(
  213. width: 4,
  214. color: Colors.transparent,
  215. ),
  216. ),
  217. ),
  218. ),
  219. SizedBox(height: 56),
  220. ],
  221. ),
  222. );
  223. }
  224. Future moveToCurrentLocation(LatLng currentLocation) async {
  225. var controller = await mapController.future;
  226. controller.animateCamera(CameraUpdate.newCameraPosition(
  227. CameraPosition(target: currentLocation, zoom: 18.0),
  228. ));
  229. }
  230. var dialogOpen;
  231. Future _checkGeolocationPermission() async {
  232. var geolocationStatus =
  233. await Geolocator().checkGeolocationPermissionStatus();
  234. if (geolocationStatus == GeolocationStatus.denied && dialogOpen == null) {
  235. d('showDialog');
  236. dialogOpen = showDialog(
  237. context: context,
  238. barrierDismissible: false,
  239. builder: (context) {
  240. return AlertDialog(
  241. title: Text('Access to location denied'),
  242. content: Text('Allow access to the location services.'),
  243. actions: <Widget>[
  244. FlatButton(
  245. child: Text('Ok'),
  246. onPressed: () {
  247. Navigator.of(context, rootNavigator: true).pop();
  248. _initCurrentLocation();
  249. dialogOpen = null;
  250. },
  251. ),
  252. ],
  253. );
  254. },
  255. );
  256. //} else if (geolocationStatus == GeolocationStatus.disabled) {
  257. } else if (geolocationStatus == GeolocationStatus.granted) {
  258. d('GeolocationStatus.granted');
  259. if (dialogOpen != null) {
  260. Navigator.of(context, rootNavigator: true).pop();
  261. dialogOpen = null;
  262. }
  263. }
  264. }
  265. Future _checkGps() async {
  266. if (!(await Geolocator().isLocationServiceEnabled())) {
  267. if (Theme.of(context).platform == TargetPlatform.android) {
  268. showDialog(
  269. context: context,
  270. barrierDismissible: false,
  271. builder: (BuildContext context) {
  272. return AlertDialog(
  273. title: Text("Can't get current location"),
  274. content: Text('Please make sure you enable GPS and try again'),
  275. actions: <Widget>[
  276. FlatButton(
  277. child: Text('Ok'),
  278. onPressed: () {
  279. final AndroidIntent intent = AndroidIntent(
  280. action: 'android.settings.LOCATION_SOURCE_SETTINGS');
  281. intent.launch();
  282. Navigator.of(context, rootNavigator: true).pop();
  283. },
  284. ),
  285. ],
  286. );
  287. },
  288. );
  289. }
  290. }
  291. }
  292. }
  293. /*
  294. class _MapFabs extends StatelessWidget {
  295. const _MapFabs({
  296. Key key,
  297. @required this.onToggleMapTypePressed,
  298. }) : assert(onToggleMapTypePressed != null),
  299. super(key: key);
  300. final VoidCallback onToggleMapTypePressed;
  301. @override
  302. Widget build(BuildContext context) {
  303. return Container(
  304. alignment: Alignment.topRight,
  305. margin: const EdgeInsets.only(top: 64, right: 8),
  306. child: Column(
  307. children: <Widget>[
  308. FloatingActionButton(
  309. onPressed: onToggleMapTypePressed,
  310. materialTapTargetSize: MaterialTapTargetSize.padded,
  311. mini: true,
  312. child: const Icon(Icons.layers, size: 28, color: Colors.white),
  313. heroTag: "layers",
  314. ),
  315. ],
  316. ),
  317. );
  318. }
  319. }*/