UI elements using the new structs #8
| @@ -12,7 +12,7 @@ import 'package:fast_network_navigation/pages/profile.dart'; | ||||
| // A side drawer is used to switch between pages | ||||
| class BasePage extends StatefulWidget { | ||||
|   final String mainScreen; | ||||
|   final Trip? trip; | ||||
|   final Future<Trip>? trip; | ||||
|    | ||||
|   const BasePage({ | ||||
|     super.key, | ||||
| @@ -30,11 +30,10 @@ class _BasePageState extends State<BasePage> { | ||||
|   Widget build(BuildContext context) { | ||||
|     Widget currentView = const Text("loading..."); | ||||
|     Future<List<Trip>> trips = loadTrips(); | ||||
|     Future<Trip> firstTrip = getFirstTrip(trips); | ||||
|     // Future<Trip> trip = Future(trips[0]); | ||||
|      | ||||
|      | ||||
|     if (widget.mainScreen == "map") { | ||||
|       currentView = NavigationOverview(trip: firstTrip); | ||||
|       currentView = NavigationOverview(trip: widget.trip ?? getFirstTrip(trips)); | ||||
|     } else if (widget.mainScreen == "tutorial") { | ||||
|       currentView = TutorialPage(); | ||||
|     } else if (widget.mainScreen == "profile") { | ||||
| @@ -88,12 +87,8 @@ class _BasePageState extends State<BasePage> { | ||||
|               child: TripsOverview(trips: trips), | ||||
|             ), | ||||
|             ElevatedButton( | ||||
|               onPressed: () { | ||||
|                 Navigator.of(context).push( | ||||
|                   MaterialPageRoute( | ||||
|                     builder: (context) => const NewTripPage() | ||||
|                   ) | ||||
|                 ); | ||||
|               onPressed: () async { | ||||
|                 removeAllTripsFromPrefs(); | ||||
|               }, | ||||
|               child: const Text('Clear trips'), | ||||
|             ), | ||||
|   | ||||
| @@ -1,44 +1,73 @@ | ||||
| import 'package:fast_network_navigation/structs/trip.dart'; | ||||
|  | ||||
| import 'package:flutter/material.dart'; | ||||
|  | ||||
| Widget Greeter(ThemeData theme, {bool full = false}) { | ||||
|   String greeterText = ""; | ||||
|   try { | ||||
|     String cityName = getCityName(); | ||||
|     greeterText = "Welcome to $cityName!"; | ||||
|   } catch (e) { | ||||
|     greeterText = "Welcome ..."; | ||||
| class Greeter extends StatefulWidget { | ||||
|   final Future<Trip> trip; | ||||
|   final bool standalone; | ||||
|  | ||||
|   Greeter({ | ||||
|     required this.standalone, | ||||
|     required this.trip | ||||
|   }); | ||||
|  | ||||
|   @override | ||||
|   State<Greeter> createState() => _GreeterState(); | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| class _GreeterState extends State<Greeter> { | ||||
|   Widget greeterBuild (BuildContext context, AsyncSnapshot<Trip> snapshot) { | ||||
|     ThemeData theme = Theme.of(context); | ||||
|     String cityName = ""; | ||||
|     if (snapshot.hasData) { | ||||
|       cityName = snapshot.data?.cityName ?? '...'; | ||||
|     } else if (snapshot.hasError) { | ||||
|       cityName = "error"; | ||||
|     } else { // still awaiting the cityname | ||||
|       cityName = "..."; | ||||
|     } | ||||
|  | ||||
|     Widget topGreeter = Text( | ||||
|     greeterText, | ||||
|     style: TextStyle(color: theme.primaryColor, fontSize: 24.0, fontWeight: FontWeight.bold), | ||||
|     maxLines: 1, | ||||
|       'Welcome to $cityName!', | ||||
|       style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24), | ||||
|     ); | ||||
|  | ||||
|   Widget bottomGreeter = Container(); | ||||
|   if (full) { | ||||
|     bottomGreeter = Text( | ||||
|     if (widget.standalone) { | ||||
|       return Center( | ||||
|         child: Padding( | ||||
|           padding: EdgeInsets.only(top: 24.0), | ||||
|           child: topGreeter, | ||||
|         ), | ||||
|       ); | ||||
|     } else { | ||||
|       return Center( | ||||
|         child: Column( | ||||
|           children: [ | ||||
|             Padding(padding: EdgeInsets.only(top: 24.0)), | ||||
|             topGreeter, | ||||
|             bottomGreeter, | ||||
|             Padding(padding: EdgeInsets.only(bottom: 24.0)), | ||||
|           ], | ||||
|         ) | ||||
|       ); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   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, | ||||
|   ); | ||||
|   } | ||||
|   Widget greeter = Center( | ||||
|     child: Column( | ||||
|       children: [ | ||||
|         if (!full) Padding(padding: EdgeInsets.only(top: 24.0)), | ||||
|         topGreeter, | ||||
|         if (full) bottomGreeter, | ||||
|         Padding(padding: EdgeInsets.only(bottom: 24.0)), | ||||
|       ], | ||||
|     ), | ||||
|  | ||||
|  | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     return FutureBuilder( | ||||
|       future: widget.trip, | ||||
|       builder: greeterBuild, | ||||
|     ); | ||||
|  | ||||
|   return greeter; | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| String getCityName() { | ||||
|   return "Paris"; | ||||
|   } | ||||
| } | ||||
| @@ -32,7 +32,7 @@ class _LandmarkCardState extends State<LandmarkCard> { | ||||
|               // force a fixed width | ||||
|               width: 160, | ||||
|               child: Image.network( | ||||
|                 widget.landmark.imageURL!, | ||||
|                 widget.landmark.imageURL ?? '', | ||||
|                 errorBuilder: (context, error, stackTrace) => Icon(Icons.question_mark_outlined), | ||||
|                 // TODO: make this a switch statement to load a placeholder if null | ||||
|                 // cover the whole container meaning the image will be cropped | ||||
|   | ||||
| @@ -5,6 +5,7 @@ import 'package:fast_network_navigation/structs/landmark.dart'; | ||||
|  | ||||
| import 'package:fast_network_navigation/structs/trip.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:shared_preferences/shared_preferences.dart'; | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -31,7 +32,7 @@ class _LandmarksOverviewState extends State<LandmarksOverview> { | ||||
|         builder: (BuildContext context, AsyncSnapshot<LinkedList<Landmark>> snapshot) { | ||||
|           List<Widget> children; | ||||
|           if (snapshot.hasData) { | ||||
|             children = [landmarksWithSteps(snapshot.data!)]; | ||||
|             children = [landmarksWithSteps(snapshot.data!), saveButton()]; | ||||
|           } else if (snapshot.hasError) { | ||||
|             children = <Widget>[ | ||||
|               const Icon( | ||||
| @@ -41,7 +42,7 @@ class _LandmarksOverviewState extends State<LandmarksOverview> { | ||||
|               ), | ||||
|               Padding( | ||||
|                 padding: const EdgeInsets.only(top: 16), | ||||
|                 child: Text('Error: ${snapshot.error}'), | ||||
|                 child: Text('Error: ${snapshot.error}', style: TextStyle(fontSize: 12)), | ||||
|               ), | ||||
|             ]; | ||||
|           } else { | ||||
| @@ -57,6 +58,15 @@ class _LandmarksOverviewState extends State<LandmarksOverview> { | ||||
|       ), | ||||
|     ); | ||||
|   } | ||||
|   Widget saveButton() => ElevatedButton( | ||||
|     onPressed: () async { | ||||
|       Trip? trip = await widget.trip; | ||||
|       SharedPreferences prefs = await SharedPreferences.getInstance(); | ||||
|       trip?.toPrefs(prefs); | ||||
|     }, | ||||
|     child: const Text('Save'), | ||||
|   ); | ||||
|  | ||||
| } | ||||
|  | ||||
| Widget landmarksWithSteps(LinkedList<Landmark> landmarks) { | ||||
| @@ -117,3 +127,4 @@ Future<LinkedList<Landmark>> getLandmarks (Future<Trip>? trip) async { | ||||
|   Trip tripf = await trip!; | ||||
|   return tripf.landmarks; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -27,8 +27,14 @@ class _MapWidgetState extends State<MapWidget> { | ||||
|   Set<Marker> markers = <Marker>{}; | ||||
|    | ||||
|  | ||||
|   void _onMapCreated(GoogleMapController controller) { | ||||
|   void _onMapCreated(GoogleMapController controller) async { | ||||
|     mapController = controller; | ||||
|     Trip? trip = await widget.trip; | ||||
|     List<double>? newLocation = trip?.landmarks.first.location; | ||||
|     if (newLocation != null) { | ||||
|       CameraUpdate update = CameraUpdate.newLatLng(LatLng(newLocation[0], newLocation[1])); | ||||
|       controller.moveCamera(update); | ||||
|     } | ||||
|     drawLandmarks(); | ||||
|   } | ||||
|  | ||||
| @@ -41,7 +47,8 @@ class _MapWidgetState extends State<MapWidget> { | ||||
|   void drawLandmarks() async { | ||||
|     // (re)draws landmarks on the map | ||||
|     Trip? trip = await widget.trip; | ||||
|     LinkedList<Landmark> landmarks = trip!.landmarks; | ||||
|     LinkedList<Landmark>? landmarks = trip?.landmarks; | ||||
|     if (landmarks != null){ | ||||
|       setState(() { | ||||
|         for (Landmark landmark in landmarks) { | ||||
|           markers.add(Marker( | ||||
| @@ -52,6 +59,7 @@ class _MapWidgetState extends State<MapWidget> { | ||||
|         } | ||||
|       }); | ||||
|     } | ||||
|   } | ||||
|  | ||||
|  | ||||
|   @override | ||||
|   | ||||
| @@ -30,7 +30,7 @@ class _TripsOverviewState extends State<TripsOverview> { | ||||
|           onTap: () { | ||||
|             Navigator.of(context).push( | ||||
|               MaterialPageRoute( | ||||
|                 builder: (context) => BasePage(mainScreen: "map", trip: trip) | ||||
|                 builder: (context) => BasePage(mainScreen: "map", trip: Future.value(trip)) | ||||
|               ) | ||||
|             ); | ||||
|           }, | ||||
|   | ||||
| @@ -1,10 +1,11 @@ | ||||
| import 'package:fast_network_navigation/modules/greeter.dart'; | ||||
| import 'package:fast_network_navigation/structs/trip.dart'; | ||||
| import 'package:flutter/material.dart'; | ||||
| import 'package:sliding_up_panel/sliding_up_panel.dart'; | ||||
|  | ||||
| import 'package:fast_network_navigation/structs/trip.dart'; | ||||
|  | ||||
| import 'package:fast_network_navigation/modules/landmarks_overview.dart'; | ||||
| import 'package:fast_network_navigation/modules/map.dart'; | ||||
| import 'package:fast_network_navigation/modules/greeter.dart'; | ||||
|  | ||||
|  | ||||
|  | ||||
| @@ -25,16 +26,16 @@ class _NavigationOverviewState extends State<NavigationOverview> { | ||||
|  | ||||
|   @override | ||||
|   Widget build(BuildContext context) { | ||||
|     final ThemeData theme = Theme.of(context); | ||||
|     return SlidingUpPanel( | ||||
|         renderPanelSheet: false, | ||||
|         panel: _floatingPanel(theme), | ||||
|         collapsed: _floatingCollapsed(theme), | ||||
|         panel: _floatingPanel(), | ||||
|         collapsed: _floatingCollapsed(), | ||||
|         body: MapWidget(trip: widget.trip) | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   Widget _floatingCollapsed(ThemeData theme){ | ||||
|   Widget _floatingCollapsed(){ | ||||
|     final ThemeData theme = Theme.of(context); | ||||
|     return Container( | ||||
|       decoration: BoxDecoration( | ||||
|         color: theme.canvasColor, | ||||
| @@ -42,11 +43,12 @@ class _NavigationOverviewState extends State<NavigationOverview> { | ||||
|         boxShadow: [] | ||||
|       ), | ||||
|        | ||||
|       child: Greeter(theme) | ||||
|       child: Greeter(standalone: true, trip: widget.trip) | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   Widget _floatingPanel(ThemeData theme){ | ||||
|   Widget _floatingPanel(){ | ||||
|     final ThemeData theme = Theme.of(context); | ||||
|     return Container( | ||||
|       decoration: BoxDecoration( | ||||
|         color: Colors.white, | ||||
| @@ -64,7 +66,7 @@ class _NavigationOverviewState extends State<NavigationOverview> { | ||||
|         child: SingleChildScrollView( | ||||
|           child: Column( | ||||
|             children: <Widget>[ | ||||
|               Greeter(theme, full: true), | ||||
|               Greeter(standalone: false, trip: widget.trip), | ||||
|               LandmarksOverview(trip: widget.trip), | ||||
|             ], | ||||
|           ), | ||||
|   | ||||
| @@ -21,6 +21,7 @@ final class Landmark extends LinkedListEntry<Landmark>{ | ||||
|   // final Landmark? next; | ||||
|   final Duration? tripTime; | ||||
|  | ||||
|  | ||||
|   Landmark({ | ||||
|     required this.uuid, | ||||
|     required this.name, | ||||
| @@ -37,23 +38,28 @@ final class Landmark extends LinkedListEntry<Landmark>{ | ||||
|     this.tripTime, | ||||
|   }); | ||||
|  | ||||
|  | ||||
|   factory Landmark.fromJson(Map<String, dynamic> json) { | ||||
|     if (json | ||||
|       case { // automatically match all the non-optionals and cast them to the right type | ||||
|         'uuid': String uuid, | ||||
|         'name': String name, | ||||
|         'location': List<double> location, | ||||
|         'type': LandmarkType type, | ||||
|         'location': List<dynamic> location, | ||||
|         'type': String type, | ||||
|       }) { | ||||
|       // refine the parsing on a few | ||||
|       List<double> locationFixed = List<double>.from(location); | ||||
|       // parse the rest separately, they could be missing | ||||
|       LandmarkType typeFixed = LandmarkType(name: type); | ||||
|       final isSecondary = json['is_secondary'] as bool?; | ||||
|       final imageURL = json['image_url'] as String?; | ||||
|       final description = json['description'] as String?; | ||||
|         final duration = json['duration'] as Duration?; | ||||
|       var duration = Duration(minutes: json['duration'] ?? 0) as Duration?; | ||||
|       if (duration == const Duration()) {duration = null;}; | ||||
|       final visited = json['visited'] as bool?; | ||||
|        | ||||
|       return Landmark( | ||||
|           uuid: uuid, name: name, location: location, type: type, isSecondary: isSecondary, imageURL: imageURL, description: description, duration: duration, visited: visited); | ||||
|         uuid: uuid, name: name, location: locationFixed, type: typeFixed, isSecondary: isSecondary, imageURL: imageURL, description: description, duration: duration, visited: visited); | ||||
|     } else { | ||||
|       throw FormatException('Invalid JSON: $json'); | ||||
|     } | ||||
| @@ -64,6 +70,19 @@ final class Landmark extends LinkedListEntry<Landmark>{ | ||||
|   bool operator ==(Object other) { | ||||
|     return other is Landmark && uuid == other.uuid; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   Map<String, dynamic> toJson() => { | ||||
|     'uuid': uuid, | ||||
|     'name': name, | ||||
|     'location': location, | ||||
|     'type': type.name, | ||||
|     'is_secondary': isSecondary, | ||||
|     'image_url': imageURL, | ||||
|     'description': description, | ||||
|     'duration': duration?.inMinutes, | ||||
|     'visited': visited | ||||
|   }; | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -80,8 +99,8 @@ class LandmarkType { | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| // Helper | ||||
| // Helpers | ||||
| // Handling the landmarks requires a little bit of special care because the linked list is not directly representable in json | ||||
| (Landmark, String?) getLandmarkFromPrefs(SharedPreferences prefs, String uuid) { | ||||
|   String? content = prefs.getString('landmark_$uuid'); | ||||
|   Map<String, dynamic> json = jsonDecode(content!); | ||||
| @@ -89,3 +108,9 @@ class LandmarkType { | ||||
|   return (Landmark.fromJson(json), nextUUID); | ||||
| } | ||||
|  | ||||
|  | ||||
| void landmarkToPrefs(SharedPreferences prefs, Landmark current, Landmark? next) { | ||||
|   Map<String, dynamic> json = current.toJson(); | ||||
|   json['next_uuid'] = next?.uuid; | ||||
|   prefs.setString('landmark_${current.uuid}', jsonEncode(json)); | ||||
| } | ||||
|   | ||||
| @@ -14,36 +14,62 @@ class Trip { | ||||
|   final LinkedList<Landmark> landmarks; | ||||
|   // could be empty as well | ||||
|  | ||||
|  | ||||
|   Trip({ | ||||
|     required this.uuid, | ||||
|     required this.cityName, | ||||
|     required this.landmarks, | ||||
|   }); | ||||
|  | ||||
|  | ||||
|   factory Trip.fromJson(Map<String, dynamic> json) { | ||||
|     return Trip( | ||||
|       uuid: json['uuid'], | ||||
|       cityName: json['cityName'], | ||||
|       cityName: json['city_name'], | ||||
|       landmarks: LinkedList() | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|  | ||||
|   factory Trip.fromPrefs(SharedPreferences prefs, String uuid) { | ||||
|     String? content = prefs.getString('trip_$uuid'); | ||||
|     Map<String, dynamic> json = jsonDecode(content!); | ||||
|     Trip trip = Trip.fromJson(json); | ||||
|     String? firstUUID = json['entry_uuid']; | ||||
|     appendLandmarks(trip.landmarks, prefs, firstUUID); | ||||
|     readLandmarks(trip.landmarks, prefs, firstUUID); | ||||
|     return trip; | ||||
|   } | ||||
|  | ||||
|  | ||||
|   Map<String, dynamic> toJson() => { | ||||
|     'uuid': uuid, | ||||
|     'city_name': cityName, | ||||
|     'entry_uuid': landmarks.first?.uuid ?? '' | ||||
|   }; | ||||
|  | ||||
|  | ||||
|   void toPrefs(SharedPreferences prefs){ | ||||
|     Map<String, dynamic> json = toJson(); | ||||
|     prefs.setString('trip_$uuid', jsonEncode(json)); | ||||
|     for (Landmark landmark in landmarks) { | ||||
|       landmarkToPrefs(prefs, landmark, landmark.next); | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| // Helper | ||||
|  | ||||
| appendLandmarks(LinkedList<Landmark> landmarks, SharedPreferences prefs, String? firstUUID) { | ||||
| // Helper | ||||
| readLandmarks(LinkedList<Landmark> landmarks, SharedPreferences prefs, String? firstUUID) { | ||||
|   while (firstUUID != null) { | ||||
|     var (head, nextUUID) = getLandmarkFromPrefs(prefs, firstUUID); | ||||
|     landmarks.add(head); | ||||
|     firstUUID = nextUUID; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
|  | ||||
| void removeAllTripsFromPrefs () async { | ||||
|   SharedPreferences prefs = await SharedPreferences.getInstance(); | ||||
|   prefs.clear(); | ||||
| } | ||||
|   | ||||
| @@ -1,6 +1,5 @@ | ||||
| import 'dart:collection'; | ||||
|  | ||||
| import 'package:fast_network_navigation/structs/linked_landmarks.dart'; | ||||
| import 'package:fast_network_navigation/structs/trip.dart'; | ||||
| import 'package:fast_network_navigation/structs/landmark.dart'; | ||||
| import 'package:shared_preferences/shared_preferences.dart'; | ||||
| @@ -18,27 +17,103 @@ Future<List<Trip>> loadTrips() async { | ||||
|   } | ||||
|  | ||||
|   if (trips.isEmpty) { | ||||
|     String now = DateTime.now().toString(); | ||||
|     trips.add( | ||||
|       Trip(uuid: '1', cityName: 'Paris (generated $now)', landmarks: LinkedList<Landmark>()) | ||||
|     Trip t1 = Trip(uuid: '1', cityName: 'Paris', landmarks: LinkedList<Landmark>()); | ||||
|     t1.landmarks.add( | ||||
|       Landmark( | ||||
|         uuid: '1', | ||||
|         name: "Eiffel Tower", | ||||
|         location: [48.859, 2.295], | ||||
|         type: LandmarkType(name: "Tower"), | ||||
|         imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg" | ||||
|       ), | ||||
|     ); | ||||
|     //   Trip(uuid: "1", cityName: "Paris", landmarks: [ | ||||
|     //     Landmark(name: "Landmark 1", location: [48.85, 2.35], type: LandmarkType(name: "Type 1")), | ||||
|     //     Landmark(name: "Landmark 2", location: [48.86, 2.36], type: LandmarkType(name: "Type 2")), | ||||
|     //     Landmark(name: "Landmark 3", location: [48.75, 2.3], type: LandmarkType(name: "Type 3")), | ||||
|     //     Landmark(name: "Landmark 4", location: [48.9, 2.4], type: LandmarkType(name: "Type 4")), | ||||
|     //     Landmark(name: "Landmark 5", location: [48.91, 2.45], type: LandmarkType(name: "Type 5")), | ||||
|     //   ])); | ||||
|     // trips.add(Trip(uuid: "2", cityName: "Vienna", landmarks: [])); | ||||
|     // trips.add(Trip(uuid: "3", cityName: "London", landmarks: [])); | ||||
|     // trips.add(Trip(uuid: "4", cityName: "Madrid", landmarks: [])); | ||||
|     // trips.add(Trip(uuid: "5", cityName: "Tokyo", landmarks: [])); | ||||
|     // trips.add(Trip(uuid: "6", cityName: "New York", landmarks: [])); | ||||
|     // trips.add(Trip(uuid: "7", cityName: "Los Angeles", landmarks: [])); | ||||
|     // trips.add(Trip(uuid: "8", cityName: "Zurich", landmarks: [])); | ||||
|     // trips.add(Trip(uuid: "9", cityName: "Orschwiller", landmarks: [])); | ||||
|     t1.landmarks.add( | ||||
|       Landmark( | ||||
|         uuid: "2", | ||||
|         name: "Notre Dame Cathedral", | ||||
|         location: [48.8530, 2.3498], | ||||
|         type: LandmarkType(name: "Monument"), | ||||
|         imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f7/Notre-Dame_de_Paris%2C_4_October_2017.jpg/440px-Notre-Dame_de_Paris%2C_4_October_2017.jpg" | ||||
|       ), | ||||
|     ); | ||||
|     t1.landmarks.add( | ||||
|       Landmark( | ||||
|         uuid: "3", | ||||
|         name: "Louvre palace", | ||||
|         location: [48.8606, 2.3376], | ||||
|         type: LandmarkType(name: "Museum"), | ||||
|         imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/66/Louvre_Museum_Wikimedia_Commons.jpg/540px-Louvre_Museum_Wikimedia_Commons.jpg" | ||||
|       ), | ||||
|     ); | ||||
|     t1.landmarks.add( | ||||
|       Landmark( | ||||
|         uuid: "4", | ||||
|         name: "Pont-des-arts", | ||||
|         location: [48.8585, 2.3376], | ||||
|         type: LandmarkType(name: "Bridge"), | ||||
|         imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/d/d1/Pont_des_Arts%2C_6e_Arrondissement%2C_Paris_%28HDR%29_20140320_1.jpg/560px-Pont_des_Arts%2C_6e_Arrondissement%2C_Paris_%28HDR%29_20140320_1.jpg" | ||||
|       ), | ||||
|     ); | ||||
|     t1.landmarks.add( | ||||
|       Landmark( | ||||
|         uuid: "5", | ||||
|         name: "Panthéon", | ||||
|         location: [48.847, 2.347], | ||||
|         type: LandmarkType(name: "Monument"), | ||||
|         imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Pantheon_of_Paris_007.JPG/1280px-Pantheon_of_Paris_007.JPG" | ||||
|       ), | ||||
|     ); | ||||
|     trips.add(t1); | ||||
|  | ||||
|  | ||||
|     Trip t2 = Trip(uuid: '2', cityName: 'Vienna', landmarks: LinkedList<Landmark>()); | ||||
|  | ||||
|     t2.landmarks.add( | ||||
|       Landmark( | ||||
|         uuid: '21', | ||||
|         name: "St. Charles's Church", | ||||
|         location: [48.1924563,16.3334399], | ||||
|         type: LandmarkType(name: "Monument"), | ||||
|         imageURL: "https://lh5.googleusercontent.com/p/AF1QipNNmA76Ps71NCL9rOOFoyheCEOyXWdHcUgQx9jd=w408-h305-k-no" | ||||
|       ), | ||||
|     ); | ||||
|     t2.landmarks.add( | ||||
|       Landmark( | ||||
|         uuid: "22", | ||||
|         name: "Vienna State Opera", | ||||
|         location: [48.1949124,16.3483292], | ||||
|         type: LandmarkType(name: "Culture"), | ||||
|         imageURL: "https://lh5.googleusercontent.com/p/AF1QipMOx398kcoeDXFruSHNsb4lmZtdT8vibtK0cLi-=w408-h306-k-no" | ||||
|       ), | ||||
|     ); | ||||
|     t2.landmarks.add( | ||||
|       Landmark( | ||||
|         uuid: "23", | ||||
|         name: "Belvedere-Schlossgarten", | ||||
|         location: [48.1956427,16.3711521], | ||||
|         type: LandmarkType(name: "Nature"), | ||||
|         imageURL: "https://lh5.googleusercontent.com/p/AF1QipNcI5LImH2Qdzx0GmF-5CY1wRKINFZ7HkahPEy1=w408-h306-k-no" | ||||
|       ), | ||||
|     ); | ||||
|     t2.landmarks.add( | ||||
|       Landmark( | ||||
|         uuid: "24", | ||||
|         name: "Kunsthistorisches Museum Wien", | ||||
|         location: [48.2047501,16.3581904], | ||||
|         type: LandmarkType(name: "Museum"), | ||||
|         imageURL: "https://lh5.googleusercontent.com/p/AF1QipPuDu-kCCowO4TcawjziE8AhDVAANagVtRYBjlv=w408-h450-k-no" | ||||
|       ), | ||||
|     ); | ||||
|     t2.landmarks.add( | ||||
|       Landmark( | ||||
|         uuid: "25", | ||||
|         name: "Salztorbrücke", | ||||
|         location: [48.2132382,16.369051], | ||||
|         type: LandmarkType(name: "Bridge"), | ||||
|       ), | ||||
|     ); | ||||
|     trips.add(t2); | ||||
|  | ||||
|   } | ||||
|  | ||||
|   return trips; | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user