Compare commits
	
		
			9 Commits
		
	
	
		
			v0.0.24
			...
			e5251c05a9
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| e5251c05a9 | |||
| 66fa55e8c3 | |||
| f4729a2de7 | |||
| 40edd923c3 | |||
| 6ad749eeed | |||
| c20ebf3d63 | |||
| 6facde6e0b | |||
| 55b0a1b793 | |||
| 39df97f4d1 | 
| @@ -9,9 +9,9 @@ name = "pypi" | |||||||
| numpy = "*" | numpy = "*" | ||||||
| fastapi = "*" | fastapi = "*" | ||||||
| pydantic = "*" | pydantic = "*" | ||||||
| geopy = "*" |  | ||||||
| shapely = "*" | shapely = "*" | ||||||
| scipy = "*" | scipy = "*" | ||||||
| osmpythontools = "*" | osmpythontools = "*" | ||||||
| pywikibot = "*" | pywikibot = "*" | ||||||
| pymemcache = "*" | pymemcache = "*" | ||||||
|  | fastapi-cli = "*" | ||||||
|   | |||||||
							
								
								
									
										2208
									
								
								backend/Pipfile.lock
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										2208
									
								
								backend/Pipfile.lock
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							 Submodule backend/deployment updated: 8927f278f3...97f4a5e175
									
								
							| @@ -16,7 +16,7 @@ OSM_CACHE_DIR = Path(cache_dir_string) | |||||||
