better visual coherence
This commit is contained in:
		| @@ -13,6 +13,11 @@ const Color GRADIENT_END = Color(0xFFE72E77); | |||||||
|  |  | ||||||
| const Color PRIMARY_COLOR = Color(0xFFF38F1A); | const Color PRIMARY_COLOR = Color(0xFFF38F1A); | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | const double TRIP_PANEL_MAX_HEIGHT = 0.8; | ||||||
|  | const double TRIP_PANEL_MIN_HEIGHT = 0.12; | ||||||
|  |  | ||||||
| ThemeData APP_THEME = ThemeData( | ThemeData APP_THEME = ThemeData( | ||||||
|   primaryColor: PRIMARY_COLOR, |   primaryColor: PRIMARY_COLOR, | ||||||
|  |  | ||||||
| @@ -33,20 +38,43 @@ ThemeData APP_THEME = ThemeData( | |||||||
|   ), |   ), | ||||||
|  |  | ||||||
|  |  | ||||||
|   textButtonTheme: TextButtonThemeData( |   textButtonTheme: const TextButtonThemeData( | ||||||
|      |     style: ButtonStyle( | ||||||
|     style: TextButton.styleFrom( |       foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR), | ||||||
|       backgroundColor: PRIMARY_COLOR, |       side: WidgetStatePropertyAll( | ||||||
|       textStyle: TextStyle( |         BorderSide( | ||||||
|         color: Colors.red |           color: PRIMARY_COLOR, | ||||||
|       ) |           width: 1, | ||||||
|  |         ), | ||||||
|  |       ), | ||||||
|  |     ) | ||||||
|     ), |     ), | ||||||
|   ), |  | ||||||
|   buttonTheme: ButtonThemeData( |   elevatedButtonTheme: const ElevatedButtonThemeData( | ||||||
|     buttonColor: PRIMARY_COLOR, |     style: ButtonStyle( | ||||||
|     textTheme: ButtonTextTheme.primary, |       foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR), | ||||||
|  |     ) | ||||||
|   ), |   ), | ||||||
|  |  | ||||||
|  |   outlinedButtonTheme: const OutlinedButtonThemeData( | ||||||
|  |     style: ButtonStyle( | ||||||
|  |       foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR), | ||||||
|  |     ) | ||||||
|  |   ), | ||||||
|  |  | ||||||
|  |  | ||||||
|  |   cardTheme: const CardTheme( | ||||||
|  |     shadowColor: Colors.grey, | ||||||
|  |     elevation: 2, | ||||||
|  |     margin: EdgeInsets.all(10), | ||||||
|  |   ), | ||||||
|  |  | ||||||
|  |   sliderTheme: const SliderThemeData( | ||||||
|  |     trackHeight: 15, | ||||||
|  |     inactiveTrackColor: Colors.grey, | ||||||
|  |     thumbColor: PRIMARY_COLOR, | ||||||
|  |     activeTrackColor: GRADIENT_END | ||||||
|  |   ) | ||||||
| ); | ); | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -1,5 +1,6 @@ | |||||||
| import 'dart:developer'; | import 'dart:developer'; | ||||||
|  |  | ||||||
|  | import 'package:anyway/constants.dart'; | ||||||
| import 'package:anyway/structs/trip.dart'; | import 'package:anyway/structs/trip.dart'; | ||||||
| import 'package:auto_size_text/auto_size_text.dart'; | import 'package:auto_size_text/auto_size_text.dart'; | ||||||
|  |  | ||||||
| @@ -20,8 +21,12 @@ class Greeter extends StatefulWidget { | |||||||
| class _GreeterState extends State<Greeter> { | class _GreeterState extends State<Greeter> { | ||||||
|    |    | ||||||
|   Widget greeterBuilder (BuildContext context, Widget? child) { |   Widget greeterBuilder (BuildContext context, Widget? child) { | ||||||
|     ThemeData theme = Theme.of(context); |     final Shader textGradient = APP_GRADIENT.createShader(Rect.fromLTWH(0.0, 0.0, 200.0, 70.0)); | ||||||
|     TextStyle greeterStyle = TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24); |     TextStyle greeterStyle = TextStyle( | ||||||
|  |       foreground: Paint()..shader = textGradient, | ||||||
|  |       fontWeight: FontWeight.bold, | ||||||
|  |       fontSize: 26 | ||||||
|  |     ); | ||||||
|  |  | ||||||
|     Widget topGreeter; |     Widget topGreeter; | ||||||
|  |  | ||||||
| @@ -91,26 +96,10 @@ class _GreeterState extends State<Greeter> { | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     return Center( |     return Center( | ||||||
|       child: Column( |       child: topGreeter, | ||||||
|         children: [ |  | ||||||
|           // Padding(padding: EdgeInsets.only(top: 20)), |  | ||||||
|           topGreeter, |  | ||||||
|           Padding( |  | ||||||
|             padding: EdgeInsets.all(20), |  | ||||||
|             child: bottomGreeter |  | ||||||
|           ), |  | ||||||
|         ], |  | ||||||
|       ) |  | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Widget bottomGreeter = const Text( |  | ||||||
|     "Busy day ahead? Here is how to make the most of it!", |  | ||||||
|     style: TextStyle(color: Colors.black, fontSize: 18), |  | ||||||
|     textAlign: TextAlign.center, |  | ||||||
|   ); |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|   | |||||||
| @@ -16,7 +16,7 @@ List<Widget> landmarksList(Trip trip) { | |||||||
|  |  | ||||||
|   log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks"); |   log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks"); | ||||||
|  |  | ||||||
|   if (trip.landmarks.isEmpty || trip.landmarks.length <= 1 && trip.landmarks.first.type == start ) { |   if (trip.landmarks.isEmpty || trip.landmarks.length <= 1 && trip.landmarks.first.type == typeStart ) { | ||||||
|     children.add( |     children.add( | ||||||
|       const Text("No landmarks in this trip"), |       const Text("No landmarks in this trip"), | ||||||
|     ); |     ); | ||||||
|   | |||||||
| @@ -1,7 +1,7 @@ | |||||||
| import 'dart:collection'; | import 'dart:collection'; | ||||||
|  |  | ||||||
| import 'package:anyway/constants.dart'; | import 'package:anyway/constants.dart'; | ||||||
| import 'package:anyway/modules/themed_marker.dart'; | import 'package:anyway/modules/landmark_map_marker.dart'; | ||||||
| import 'package:flutter/material.dart'; | 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'; | ||||||
|   | |||||||
							
								
								
									
										82
									
								
								frontend/lib/modules/current_trip_panel.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								frontend/lib/modules/current_trip_panel.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | |||||||
|  | import 'package:anyway/constants.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
|  | import 'package:anyway/structs/trip.dart'; | ||||||
|  | import 'package:anyway/modules/current_trip_summary.dart'; | ||||||
|  | import 'package:anyway/modules/current_trip_save_button.dart'; | ||||||
|  | import 'package:anyway/modules/current_trip_landmarks_list.dart'; | ||||||
|  | import 'package:anyway/modules/current_trip_greeter.dart'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  | class CurrentTripPanel extends StatefulWidget { | ||||||
|  |   final ScrollController controller; | ||||||
|  |   final Trip trip; | ||||||
|  |  | ||||||
|  |   const CurrentTripPanel({ | ||||||
|  |     super.key, | ||||||
|  |     required this.controller, | ||||||
|  |     required this.trip, | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   State<CurrentTripPanel> createState() => _CurrentTripPanelState(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _CurrentTripPanelState extends State<CurrentTripPanel> { | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return ListenableBuilder( | ||||||
|  |       listenable: widget.trip, | ||||||
|  |       builder: (context, child) { | ||||||
|  |         if (widget.trip.uuid != 'pending' && widget.trip.uuid != 'error') { | ||||||
|  |           return ListView( | ||||||
|  |             controller: widget.controller, | ||||||
|  |             padding: const EdgeInsets.only(bottom: 30, left: 5, right: 5), | ||||||
|  |             children: [ | ||||||
|  |               SizedBox( | ||||||
|  |                 // reuse the exact same height as the panel has when collapsed | ||||||
|  |                 // this way the greeter will be centered when the panel is collapsed | ||||||
|  |                 height: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT - 20, | ||||||
|  |                 child: Greeter(trip: widget.trip), | ||||||
|  |               ), | ||||||
|  |  | ||||||
|  |               const Padding(padding: EdgeInsets.only(top: 10)), | ||||||
|  |  | ||||||
|  |               // CurrentTripSummary(trip: widget.trip), | ||||||
|  |  | ||||||
|  |               // const Divider(), | ||||||
|  |  | ||||||
|  |               ...landmarksList(widget.trip), | ||||||
|  |  | ||||||
|  |               const Padding(padding: EdgeInsets.only(top: 10)), | ||||||
|  |  | ||||||
|  |               Center(child: saveButton(widget.trip)), | ||||||
|  |             ], | ||||||
|  |           ); | ||||||
|  |         } else if(widget.trip.uuid == 'pending') { | ||||||
|  |           return SizedBox( | ||||||
|  |             // reuse the exact same height as the panel has when collapsed | ||||||
|  |             // this way the greeter will be centered when the panel is collapsed | ||||||
|  |             height: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT - 20, | ||||||
|  |             child: Greeter(trip: widget.trip) | ||||||
|  |           ); | ||||||
|  |         } else { | ||||||
|  |           return Row( | ||||||
|  |             mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |             children: [ | ||||||
|  |               const Icon( | ||||||
|  |                 Icons.error_outline, | ||||||
|  |                 color: Colors.red, | ||||||
|  |                 size: 50, | ||||||
|  |               ), | ||||||
|  |               Padding( | ||||||
|  |                 padding: const EdgeInsets.only(left: 10), | ||||||
|  |                 child: Text('Error: ${widget.trip.errorDescription}'), | ||||||
|  |               ), | ||||||
|  |             ], | ||||||
|  |           ); | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     ); | ||||||
|  |   } | ||||||
|  | }   | ||||||
| @@ -1,4 +1,5 @@ | |||||||
|  |  | ||||||
|  | import 'package:anyway/main.dart'; | ||||||
| import 'package:anyway/structs/trip.dart'; | import 'package:anyway/structs/trip.dart'; | ||||||
| import 'package:auto_size_text/auto_size_text.dart'; | import 'package:auto_size_text/auto_size_text.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| @@ -8,6 +9,13 @@ Widget saveButton(Trip trip) => ElevatedButton( | |||||||
|   onPressed: () async { |   onPressed: () async { | ||||||
|     SharedPreferences prefs = await SharedPreferences.getInstance(); |     SharedPreferences prefs = await SharedPreferences.getInstance(); | ||||||
|     trip.toPrefs(prefs); |     trip.toPrefs(prefs); | ||||||
|  |     rootScaffoldMessengerKey.currentState!.showSnackBar( | ||||||
|  |       SnackBar( | ||||||
|  |         content: Text('Trip saved'), | ||||||
|  |         duration: Duration(seconds: 2), | ||||||
|  |         dismissDirection: DismissDirection.horizontal | ||||||
|  |       ) | ||||||
|  |     ); | ||||||
|   }, |   }, | ||||||
|   child: SizedBox( |   child: SizedBox( | ||||||
|     width: 100, |     width: 100, | ||||||
|   | |||||||
							
								
								
									
										31
									
								
								frontend/lib/modules/current_trip_summary.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								frontend/lib/modules/current_trip_summary.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,31 @@ | |||||||
|  | import 'package:anyway/structs/trip.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
|  | class CurrentTripSummary extends StatefulWidget { | ||||||
|  |   final Trip trip; | ||||||
|  |   const CurrentTripSummary({ | ||||||
|  |     super.key, | ||||||
|  |     required this.trip, | ||||||
|  |     }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   State<CurrentTripSummary> createState() => _CurrentTripSummaryState(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _CurrentTripSummaryState extends State<CurrentTripSummary> { | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) { | ||||||
|  |     return Column( | ||||||
|  |       children: [ | ||||||
|  |         Text('Summary'), | ||||||
|  |         // Text('Start: ${widget.trip.start}'), | ||||||
|  |         // Text('End: ${widget.trip.end}'), | ||||||
|  |         Text('Total duration: ${widget.trip.totalTime}'), | ||||||
|  |         Text('Total distance: ${widget.trip.totalTime}'), | ||||||
|  |         // Text('Fuel: ${widget.trip.fuel}'), | ||||||
|  |         // Text('Cost: ${widget.trip.cost}'), | ||||||
|  |       ], | ||||||
|  |     ); | ||||||
|  |      | ||||||
|  |   } | ||||||
|  | } | ||||||
| @@ -36,7 +36,7 @@ class _LandmarkCardState extends State<LandmarkCard> { | |||||||
|               width: 160, |               width: 160, | ||||||
|               child: CachedNetworkImage( |               child: CachedNetworkImage( | ||||||
|                 imageUrl: widget.landmark.imageURL ?? '', |                 imageUrl: widget.landmark.imageURL ?? '', | ||||||
|                 placeholder: (context, url) => CircularProgressIndicator(), |                 placeholder: (context, url) => Center(child: CircularProgressIndicator()), | ||||||
|                 errorWidget: (context, error, stackTrace) => Icon(Icons.question_mark_outlined), |                 errorWidget: (context, error, stackTrace) => Icon(Icons.question_mark_outlined), | ||||||
|                 // TODO: make this a switch statement to load a placeholder if null |                 // TODO: make this a switch statement to load a placeholder if null | ||||||
|                 // cover the whole container meaning the image will be cropped |                 // cover the whole container meaning the image will be cropped | ||||||
| @@ -84,21 +84,18 @@ class _LandmarkCardState extends State<LandmarkCard> { | |||||||
|                         // show the type, the website, and the wikipedia link as buttons/labels in a row |                         // show the type, the website, and the wikipedia link as buttons/labels in a row | ||||||
|                         children: [ |                         children: [ | ||||||
|                           TextButton.icon( |                           TextButton.icon( | ||||||
|                             style: theme.iconButtonTheme.style, |  | ||||||
|                             onPressed: () {}, |                             onPressed: () {}, | ||||||
|                             icon: widget.landmark.type.icon, |                             icon: widget.landmark.type.icon, | ||||||
|                             label: Text(widget.landmark.type.name), |                             label: Text(widget.landmark.type.name), | ||||||
|                           ), |                           ), | ||||||
|                           if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0) |                           if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0) | ||||||
|                             TextButton.icon( |                             TextButton.icon( | ||||||
|                               style: theme.iconButtonTheme.style, |  | ||||||
|                               onPressed: () {}, |                               onPressed: () {}, | ||||||
|                               icon: Icon(Icons.hourglass_bottom), |                               icon: Icon(Icons.hourglass_bottom), | ||||||
|                               label: Text('${widget.landmark.duration!.inMinutes} minutes'), |                               label: Text('${widget.landmark.duration!.inMinutes} minutes'), | ||||||
|                             ), |                             ), | ||||||
|                           if (widget.landmark.websiteURL != null) |                           if (widget.landmark.websiteURL != null) | ||||||
|                             TextButton.icon( |                             TextButton.icon( | ||||||
|                               style: theme.iconButtonTheme.style, |  | ||||||
|                               onPressed: () async { |                               onPressed: () async { | ||||||
|                                 // open a browser with the website link |                                 // open a browser with the website link | ||||||
|                                 await launchUrl(Uri.parse(widget.landmark.websiteURL!)); |                                 await launchUrl(Uri.parse(widget.landmark.websiteURL!)); | ||||||
| @@ -108,7 +105,6 @@ class _LandmarkCardState extends State<LandmarkCard> { | |||||||
|                             ), |                             ), | ||||||
|                           if (widget.landmark.wikipediaURL != null) |                           if (widget.landmark.wikipediaURL != null) | ||||||
|                             TextButton.icon( |                             TextButton.icon( | ||||||
|                               style: theme.iconButtonTheme.style, |  | ||||||
|                               onPressed: () async { |                               onPressed: () async { | ||||||
|                                 // open a browser with the wikipedia link |                                 // open a browser with the wikipedia link | ||||||
|                                 await launchUrl(Uri.parse(widget.landmark.wikipediaURL!)); |                                 await launchUrl(Uri.parse(widget.landmark.wikipediaURL!)); | ||||||
|   | |||||||
| @@ -17,21 +17,9 @@ class ThemedMarker extends StatelessWidget { | |||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     // This returns an outlined circle, with an icon corresponding to the landmark type |     // This returns an outlined circle, with an icon corresponding to the landmark type | ||||||
|     // As a small dot, the number of the landmark is displayed in the top right |     // As a small dot, the number of the landmark is displayed in the top right | ||||||
|     Icon icon; |  | ||||||
|     if (landmark.type == sightseeing) { |  | ||||||
|       icon = Icon(Icons.church, color: Colors.black, size: 50); |  | ||||||
|     } else if (landmark.type == nature) { |  | ||||||
|       icon = Icon(Icons.park, color: Colors.black, size: 50); |  | ||||||
|     } else if (landmark.type == shopping) { |  | ||||||
|       icon = Icon(Icons.shopping_cart, color: Colors.black, size: 50); |  | ||||||
|     } else if (landmark.type == start || landmark.type == finish) { |  | ||||||
|       icon = Icon(Icons.flag, color: Colors.black, size: 50); |  | ||||||
|     } else { |  | ||||||
|       icon = Icon(Icons.location_on, color: Colors.black, size: 50); |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     Widget? positionIndicator; |     Widget? positionIndicator; | ||||||
|     if (landmark.type != start && landmark.type != finish) { |     if (landmark.type != typeStart && landmark.type != typeFinish) { | ||||||
|       positionIndicator = Positioned( |       positionIndicator = Positioned( | ||||||
|         top: 0, |         top: 0, | ||||||
|         right: 0, |         right: 0, | ||||||
| @@ -56,8 +44,10 @@ class ThemedMarker extends StatelessWidget { | |||||||
|               shape: BoxShape.circle, |               shape: BoxShape.circle, | ||||||
|               border: Border.all(color: Colors.black, width: 5), |               border: Border.all(color: Colors.black, width: 5), | ||||||
|             ), |             ), | ||||||
|             padding: EdgeInsets.all(5), |             width: 70, | ||||||
|             child: icon |             height: 70, | ||||||
|  |             padding: const EdgeInsets.all(5), | ||||||
|  |             child: Icon(landmark.type.icon.icon, size: 50), | ||||||
|           ), |           ), | ||||||
|           if (positionIndicator != null) positionIndicator, |           if (positionIndicator != null) positionIndicator, | ||||||
|         ], |         ], | ||||||
| @@ -42,7 +42,7 @@ class _NewTripLocationSearchState extends State<NewTripLocationSearch> { | |||||||
|           uuid: 'pending', |           uuid: 'pending', | ||||||
|           name: query, |           name: query, | ||||||
|           location: [location.latitude, location.longitude], |           location: [location.latitude, location.longitude], | ||||||
|           type: start |           type: typeStart | ||||||
|         ) |         ) | ||||||
|       ); |       ); | ||||||
|     } |     } | ||||||
| @@ -65,9 +65,8 @@ class _NewTripLocationSearchState extends State<NewTripLocationSearch> { | |||||||
|  |  | ||||||
|  |  | ||||||
|   late Widget useCurrentLocationButton = ElevatedButton( |   late Widget useCurrentLocationButton = ElevatedButton( | ||||||
|     onPressed: () { |     onPressed: () async { | ||||||
|       // setTripLocation(location); |        | ||||||
|       // TODO: get current location |  | ||||||
|     }, |     }, | ||||||
|     child: Text('Use current location'), |     child: Text('Use current location'), | ||||||
|   ); |   ); | ||||||
|   | |||||||
| @@ -2,7 +2,7 @@ | |||||||
| import 'dart:developer'; | import 'dart:developer'; | ||||||
|  |  | ||||||
| import 'package:anyway/constants.dart'; | import 'package:anyway/constants.dart'; | ||||||
| import 'package:anyway/modules/themed_marker.dart'; | import 'package:anyway/modules/landmark_map_marker.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:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| @@ -37,7 +37,7 @@ class _NewTripMapState extends State<NewTripMap> { | |||||||
|         uuid: 'pending', |         uuid: 'pending', | ||||||
|         name: 'start', |         name: 'start', | ||||||
|         location: [location.latitude, location.longitude], |         location: [location.latitude, location.longitude], | ||||||
|         type: start |         type: typeStart | ||||||
|       ) |       ) | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -1,11 +1,10 @@ | |||||||
| import 'package:anyway/modules/current_trip_save_button.dart'; | import 'package:anyway/constants.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:sliding_up_panel/sliding_up_panel.dart'; | import 'package:sliding_up_panel/sliding_up_panel.dart'; | ||||||
|  |  | ||||||
| import 'package:anyway/structs/trip.dart'; | import 'package:anyway/structs/trip.dart'; | ||||||
| import 'package:anyway/modules/current_trip_landmarks_list.dart'; |  | ||||||
| import 'package:anyway/modules/current_trip_greeter.dart'; |  | ||||||
| import 'package:anyway/modules/current_trip_map.dart'; | import 'package:anyway/modules/current_trip_map.dart'; | ||||||
|  | import 'package:anyway/modules/current_trip_panel.dart'; | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -27,15 +26,20 @@ class _TripPageState extends State<TripPage> { | |||||||
|   @override |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     return SlidingUpPanel( |     return SlidingUpPanel( | ||||||
|         panelBuilder: (sc) => _panelFull(sc), |         // use panelBuilder instead of panel so that we can reuse the scrollcontroller for the listview | ||||||
|         // collapsed: _floatingCollapsed(), |         panelBuilder: (scrollcontroller) => CurrentTripPanel(controller: scrollcontroller, trip: widget.trip), | ||||||
|  |         // using collapsed and panelBuilder seems to show both at the same time, so we include the greeter in the panelBuilder | ||||||
|  |         // collapsed: Greeter(trip: widget.trip), | ||||||
|         body: CurrentTripMap(trip: widget.trip), |         body: CurrentTripMap(trip: widget.trip), | ||||||
|         // renderPanelSheet: false, |         minHeight: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT, | ||||||
|         // backdropEnabled: true, |         maxHeight: MediaQuery.of(context).size.height * TRIP_PANEL_MAX_HEIGHT, | ||||||
|         maxHeight: MediaQuery.of(context).size.height * 0.8, |         // padding in this context is annoying: it offsets the notion of vertical alignment. | ||||||
|         padding: EdgeInsets.only(left: 10, right: 10, top: 25, bottom: 10), |         // children that want to be centered vertically need to have their size adjusted by 2x the padding | ||||||
|         // panelSnapping: false, |         padding: const EdgeInsets.only(top: 10), | ||||||
|         borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), |         // Panel snapping should not be disabled because it significantly improves the user experience | ||||||
|  |         // panelSnapping: false | ||||||
|  |         borderRadius: const BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), | ||||||
|  |         parallaxEnabled: true, | ||||||
|         boxShadow: const [ |         boxShadow: const [ | ||||||
|           BoxShadow( |           BoxShadow( | ||||||
|             blurRadius: 20.0, |             blurRadius: 20.0, | ||||||
| @@ -44,41 +48,4 @@ class _TripPageState extends State<TripPage> { | |||||||
|         ], |         ], | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|    |  | ||||||
|   Widget _panelFull(ScrollController sc) { |  | ||||||
|     return ListenableBuilder( |  | ||||||
|       listenable: widget.trip, |  | ||||||
|       builder: (context, child) { |  | ||||||
|         if (widget.trip.uuid != 'pending' && widget.trip.uuid != 'error') { |  | ||||||
|           return ListView( |  | ||||||
|             controller: sc, |  | ||||||
|             padding: EdgeInsets.only(bottom: 35), |  | ||||||
|             children: [ |  | ||||||
|               Greeter(trip: widget.trip), |  | ||||||
|               ...landmarksList(widget.trip), |  | ||||||
|               Padding(padding: EdgeInsets.only(top: 10)), |  | ||||||
|               Center(child: saveButton(widget.trip)), |  | ||||||
|             ], |  | ||||||
|           ); |  | ||||||
|         } else if(widget.trip.uuid == 'pending') { |  | ||||||
|           return Greeter(trip: widget.trip); |  | ||||||
|         } else { |  | ||||||
|           return Column( |  | ||||||
|             children: [ |  | ||||||
|               const Icon( |  | ||||||
|                 Icons.error_outline, |  | ||||||
|                 color: Colors.red, |  | ||||||
|                 size: 60, |  | ||||||
|               ), |  | ||||||
|               Padding( |  | ||||||
|                 padding: const EdgeInsets.only(top: 16), |  | ||||||
|                 child: Text('Error: ${widget.trip.errorDescription}'), |  | ||||||
|               ), |  | ||||||
|             ], |  | ||||||
|           ); |  | ||||||
|         } |  | ||||||
|       } |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } | } | ||||||
|   | |||||||
| @@ -28,25 +28,26 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> { | |||||||
|           //     child: Icon(Icons.person, size: 100), |           //     child: Icon(Icons.person, size: 100), | ||||||
|           //   ) |           //   ) | ||||||
|           // ), |           // ), | ||||||
|  |           Padding(padding: EdgeInsets.only(top: 30)), | ||||||
|           Center( |           Center( | ||||||
|             child: FutureBuilder( |             child: FutureBuilder( | ||||||
|               future: widget.trip.cityName, |               future: widget.trip.cityName, | ||||||
|               builder: (context, snapshot) => Text( |               builder: (context, snapshot) => Text( | ||||||
|                 'New trip to ${snapshot.hasData ? snapshot.data! : "..."}', |                 'Your trip to ${snapshot.hasData ? snapshot.data! : "..."}', | ||||||
|                 style: TextStyle(fontSize: 24) |                 style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold) | ||||||
|               ) |               ) | ||||||
|             ) |             ) | ||||||
|           ), |           ), | ||||||
|  |  | ||||||
|           Divider(indent: 25, endIndent: 25, height: 50), |  | ||||||
|  |  | ||||||
|           Center( |           Center( | ||||||
|             child: Padding( |             child: Padding( | ||||||
|             padding: EdgeInsets.only(left: 10, right: 10, top: 0, bottom: 10), |             padding: EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 0), | ||||||
|               child: Text('Tell us about your ideal trip.', style: TextStyle(fontSize: 18)) |               child: Text('Tell us about your ideal trip.', style: TextStyle(fontSize: 18)) | ||||||
|             ), |             ), | ||||||
|           ), |           ), | ||||||
|  |  | ||||||
|  |           Divider(indent: 25, endIndent: 25, height: 50), | ||||||
|  |  | ||||||
|           durationPicker(preferences.maxTime), |           durationPicker(preferences.maxTime), | ||||||
|  |  | ||||||
|           preferenceSliders([preferences.sightseeing, preferences.shopping, preferences.nature]), |           preferenceSliders([preferences.sightseeing, preferences.shopping, preferences.nature]), | ||||||
| @@ -63,7 +64,7 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> { | |||||||
|       shadowColor: Colors.grey, |       shadowColor: Colors.grey, | ||||||
|       child: ListTile( |       child: ListTile( | ||||||
|         leading: Icon(Icons.timer), |         leading: Icon(Icons.timer), | ||||||
|         title: Text('How long should the trip be?'), |         title: Text(preferences.maxTime.description), | ||||||
|         subtitle: CupertinoTimerPicker( |         subtitle: CupertinoTimerPicker( | ||||||
|           mode: CupertinoTimerPickerMode.hm, |           mode: CupertinoTimerPickerMode.hm, | ||||||
|           initialTimerDuration: Duration(minutes: 90), |           initialTimerDuration: Duration(minutes: 90), | ||||||
| @@ -84,8 +85,6 @@ 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), | ||||||
|   | |||||||
| @@ -174,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, color: Colors.white), |             icon: Icon(Icons.info), | ||||||
|             label: Text(PRIVACY_URL, style: TextStyle(color: Colors.white)), |             label: Text(PRIVACY_URL), | ||||||
|             onPressed: () async{ |             onPressed: () async{ | ||||||
|               await launchUrl(Uri.parse(PRIVACY_URL)); |               await launchUrl(Uri.parse(PRIVACY_URL)); | ||||||
|             } |             } | ||||||
|   | |||||||
| @@ -4,13 +4,13 @@ import 'dart:convert'; | |||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
| import 'package:shared_preferences/shared_preferences.dart'; | import 'package:shared_preferences/shared_preferences.dart'; | ||||||
|  |  | ||||||
| LandmarkType sightseeing = LandmarkType(name: 'sightseeing'); | LandmarkType typeSightseeing = LandmarkType(name: 'sightseeing'); | ||||||
| LandmarkType nature = LandmarkType(name: 'nature'); | LandmarkType typeNature = LandmarkType(name: 'nature'); | ||||||
| LandmarkType shopping = LandmarkType(name: 'shopping'); | LandmarkType typeShopping = LandmarkType(name: 'shopping'); | ||||||
| // LandmarkType museum = LandmarkType(name: 'Museum'); | // LandmarkType museum = LandmarkType(name: 'Museum'); | ||||||
| // LandmarkType restaurant = LandmarkType(name: 'Restaurant'); | // LandmarkType restaurant = LandmarkType(name: 'Restaurant'); | ||||||
| LandmarkType start = LandmarkType(name: 'start'); | LandmarkType typeStart = LandmarkType(name: 'start'); | ||||||
| LandmarkType finish = LandmarkType(name: 'finish'); | LandmarkType typeFinish = LandmarkType(name: 'finish'); | ||||||
|  |  | ||||||
|  |  | ||||||
| final class Landmark extends LinkedListEntry<Landmark>{ | final class Landmark extends LinkedListEntry<Landmark>{ | ||||||
| @@ -130,22 +130,22 @@ class LandmarkType { | |||||||
|   LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) { |   LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) { | ||||||
|     switch (name) { |     switch (name) { | ||||||
|       case 'sightseeing': |       case 'sightseeing': | ||||||
|         icon = Icon(Icons.church); |         icon = const Icon(Icons.church); | ||||||
|         break; |         break; | ||||||
|       case 'nature': |       case 'nature': | ||||||
|         icon = Icon(Icons.eco); |         icon = const Icon(Icons.eco); | ||||||
|         break; |         break; | ||||||
|       case 'shopping': |       case 'shopping': | ||||||
|         icon = Icon(Icons.shopping_cart); |         icon = const Icon(Icons.shopping_cart); | ||||||
|         break; |         break; | ||||||
|       case 'start': |       case 'start': | ||||||
|         icon = Icon(Icons.play_arrow); |         icon = const Icon(Icons.play_arrow); | ||||||
|         break; |         break; | ||||||
|       case 'finish': |       case 'finish': | ||||||
|         icon = Icon(Icons.flag); |         icon = const Icon(Icons.flag); | ||||||
|         break; |         break; | ||||||
|       default: |       default: | ||||||
|         icon = Icon(Icons.location_on); |         icon = const Icon(Icons.location_on); | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -1,3 +1,4 @@ | |||||||
|  | import 'package:anyway/structs/landmark.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
|  |  | ||||||
| @@ -28,27 +29,27 @@ class UserPreferences { | |||||||
|     slug: "sightseeing", |     slug: "sightseeing", | ||||||
|     description: "How much do you like sightseeing?", |     description: "How much do you like sightseeing?", | ||||||
|     value: 0, |     value: 0, | ||||||
|     icon: Icon(Icons.church), |     icon: typeSightseeing.icon, | ||||||
|   ); |   ); | ||||||
|   SinglePreference shopping = SinglePreference( |   SinglePreference shopping = SinglePreference( | ||||||
|     name: "Shopping", |     name: "Shopping", | ||||||
|     slug: "shopping", |     slug: "shopping", | ||||||
|     description: "How much do you like shopping?", |     description: "How much do you like shopping?", | ||||||
|     value: 0, |     value: 0, | ||||||
|     icon: Icon(Icons.shopping_bag), |     icon: typeShopping.icon, | ||||||
|   ); |   ); | ||||||
|   SinglePreference nature = SinglePreference( |   SinglePreference nature = SinglePreference( | ||||||
|     name: "Nature", |     name: "Nature", | ||||||
|     slug: "nature", |     slug: "nature", | ||||||
|     description: "How much do you like nature?", |     description: "How much do you like nature?", | ||||||
|     value: 0, |     value: 0, | ||||||
|     icon: Icon(Icons.landscape), |     icon: typeNature.icon, | ||||||
|   ); |   ); | ||||||
|  |  | ||||||
|   SinglePreference maxTime = SinglePreference( |   SinglePreference maxTime = SinglePreference( | ||||||
|     name: "Trip duration", |     name: "Trip duration", | ||||||
|     slug: "duration", |     slug: "duration", | ||||||
|     description: "How long do you want your trip to be?", |     description: "How long should your trip be?", | ||||||
|     value: 30, |     value: 30, | ||||||
|     minVal: 30, |     minVal: 30, | ||||||
|     maxVal: 720, |     maxVal: 720, | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user