Usability and styling #24
| @@ -34,26 +34,19 @@ ThemeData APP_THEME = ThemeData( | |||||||
|  |  | ||||||
|  |  | ||||||
|   textButtonTheme: TextButtonThemeData( |   textButtonTheme: TextButtonThemeData( | ||||||
|  |      | ||||||
|     style: TextButton.styleFrom( |     style: TextButton.styleFrom( | ||||||
|       backgroundColor: PRIMARY_COLOR, |       backgroundColor: PRIMARY_COLOR, | ||||||
|       textStyle: TextStyle( |       textStyle: TextStyle( | ||||||
|         color: Colors.black, |         color: Colors.red | ||||||
|       ), |       ) | ||||||
|     ), |     ), | ||||||
|   ), |   ), | ||||||
|  |  | ||||||
|   iconButtonTheme: IconButtonThemeData( |  | ||||||
|     style: ButtonStyle( |  | ||||||
|       backgroundColor: MaterialStateProperty.all(PRIMARY_COLOR), |  | ||||||
|     ) |  | ||||||
|   ), |  | ||||||
|    |  | ||||||
|   buttonTheme: ButtonThemeData( |   buttonTheme: ButtonThemeData( | ||||||
|     buttonColor: PRIMARY_COLOR, |     buttonColor: PRIMARY_COLOR, | ||||||
|     textTheme: ButtonTextTheme.primary, |     textTheme: ButtonTextTheme.primary, | ||||||
|   ), |   ), | ||||||
|  |  | ||||||
|    |  | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -6,22 +6,23 @@ import 'package:flutter/material.dart'; | |||||||
| import 'package:anyway/structs/landmark.dart'; | import 'package:anyway/structs/landmark.dart'; | ||||||
| import 'package:anyway/structs/trip.dart'; | import 'package:anyway/structs/trip.dart'; | ||||||
| import 'package:google_maps_flutter/google_maps_flutter.dart'; | import 'package:google_maps_flutter/google_maps_flutter.dart'; | ||||||
|  | import 'package:shared_preferences/shared_preferences.dart'; | ||||||
| import 'package:widget_to_marker/widget_to_marker.dart'; | import 'package:widget_to_marker/widget_to_marker.dart'; | ||||||
|  |  | ||||||
|  |  | ||||||
| class MapWidget extends StatefulWidget { | class CurrentTripMap extends StatefulWidget { | ||||||
|  |  | ||||||
|   final Trip? trip; |   final Trip? trip; | ||||||
|  |  | ||||||
|   MapWidget({ |   CurrentTripMap({ | ||||||
|     this.trip |     this.trip | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   State<MapWidget> createState() => _MapWidgetState(); |   State<CurrentTripMap> createState() => _CurrentTripMapState(); | ||||||
| } | } | ||||||
|  |  | ||||||
| class _MapWidgetState extends State<MapWidget> { | class _CurrentTripMapState extends State<CurrentTripMap> { | ||||||
|   late GoogleMapController mapController; |   late GoogleMapController mapController; | ||||||
|  |  | ||||||
|   CameraPosition _cameraPosition = CameraPosition( |   CameraPosition _cameraPosition = CameraPosition( | ||||||
| @@ -67,9 +68,27 @@ class _MapWidgetState extends State<MapWidget> { | |||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     widget.trip?.addListener(setMapMarkers); |     widget.trip?.addListener(setMapMarkers); | ||||||
|  |     Future<SharedPreferences> preferences = SharedPreferences.getInstance(); | ||||||
|  |  | ||||||
|  |     return FutureBuilder( | ||||||
|  |       future: preferences, | ||||||
|  |       builder: (context, snapshot) { | ||||||
|  |         if (snapshot.hasData) { | ||||||
|  |           SharedPreferences prefs = snapshot.data as SharedPreferences; | ||||||
|  |           bool useLocation = prefs.getBool('useLocation') ?? true; | ||||||
|  |           return _buildMap(useLocation); | ||||||
|  |         } else { | ||||||
|  |           return const CircularProgressIndicator(); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget _buildMap(bool useLocation) { | ||||||
|     return GoogleMap( |     return GoogleMap( | ||||||
|       onMapCreated: _onMapCreated, |       onMapCreated: _onMapCreated, | ||||||
|       initialCameraPosition: _cameraPosition, |       initialCameraPosition: _cameraPosition, | ||||||
| @@ -79,7 +98,9 @@ class _MapWidgetState extends State<MapWidget> { | |||||||
|       cloudMapId: MAP_ID, |       cloudMapId: MAP_ID, | ||||||
|       mapToolbarEnabled: false, |       mapToolbarEnabled: false, | ||||||
|       zoomControlsEnabled: false, |       zoomControlsEnabled: false, | ||||||
|       myLocationEnabled: true, |       myLocationEnabled: useLocation, | ||||||
|  |       myLocationButtonEnabled: false, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import 'package:anyway/structs/landmark.dart'; | |||||||
| import 'package:anyway/structs/trip.dart'; | import 'package:anyway/structs/trip.dart'; | ||||||
| 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 'package:shared_preferences/shared_preferences.dart'; | ||||||
| import 'package:widget_to_marker/widget_to_marker.dart'; | import 'package:widget_to_marker/widget_to_marker.dart'; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -72,6 +73,23 @@ class _NewTripMapState extends State<NewTripMap> { | |||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     widget.trip.addListener(updateTripDetails); |     widget.trip.addListener(updateTripDetails); | ||||||
|  |     Future<SharedPreferences> preferences = SharedPreferences.getInstance(); | ||||||
|  |  | ||||||
|  |     return FutureBuilder( | ||||||
|  |       future: preferences, | ||||||
|  |       builder: (context, snapshot) { | ||||||
|  |         if (snapshot.hasData) { | ||||||
|  |           SharedPreferences prefs = snapshot.data as SharedPreferences; | ||||||
|  |           bool useLocation = prefs.getBool('useLocation') ?? true; | ||||||
|  |           return _buildMap(useLocation); | ||||||
|  |         } else { | ||||||
|  |           return const CircularProgressIndicator(); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   Widget _buildMap(bool useLocation) { | ||||||
|     return GoogleMap( |     return GoogleMap( | ||||||
|       onMapCreated: _onMapCreated, |       onMapCreated: _onMapCreated, | ||||||
|       initialCameraPosition: _cameraPosition, |       initialCameraPosition: _cameraPosition, | ||||||
| @@ -80,8 +98,8 @@ class _NewTripMapState extends State<NewTripMap> { | |||||||
|       cloudMapId: MAP_ID, |       cloudMapId: MAP_ID, | ||||||
|       mapToolbarEnabled: false, |       mapToolbarEnabled: false, | ||||||
|       zoomControlsEnabled: false, |       zoomControlsEnabled: false, | ||||||
|       // TODO: should be loaded from the sharedprefs |       myLocationButtonEnabled: false, | ||||||
|       myLocationEnabled: true, |       myLocationEnabled: useLocation, | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
| } | } | ||||||
| @@ -29,14 +29,14 @@ class _TripPageState extends State<TripPage> { | |||||||
|     return SlidingUpPanel( |     return SlidingUpPanel( | ||||||
|         panelBuilder: (sc) => _panelFull(sc), |         panelBuilder: (sc) => _panelFull(sc), | ||||||
|         // collapsed: _floatingCollapsed(), |         // collapsed: _floatingCollapsed(), | ||||||
|         body: MapWidget(trip: widget.trip), |         body: CurrentTripMap(trip: widget.trip), | ||||||
|         // renderPanelSheet: false, |         // renderPanelSheet: false, | ||||||
|         // backdropEnabled: true, |         // backdropEnabled: true, | ||||||
|         maxHeight: MediaQuery.of(context).size.height * 0.8, |         maxHeight: MediaQuery.of(context).size.height * 0.8, | ||||||
|         padding: EdgeInsets.only(left: 10, right: 10, top: 25, bottom: 10), |         padding: EdgeInsets.only(left: 10, right: 10, top: 25, bottom: 10), | ||||||
|         // panelSnapping: false, |         // panelSnapping: false, | ||||||
|         borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), |         borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), | ||||||
|         boxShadow: [ |         boxShadow: const [ | ||||||
|           BoxShadow( |           BoxShadow( | ||||||
|             blurRadius: 20.0, |             blurRadius: 20.0, | ||||||
|             color: Colors.black, |             color: Colors.black, | ||||||
|   | |||||||
| @@ -84,6 +84,8 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> { | |||||||
|       for (SinglePreference pref in prefs) { |       for (SinglePreference pref in prefs) { | ||||||
|       sliders.add( |       sliders.add( | ||||||
|         Card( |         Card( | ||||||
|  |           margin: const EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 0), | ||||||
|  |           shadowColor: Colors.grey, | ||||||
|           child: ListTile( |           child: ListTile( | ||||||
|             leading: pref.icon, |             leading: pref.icon, | ||||||
|             title: Text(pref.name), |             title: Text(pref.name), | ||||||
| @@ -100,8 +102,6 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> { | |||||||
|               }, |               }, | ||||||
|             ) |             ) | ||||||
|           ), |           ), | ||||||
|           margin: const EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 0), |  | ||||||
|           shadowColor: Colors.grey, |  | ||||||
|         ) |         ) | ||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -7,7 +7,6 @@ import 'package:url_launcher/url_launcher.dart'; | |||||||
|  |  | ||||||
|  |  | ||||||
| bool debugMode = false; | bool debugMode = false; | ||||||
| bool useLocation = false; |  | ||||||
|  |  | ||||||
| class SettingsPage extends StatefulWidget { | class SettingsPage extends StatefulWidget { | ||||||
|   @override |   @override | ||||||
| @@ -15,7 +14,6 @@ class SettingsPage extends StatefulWidget { | |||||||
| } | } | ||||||
|  |  | ||||||
| class _SettingsPageState extends State<SettingsPage> { | class _SettingsPageState extends State<SettingsPage> { | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return ListView( |     return ListView( | ||||||
| @@ -90,6 +88,7 @@ class _SettingsPageState extends State<SettingsPage> { | |||||||
|       ], |       ], | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Widget darkMode() { |   Widget darkMode() { | ||||||
|     return Row( |     return Row( | ||||||
|       children: [ |       children: [ | ||||||
| @@ -115,46 +114,58 @@ class _SettingsPageState extends State<SettingsPage> { | |||||||
|       ], |       ], | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Widget setLocationUsage() { |   Widget setLocationUsage() { | ||||||
|  |     Future<SharedPreferences> preferences = SharedPreferences.getInstance(); | ||||||
|     return Row( |     return Row( | ||||||
|       children: [ |       children: [ | ||||||
|         Text('Use location services'), |         Text('Use location services'), | ||||||
|         // white space |         // white space | ||||||
|         Spacer(), |         Spacer(), | ||||||
|         Switch( |         FutureBuilder( | ||||||
|           value: useLocation, |           future: preferences, | ||||||
|           onChanged: (bool? newValue) async { |           builder: (context, snapshot) { | ||||||
|             await Permission.locationWhenInUse |             if (snapshot.hasData) { | ||||||
|               .onDeniedCallback(() { |               bool useLocation = snapshot.data!.getBool('useLocation') ?? false; | ||||||
|                 rootScaffoldMessengerKey.currentState!.showSnackBar( |               return Switch( | ||||||
|                   SnackBar(content: Text('Location services are required for this feature')) |                 value: useLocation, | ||||||
|                 ); |                 onChanged: setUseLocation, | ||||||
|               }) |               ); | ||||||
|               .onGrantedCallback(() { |             } else { | ||||||
|                 rootScaffoldMessengerKey.currentState!.showSnackBar( |               return CircularProgressIndicator(); | ||||||
|                   SnackBar(content: Text('Location services are now enabled')) |             } | ||||||
|                 ); |  | ||||||
|                 setState(() { |  | ||||||
|                   useLocation = newValue!; |  | ||||||
|                 }); |  | ||||||
|                 SharedPreferences.getInstance().then( |  | ||||||
|                   (SharedPreferences prefs) { |  | ||||||
|                     prefs.setBool('useLocation', useLocation); |  | ||||||
|                   } |  | ||||||
|                 ); |  | ||||||
|               }) |  | ||||||
|               .onPermanentlyDeniedCallback(() { |  | ||||||
|                 rootScaffoldMessengerKey.currentState!.showSnackBar( |  | ||||||
|                   SnackBar(content: Text('Location services are required for this feature')) |  | ||||||
|                 ); |  | ||||||
|               })   |  | ||||||
|             .request(); |  | ||||||
|           } |           } | ||||||
|         ) |         ) | ||||||
|       ], |       ], | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   void setUseLocation(bool newValue) async { | ||||||
|  |     await Permission.locationWhenInUse | ||||||
|  |       .onDeniedCallback(() { | ||||||
|  |         rootScaffoldMessengerKey.currentState!.showSnackBar( | ||||||
|  |           SnackBar(content: Text('Location services are required for this feature')) | ||||||
|  |         ); | ||||||
|  |       }) | ||||||
|  |       .onGrantedCallback(() { | ||||||
|  |         rootScaffoldMessengerKey.currentState!.showSnackBar( | ||||||
|  |           SnackBar(content: Text('Location services are now enabled')) | ||||||
|  |         ); | ||||||
|  |         SharedPreferences.getInstance().then( | ||||||
|  |           (SharedPreferences prefs) { | ||||||
|  |             setState(() { | ||||||
|  |               prefs.setBool('useLocation', newValue); | ||||||
|  |             }); | ||||||
|  |           } | ||||||
|  |         ); | ||||||
|  |       }) | ||||||
|  |       .onPermanentlyDeniedCallback(() { | ||||||
|  |         rootScaffoldMessengerKey.currentState!.showSnackBar( | ||||||
|  |           SnackBar(content: Text('Location services are required for this feature')) | ||||||
|  |         ); | ||||||
|  |       })   | ||||||
|  |     .request(); | ||||||
|  |   } | ||||||
|  |  | ||||||
|   Widget privacyInfo() { |   Widget privacyInfo() { | ||||||
|     return Center( |     return Center( | ||||||
| @@ -163,8 +174,8 @@ class _SettingsPageState extends State<SettingsPage> { | |||||||
|           Text('Our privacy policy is available under:'), |           Text('Our privacy policy is available under:'), | ||||||
|            |            | ||||||
|           TextButton.icon( |           TextButton.icon( | ||||||
|             icon: Icon(Icons.info), |             icon: Icon(Icons.info, color: Colors.white), | ||||||
|             label: Text(PRIVACY_URL), |             label: Text(PRIVACY_URL, style: TextStyle(color: Colors.white)), | ||||||
|             onPressed: () async{ |             onPressed: () async{ | ||||||
|               await launchUrl(Uri.parse(PRIVACY_URL)); |               await launchUrl(Uri.parse(PRIVACY_URL)); | ||||||
|             } |             } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user