|  |  | ||||||
| import logging | import logging | ||||||
| # if we are in a debug session, set verbose and rich logging | # if we are in a debug session, set verbose and rich logging | ||||||
| if os.getenv('DEBUG', False): | if os.getenv('DEBUG', "false") == "true": | ||||||
|     from rich.logging import RichHandler |     from rich.logging import RichHandler | ||||||
|     logging.basicConfig( |     logging.basicConfig( | ||||||
|         level=logging.DEBUG, |         level=logging.DEBUG, | ||||||
|   | |||||||
| @@ -1,3 +1,6 @@ | |||||||
|  | # Tags were picked mostly arbitrarily, based on the OSM wiki and the OSM tags page. | ||||||
|  | # See https://taginfo.openstreetmap.org for more inspiration. | ||||||
|  |  | ||||||
| nature: | nature: | ||||||
|   leisure: park |   leisure: park | ||||||
|   geological: '' |   geological: '' | ||||||
| @@ -11,7 +14,24 @@ nature: | |||||||
|     - alpine_hut |     - alpine_hut | ||||||
|     - viewpoint |     - viewpoint | ||||||
|     - zoo |     - zoo | ||||||
|   waterway: waterfall |     - resort | ||||||
|  |     - picnic_site | ||||||
|  |   water: | ||||||
|  |     - pond | ||||||
|  |     - lake | ||||||
|  |     - river | ||||||
|  |     - basin | ||||||
|  |     - stream | ||||||
|  |     - lagoon | ||||||
|  |     - rapids | ||||||
|  |   waterway: | ||||||
|  |     - waterfall | ||||||
|  |     - river | ||||||
|  |     - canal | ||||||
|  |     - dam | ||||||
|  |     - dock | ||||||
|  |     - boatyard | ||||||
|  |  | ||||||
|  |  | ||||||
| shopping: | shopping: | ||||||
|   shop: |   shop: | ||||||
| @@ -23,10 +43,48 @@ sightseeing: | |||||||
|     - museum |     - museum | ||||||
|     - attraction |     - attraction | ||||||
|     - gallery |     - gallery | ||||||
|  |     - artwork | ||||||
|  |     - aquarium | ||||||
|  |  | ||||||
|   historic: '' |   historic: '' | ||||||
|   amenity: |   amenity: | ||||||
|     - planetarium |     - planetarium | ||||||
|     - place_of_worship |     - place_of_worship | ||||||
|     - fountain |     - fountain | ||||||
|  |     - townhall | ||||||
|   water: |   water: | ||||||
|     - reflecting_pool |     - reflecting_pool | ||||||
|  |   bridge: | ||||||
|  |     - aqueduct | ||||||
|  |     - viaduct | ||||||
|  |     - boardwalk | ||||||
|  |     - cantilever | ||||||
|  |     - abandoned | ||||||
|  |   building: | ||||||
|  |     - church | ||||||
|  |     - chapel | ||||||
|  |     - mosque | ||||||
|  |     - synagogue | ||||||
|  |     - ruins | ||||||
|  |     - temple | ||||||
|  |     - government | ||||||
|  |     - cathedral | ||||||
|  |     - castle | ||||||
|  |     - museum | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | # to be used later on | ||||||
|  | restauration: | ||||||
|  |   shop: | ||||||
|  |     - coffee | ||||||
|  |     - bakery | ||||||
|  |     - restaurant | ||||||
|  |     - pastry | ||||||
|  |   amenity: | ||||||
|  |     - restaurant | ||||||
|  |     - cafe | ||||||
|  |     - ice_cream | ||||||
|  |     - food_court | ||||||
|  |     - biergarten | ||||||
|   | |||||||
| @@ -21,8 +21,8 @@ if constants.MEMCACHED_HOST_PATH is None: | |||||||
| else: | else: | ||||||
|     client = Client( |     client = Client( | ||||||
|         constants.MEMCACHED_HOST_PATH, |         constants.MEMCACHED_HOST_PATH, | ||||||
|         timeout=1, |         timeout = 1, | ||||||
|         allow_unicode_keys=True, |         allow_unicode_keys = True, | ||||||
|         encoding='utf-8', |         encoding = 'utf-8', | ||||||
|         serde=serde.pickle_serde |         serde = serde.pickle_serde | ||||||
|     ) |     ) | ||||||
|   | |||||||
| @@ -22,7 +22,8 @@ class Trip(BaseModel): | |||||||
|  |  | ||||||
|         # Store the trip in the cache |         # Store the trip in the cache | ||||||
|         cache_client.set(f"trip_{trip.uuid}", trip) |         cache_client.set(f"trip_{trip.uuid}", trip) | ||||||
|         cache_client.set_many({f"landmark_{landmark.uuid}": landmark for landmark in landmarks}, expire=3600) |         # make sure to await the result (noreply=False). Otherwise the cache might not be inplace when the trip is actually requested | ||||||
|  |         cache_client.set_many({f"landmark_{landmark.uuid}": landmark for landmark in landmarks}, expire=3600, noreply=False) | ||||||
|         # is equivalent to: |         # is equivalent to: | ||||||
|         # for landmark in landmarks: |         # for landmark in landmarks: | ||||||
|         #     cache_client.set(f"landmark_{landmark.uuid}", landmark, expire=3600) |         #     cache_client.set(f"landmark_{landmark.uuid}", landmark, expire=3600) | ||||||
|   | |||||||
| @@ -1,5 +1,5 @@ | |||||||
| import yaml | import yaml | ||||||
| from geopy.distance import geodesic | from math import sin, cos, sqrt, atan2, radians | ||||||
|  |  | ||||||
| import constants | import constants | ||||||
|  |  | ||||||
| @@ -8,6 +8,7 @@ with constants.OPTIMIZER_PARAMETERS_PATH.open('r') as f: | |||||||
|     DETOUR_FACTOR = parameters['detour_factor'] |     DETOUR_FACTOR = parameters['detour_factor'] | ||||||
|     AVERAGE_WALKING_SPEED = parameters['average_walking_speed'] |     AVERAGE_WALKING_SPEED = parameters['average_walking_speed'] | ||||||
|  |  | ||||||
|  | EARTH_RADIUS_KM = 6373 | ||||||
|  |  | ||||||
| def get_time(p1: tuple[float, float], p2: tuple[float, float]) -> int: | def get_time(p1: tuple[float, float], p2: tuple[float, float]) -> int: | ||||||
|     """ |     """ | ||||||
| @@ -22,16 +23,28 @@ def get_time(p1: tuple[float, float], p2: tuple[float, float]) -> int: | |||||||
|     """ |     """ | ||||||
|  |  | ||||||
|  |  | ||||||
|     # Compute the straight-line distance in km |     if p1 == p2: | ||||||
|     if p1 == p2 : |  | ||||||
|         return 0 |         return 0 | ||||||
|     else: |     else: | ||||||
|         dist = geodesic(p1, p2).kilometers |         # Compute the distance in km along the surface of the Earth | ||||||
|  |         # (assume spherical Earth) | ||||||
|  |         # this is the haversine formula, stolen from stackoverflow | ||||||
|  |         # in order to not use any external libraries | ||||||
|  |         lat1, lon1 = radians(p1[0]), radians(p1[1]) | ||||||
|  |         lat2, lon2 = radians(p2[0]), radians(p2[1]) | ||||||
|  |  | ||||||
|     # Consider the detour factor for average cityto deterline walking distance (in km) |         dlon = lon2 - lon1 | ||||||
|     walk_dist = dist*DETOUR_FACTOR |         dlat = lat2 - lat1 | ||||||
|  |  | ||||||
|  |         a = sin(dlat / 2)**2 + cos(lat1) * cos(lat2) * sin(dlon / 2)**2 | ||||||
|  |         c = 2 * atan2(sqrt(a), sqrt(1 - a)) | ||||||
|  |  | ||||||
|  |         distance = EARTH_RADIUS_KM * c | ||||||
|  |  | ||||||
|  |     # Consider the detour factor for average an average city | ||||||
|  |     walk_distance = distance * DETOUR_FACTOR | ||||||
|  |  | ||||||
|     # Time to walk this distance (in minutes) |     # Time to walk this distance (in minutes) | ||||||
|     walk_time = walk_dist/AVERAGE_WALKING_SPEED*60 |     walk_time = walk_distance / AVERAGE_WALKING_SPEED * 60 | ||||||
|  |  | ||||||
|     return round(walk_time) |     return round(walk_time) | ||||||
|   | |||||||
| @@ -10,7 +10,8 @@ from structs.landmark import Landmark | |||||||
| from .take_most_important import take_most_important | from .take_most_important import take_most_important | ||||||
| import constants | import constants | ||||||
|  |  | ||||||
|  | # silence the overpass logger | ||||||
|  | logging.getLogger('OSMPythonTools').setLevel(level=logging.CRITICAL) | ||||||
|  |  | ||||||
|  |  | ||||||
| class LandmarkManager: | class LandmarkManager: | ||||||
| @@ -206,11 +207,15 @@ class LandmarkManager: | |||||||
|             query = overpassQueryBuilder( |             query = overpassQueryBuilder( | ||||||
|                 bbox = bbox, |                 bbox = bbox, | ||||||
|                 elementType = ['way', 'relation'], |                 elementType = ['way', 'relation'], | ||||||
|  |                 # selector can in principle be a list already, | ||||||
|  |                 # but it generates the intersection of the queries | ||||||
|  |                 # we want the union | ||||||
|                 selector = sel, |                 selector = sel, | ||||||
|                 # conditions = [], |                 conditions = ['count_tags()>5'], | ||||||
|                 includeCenter = True, |                 includeCenter = True, | ||||||
|                 out = 'body' |                 out = 'body' | ||||||
|                 ) |                 ) | ||||||
|  |             self.logger.debug(f"Query: {query}") | ||||||
|  |  | ||||||
|             try: |             try: | ||||||
|                 result = self.overpass.query(query) |                 result = self.overpass.query(query) | ||||||
| @@ -336,7 +341,7 @@ def dict_to_selector_list(d: dict) -> list: | |||||||
|     for key, value in d.items(): |     for key, value in d.items(): | ||||||
|         if type(value) == list: |         if type(value) == list: | ||||||
|             val = '|'.join(value) |             val = '|'.join(value) | ||||||
|             return_list.append(f'{key}~"{val}"') |             return_list.append(f'{key}~"^({val})$"') | ||||||
|         elif type(value) == str and len(value) == 0: |         elif type(value) == str and len(value) == 0: | ||||||
|             return_list.append(f'{key}') |             return_list.append(f'{key}') | ||||||
|         else: |         else: | ||||||
|   | |||||||
| @@ -3,7 +3,6 @@ import numpy as np | |||||||
|  |  | ||||||
| from scipy.optimize import linprog | from scipy.optimize import linprog | ||||||
| from collections import defaultdict, deque | from collections import defaultdict, deque | ||||||
| from geopy.distance import geodesic |  | ||||||
|  |  | ||||||
| from structs.landmark import Landmark | from structs.landmark import Landmark | ||||||
| from .get_time_separation import get_time | from .get_time_separation import get_time | ||||||
|   | |||||||
| @@ -41,9 +41,8 @@ jobs: | |||||||
|  |  | ||||||
|       - name: Load secrets from github |       - name: Load secrets from github | ||||||
|         run: | |         run: | | ||||||
|           echo "${{ secrets.ANDROID_SECRET_PROPERTIES }}" > secrets.properties |           echo "${{ secrets.ANDROID_SECRET_PROPERTIES_BASE64 }}" | base64 -d > secrets.properties | ||||||
|           echo "${{ secrets.ANDROID_GOOGLE_PLAY_JSON }}" > fastlane/google-key.json |           echo "${{ secrets.ANDROID_GOOGLE_PLAY_JSON_BASE64 }}" | base64 -d > google-key.json | ||||||
|           # decode the base64 encoded google key |  | ||||||
|           echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > release.keystore |           echo "${{ secrets.ANDROID_KEYSTORE_BASE64 }}" | base64 -d > release.keystore | ||||||
|         working-directory: android |         working-directory: android | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										37
									
								
								frontend/lib/modules/current_trip_error_message.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								frontend/lib/modules/current_trip_error_message.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | |||||||
|  | import 'package:anyway/structs/trip.dart'; | ||||||
|  | import 'package:auto_size_text/auto_size_text.dart'; | ||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
|  | class CurrentTripErrorMessage extends StatefulWidget { | ||||||
|  |   final Trip trip; | ||||||
|  |   const CurrentTripErrorMessage({ | ||||||
|  |     super.key, | ||||||
|  |     required this.trip, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   State<CurrentTripErrorMessage> createState() => _CurrentTripErrorMessageState(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _CurrentTripErrorMessageState extends State<CurrentTripErrorMessage> { | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) => Center( | ||||||
|  |     child: Row( | ||||||
|  |       mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |       children: [ | ||||||
|  |         const Icon( | ||||||
|  |           Icons.error_outline, | ||||||
|  |           color: Colors.red, | ||||||
|  |           size: 50, | ||||||
|  |         ), | ||||||
|  |         const Padding( | ||||||
|  |           padding: EdgeInsets.only(left: 10), | ||||||
|  |         ), | ||||||
|  |         AutoSizeText( | ||||||
|  |           'Error: ${widget.trip.errorDescription}', | ||||||
|  |           maxLines: 3, | ||||||
|  |         ), | ||||||
|  |       ], | ||||||
|  |     ) | ||||||
|  |   ); | ||||||
|  | } | ||||||
| @@ -1,37 +1,27 @@ | |||||||
| import 'dart:developer'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| import 'package:anyway/constants.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:anyway/pages/current_trip.dart'; | ||||||
|  | import 'package:anyway/structs/trip.dart'; | ||||||
|  |  | ||||||
| class Greeter extends StatefulWidget { |  | ||||||
|  | class CurrentTripGreeter extends StatefulWidget { | ||||||
|   final Trip trip; |   final Trip trip; | ||||||
|  |  | ||||||
|   Greeter({ |   CurrentTripGreeter({ | ||||||
|  |     super.key, | ||||||
|     required this.trip, |     required this.trip, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   State<Greeter> createState() => _GreeterState(); |   State<CurrentTripGreeter> createState() => _CurrentTripGreeterState(); | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
| class _GreeterState extends State<Greeter> { | class _CurrentTripGreeterState extends State<CurrentTripGreeter> { | ||||||
|    |   @override | ||||||
|   Widget greeterBuilder (BuildContext context, Widget? child) { |   Widget build(BuildContext context) => Center( | ||||||
|     final Shader textGradient = APP_GRADIENT.createShader(Rect.fromLTWH(0.0, 0.0, 200.0, 70.0)); |     child: FutureBuilder( | ||||||
|     TextStyle greeterStyle = TextStyle( |  | ||||||
|       foreground: Paint()..shader = textGradient, |  | ||||||
|       fontWeight: FontWeight.bold, |  | ||||||
|       fontSize: 26 |  | ||||||
|     ); |  | ||||||
|  |  | ||||||
|     Widget topGreeter; |  | ||||||
|  |  | ||||||
|     if (widget.trip.uuid != 'pending') { |  | ||||||
|       topGreeter = FutureBuilder( |  | ||||||
|       future: widget.trip.cityName, |       future: widget.trip.cityName, | ||||||
|       builder: (BuildContext context, AsyncSnapshot<String> snapshot) { |       builder: (BuildContext context, AsyncSnapshot<String> snapshot) { | ||||||
|         if (snapshot.hasData) { |         if (snapshot.hasData) { | ||||||
| @@ -41,7 +31,6 @@ class _GreeterState extends State<Greeter> { | |||||||
|             style: greeterStyle |             style: greeterStyle | ||||||
|           ); |           ); | ||||||
|         } else if (snapshot.hasError) { |         } else if (snapshot.hasError) { | ||||||
|             log('Error while fetching city name'); |  | ||||||
|           return AutoSizeText( |           return AutoSizeText( | ||||||
|             maxLines: 1, |             maxLines: 1, | ||||||
|             'Welcome to your trip!', |             'Welcome to your trip!', | ||||||
| @@ -55,57 +44,7 @@ class _GreeterState extends State<Greeter> { | |||||||
|           ); |           ); | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       ); |  | ||||||
|     } else { |  | ||||||
|       // still awaiting the trip |  | ||||||
|       // We can hopefully infer the city name from the cityName future |  | ||||||
|       // Show a linear loader at the bottom and an info message above |  | ||||||
|       topGreeter = Column( |  | ||||||
|         mainAxisAlignment: MainAxisAlignment.end, |  | ||||||
|         children: [ |  | ||||||
|           FutureBuilder( |  | ||||||
|             future: widget.trip.cityName, |  | ||||||
|             builder: (BuildContext context, AsyncSnapshot<String> snapshot) { |  | ||||||
|               if (snapshot.hasData) { |  | ||||||
|                 return AutoSizeText( |  | ||||||
|                   maxLines: 1, |  | ||||||
|                   'Generating your trip to ${snapshot.data}...', |  | ||||||
|                   style: greeterStyle |  | ||||||
|                 ); |  | ||||||
|               } else if (snapshot.hasError) { |  | ||||||
|                 // the exact error is shown in the central part of the trip overview. No need to show it here |  | ||||||
|                 return AutoSizeText( |  | ||||||
|                   maxLines: 1, |  | ||||||
|                   'Error while loading trip.', |  | ||||||
|                   style: greeterStyle |  | ||||||
|                   ); |  | ||||||
|               } |  | ||||||
|               return AutoSizeText( |  | ||||||
|                   maxLines: 1, |  | ||||||
|                   'Generating your trip...', |  | ||||||
|                   style: greeterStyle |  | ||||||
|                   ); |  | ||||||
|             } |  | ||||||
|           ), |  | ||||||
|           Padding( |  | ||||||
|             padding: EdgeInsets.all(5), |  | ||||||
|             child: const LinearProgressIndicator() |  | ||||||
|     ) |     ) | ||||||
|         ] |  | ||||||
|   ); |   ); | ||||||
|     } |  | ||||||
|  |  | ||||||
|     return Center( |  | ||||||
|       child: topGreeter, |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
|  |  | ||||||
|  |  | ||||||
|   @override |  | ||||||
|   Widget build(BuildContext context) { |  | ||||||
|     return ListenableBuilder( |  | ||||||
|       listenable: widget.trip, |  | ||||||
|       builder: greeterBuilder, |  | ||||||
|     ); |  | ||||||
|   } |  | ||||||
| } | } | ||||||
							
								
								
									
										60
									
								
								frontend/lib/modules/current_trip_loading_indicator.dart
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								frontend/lib/modules/current_trip_loading_indicator.dart
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,60 @@ | |||||||
|  | import 'package:flutter/material.dart'; | ||||||
|  | import 'package:auto_size_text/auto_size_text.dart'; | ||||||
|  |  | ||||||
|  | import 'package:anyway/structs/trip.dart'; | ||||||
|  | import 'package:anyway/pages/current_trip.dart'; | ||||||
|  |  | ||||||
|  | class CurrentTripLoadingIndicator extends StatefulWidget { | ||||||
|  |   final Trip trip; | ||||||
|  |   const CurrentTripLoadingIndicator({ | ||||||
|  |     super.key, | ||||||
|  |     required this.trip, | ||||||
|  |   }); | ||||||
|  |  | ||||||
|  |   @override | ||||||
|  |   State<CurrentTripLoadingIndicator> createState() => _CurrentTripLoadingIndicatorState(); | ||||||
|  | } | ||||||
|  |  | ||||||
|  | class _CurrentTripLoadingIndicatorState extends State<CurrentTripLoadingIndicator> { | ||||||
|  |   @override | ||||||
|  |   Widget build(BuildContext context) => Center( | ||||||
|  |     child: FutureBuilder( | ||||||
|  |       future: widget.trip.cityName, | ||||||
|  |       builder: (BuildContext context, AsyncSnapshot<String> snapshot) { | ||||||
|  |         Widget greeter; | ||||||
|  |         Widget loadingIndicator = const Padding( | ||||||
|  |           padding: EdgeInsets.only(top: 10), | ||||||
|  |           child: CircularProgressIndicator() | ||||||
|  |         ); | ||||||
|  |  | ||||||
|  |         if (snapshot.hasData) { | ||||||
|  |           greeter = AutoSizeText( | ||||||
|  |             maxLines: 1, | ||||||
|  |             'Generating your trip to ${snapshot.data}...', | ||||||
|  |             style: greeterStyle, | ||||||
|  |           ); | ||||||
|  |         } else if (snapshot.hasError) { | ||||||
|  |           // the exact error is shown in the central part of the trip overview. No need to show it here | ||||||
|  |           greeter = AutoSizeText( | ||||||
|  |             maxLines: 1, | ||||||
|  |             'Error while loading trip.', | ||||||
|  |             style: greeterStyle, | ||||||
|  |             ); | ||||||
|  |         } else { | ||||||
|  |           greeter = AutoSizeText( | ||||||
|  |             maxLines: 1, | ||||||
|  |             'Generating your trip...', | ||||||
|  |             style: greeterStyle, | ||||||
|  |             ); | ||||||
|  |         } | ||||||
|  |         return Column( | ||||||
|  |           mainAxisAlignment: MainAxisAlignment.center, | ||||||
|  |           children: [ | ||||||
|  |             greeter, | ||||||
|  |             loadingIndicator, | ||||||
|  |           ], | ||||||
|  |         ); | ||||||
|  |       } | ||||||
|  |     ) | ||||||
|  |   ); | ||||||
|  | } | ||||||
| @@ -1,4 +1,6 @@ | |||||||
| import 'package:anyway/constants.dart'; | import 'package:anyway/constants.dart'; | ||||||
|  | import 'package:anyway/modules/current_trip_error_message.dart'; | ||||||
|  | import 'package:anyway/modules/current_trip_loading_indicator.dart'; | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| import 'package:anyway/structs/trip.dart'; | import 'package:anyway/structs/trip.dart'; | ||||||
| @@ -28,16 +30,36 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> { | |||||||
|     return ListenableBuilder( |     return ListenableBuilder( | ||||||
|       listenable: widget.trip, |       listenable: widget.trip, | ||||||
|       builder: (context, child) { |       builder: (context, child) { | ||||||
|         if (widget.trip.uuid != 'pending' && widget.trip.uuid != 'error') { |         if (widget.trip.uuid == 'error') { | ||||||
|  |           return Align( | ||||||
|  |               alignment: Alignment.topCenter, | ||||||
|  |               child: 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: CurrentTripErrorMessage(trip: widget.trip) | ||||||
|  |               ), | ||||||
|  |             ); | ||||||
|  |         } else if (widget.trip.uuid == 'pending') { | ||||||
|  |             return Align( | ||||||
|  |               alignment: Alignment.topCenter, | ||||||
|  |               child: 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: CurrentTripLoadingIndicator(trip: widget.trip), | ||||||
|  |               ), | ||||||
|  |             ); | ||||||
|  |         } else { | ||||||
|           return ListView( |           return ListView( | ||||||
|             controller: widget.controller, |             controller: widget.controller, | ||||||
|             padding: const EdgeInsets.only(bottom: 30, left: 5, right: 5), |             padding: const EdgeInsets.only(bottom: 30), | ||||||
|             children: [ |             children: [ | ||||||
|               SizedBox( |               SizedBox( | ||||||
|                 // reuse the exact same height as the panel has when collapsed |                 // reuse the exact same height as the panel has when collapsed | ||||||
|                 // this way the greeter will be centered when the panel is collapsed |                 // this way the greeter will be centered when the panel is collapsed | ||||||
|                 height: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT - 20, |                 height: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT - 20, | ||||||
|                 child: Greeter(trip: widget.trip), |                 child: CurrentTripGreeter(trip: widget.trip), | ||||||
|               ), |               ), | ||||||
|  |  | ||||||
|               const Padding(padding: EdgeInsets.only(top: 10)), |               const Padding(padding: EdgeInsets.only(top: 10)), | ||||||
| @@ -53,28 +75,6 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> { | |||||||
|               Center(child: saveButton(widget.trip)), |               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}'), |  | ||||||
|               ), |  | ||||||
|             ], |  | ||||||
|           ); |  | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     ); |     ); | ||||||
|   | |||||||
| @@ -6,6 +6,12 @@ import 'package:anyway/structs/trip.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'; | import 'package:anyway/modules/current_trip_panel.dart'; | ||||||
|  |  | ||||||
|  | final Shader textGradient = APP_GRADIENT.createShader(Rect.fromLTWH(0.0, 0.0, 200.0, 70.0)); | ||||||
|  | TextStyle greeterStyle = TextStyle( | ||||||
|  |   foreground: Paint()..shader = textGradient, | ||||||
|  |   fontWeight: FontWeight.bold, | ||||||
|  |   fontSize: 26 | ||||||
|  | ); | ||||||
|  |  | ||||||
|  |  | ||||||
| class TripPage extends StatefulWidget { | class TripPage extends StatefulWidget { | ||||||
| @@ -35,7 +41,7 @@ class _TripPageState extends State<TripPage> { | |||||||
|         maxHeight: MediaQuery.of(context).size.height * TRIP_PANEL_MAX_HEIGHT, |         maxHeight: MediaQuery.of(context).size.height * TRIP_PANEL_MAX_HEIGHT, | ||||||
|         // padding in this context is annoying: it offsets the notion of vertical alignment. |         // padding in this context is annoying: it offsets the notion of vertical alignment. | ||||||
|         // children that want to be centered vertically need to have their size adjusted by 2x the padding |         // children that want to be centered vertically need to have their size adjusted by 2x the padding | ||||||
|         padding: const EdgeInsets.only(top: 10), |         padding: const EdgeInsets.all(10.0), | ||||||
|         // Panel snapping should not be disabled because it significantly improves the user experience |         // Panel snapping should not be disabled because it significantly improves the user experience | ||||||
|         // panelSnapping: false |         // panelSnapping: false | ||||||
|         borderRadius: const BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), |         borderRadius: const BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)), | ||||||
|   | |||||||
| @@ -38,10 +38,18 @@ fetchTrip( | |||||||
|   String dataString = jsonEncode(data); |   String dataString = jsonEncode(data); | ||||||
|   log(dataString); |   log(dataString); | ||||||
|  |  | ||||||
|   final response = await dio.post( |   late Response response; | ||||||
|  |   try { | ||||||
|  |      response = await dio.post( | ||||||
|       "/trip/new", |       "/trip/new", | ||||||
|       data: data |       data: data | ||||||
|     ); |     ); | ||||||
|  |   } catch (e) { | ||||||
|  |     trip.updateUUID("error"); | ||||||
|  |     trip.updateError(e.toString()); | ||||||
|  |     log(e.toString()); | ||||||
|  |     return; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   // handle errors |   // handle errors | ||||||
|   if (response.statusCode != 200) { |   if (response.statusCode != 200) { | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user