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 | // A side drawer is used to switch between pages | ||||||
| class BasePage extends StatefulWidget { | class BasePage extends StatefulWidget { | ||||||
|   final String mainScreen; |   final String mainScreen; | ||||||
|   final Trip? trip; |   final Future<Trip>? trip; | ||||||
|    |    | ||||||
|   const BasePage({ |   const BasePage({ | ||||||
|     super.key, |     super.key, | ||||||
| @@ -30,11 +30,10 @@ class _BasePageState extends State<BasePage> { | |||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     Widget currentView = const Text("loading..."); |     Widget currentView = const Text("loading..."); | ||||||
|     Future<List<Trip>> trips = loadTrips(); |     Future<List<Trip>> trips = loadTrips(); | ||||||
|     Future<Trip> firstTrip = getFirstTrip(trips); |      | ||||||
|     // Future<Trip> trip = Future(trips[0]); |  | ||||||
|      |      | ||||||
|     if (widget.mainScreen == "map") { |     if (widget.mainScreen == "map") { | ||||||
|       currentView = NavigationOverview(trip: firstTrip); |       currentView = NavigationOverview(trip: widget.trip ?? getFirstTrip(trips)); | ||||||
|     } else if (widget.mainScreen == "tutorial") { |     } else if (widget.mainScreen == "tutorial") { | ||||||
|       currentView = TutorialPage(); |       currentView = TutorialPage(); | ||||||
|     } else if (widget.mainScreen == "profile") { |     } else if (widget.mainScreen == "profile") { | ||||||
| @@ -88,12 +87,8 @@ class _BasePageState extends State<BasePage> { | |||||||
|               child: TripsOverview(trips: trips), |               child: TripsOverview(trips: trips), | ||||||
|             ), |             ), | ||||||
|             ElevatedButton( |             ElevatedButton( | ||||||
|               onPressed: () { |               onPressed: () async { | ||||||
|                 Navigator.of(context).push( |                 removeAllTripsFromPrefs(); | ||||||
|                   MaterialPageRoute( |  | ||||||
|                     builder: (context) => const NewTripPage() |  | ||||||
|                   ) |  | ||||||
|                 ); |  | ||||||
|               }, |               }, | ||||||
|               child: const Text('Clear trips'), |               child: const Text('Clear trips'), | ||||||
|             ), |             ), | ||||||
|   | |||||||
| @@ -1,44 +1,73 @@ | |||||||
|  | import 'package:fast_network_navigation/structs/trip.dart'; | ||||||
|  |  | ||||||
| import 'package:flutter/material.dart'; | import 'package:flutter/material.dart'; | ||||||
|  |  | ||||||
| Widget Greeter(ThemeData theme, {bool full = false}) { | class Greeter extends StatefulWidget { | ||||||
|   String greeterText = ""; |   final Future<Trip> trip; | ||||||
|   try { |   final bool standalone; | ||||||
|     String cityName = getCityName(); |  | ||||||
|     greeterText = "Welcome to $cityName!"; |   Greeter({ | ||||||
|   } catch (e) { |     required this.standalone, | ||||||
|     greeterText = "Welcome ..."; |     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( |     Widget topGreeter = Text( | ||||||
|     greeterText, |       'Welcome to $cityName!', | ||||||
|     style: TextStyle(color: theme.primaryColor, fontSize: 24.0, fontWeight: FontWeight.bold), |       style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24), | ||||||
|     maxLines: 1, |  | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|   Widget bottomGreeter = Container(); |     if (widget.standalone) { | ||||||
|   if (full) { |       return Center( | ||||||
|     bottomGreeter = Text( |         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!", |     "Busy day ahead? Here is how to make the most of it!", | ||||||
|     style: TextStyle(color: Colors.black, fontSize: 18), |     style: TextStyle(color: Colors.black, fontSize: 18), | ||||||
|     textAlign: TextAlign.center, |     textAlign: TextAlign.center, | ||||||
|   ); |   ); | ||||||
|   } |  | ||||||
|   Widget greeter = Center( |  | ||||||
|     child: Column( |  | ||||||
|       children: [ |   @override | ||||||
|         if (!full) Padding(padding: EdgeInsets.only(top: 24.0)), |   Widget build(BuildContext context) { | ||||||
|         topGreeter, |     return FutureBuilder( | ||||||
|         if (full) bottomGreeter, |       future: widget.trip, | ||||||
|         Padding(padding: EdgeInsets.only(bottom: 24.0)), |       builder: greeterBuild, | ||||||
|       ], |  | ||||||
|     ), |  | ||||||
|     ); |     ); | ||||||
|  |  | ||||||
|   return greeter; |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
| String getCityName() { |  | ||||||
|   return "Paris"; |  | ||||||
| } | } | ||||||
| @@ -32,7 +32,7 @@ class _LandmarkCardState extends State<LandmarkCard> { | |||||||
|               // force a fixed width |               // force a fixed width | ||||||
|               width: 160, |               width: 160, | ||||||
|               child: Image.network( |               child: Image.network( | ||||||
|                 widget.landmark.imageURL!, |                 widget.landmark.imageURL ?? '', | ||||||
|                 errorBuilder: (context, error, stackTrace) => Icon(Icons.question_mark_outlined), |                 errorBuilder: (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 | ||||||
|   | |||||||
| @@ -5,6 +5,7 @@ import 'package:fast_network_navigation/structs/landmark.dart'; | |||||||
|  |  | ||||||
| import 'package:fast_network_navigation/structs/trip.dart'; | import 'package:fast_network_navigation/structs/trip.dart'; | ||||||
| import 'package:flutter/material.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) { |         builder: (BuildContext context, AsyncSnapshot<LinkedList<Landmark>> snapshot) { | ||||||
|           List<Widget> children; |           List<Widget> children; | ||||||
|           if (snapshot.hasData) { |           if (snapshot.hasData) { | ||||||
|             children = [landmarksWithSteps(snapshot.data!)]; |             children = [landmarksWithSteps(snapshot.data!), saveButton()]; | ||||||
|           } else if (snapshot.hasError) { |           } else if (snapshot.hasError) { | ||||||
|             children = <Widget>[ |             children = <Widget>[ | ||||||
|               const Icon( |               const Icon( | ||||||
| @@ -41,7 +42,7 @@ class _LandmarksOverviewState extends State<LandmarksOverview> { | |||||||
|               ), |               ), | ||||||
|               Padding( |               Padding( | ||||||
|                 padding: const EdgeInsets.only(top: 16), |                 padding: const EdgeInsets.only(top: 16), | ||||||
|                 child: Text('Error: ${snapshot.error}'), |                 child: Text('Error: ${snapshot.error}', style: TextStyle(fontSize: 12)), | ||||||
|               ), |               ), | ||||||
|             ]; |             ]; | ||||||
|           } else { |           } 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) { | Widget landmarksWithSteps(LinkedList<Landmark> landmarks) { | ||||||
| @@ -117,3 +127,4 @@ Future<LinkedList<Landmark>> getLandmarks (Future<Trip>? trip) async { | |||||||
|   Trip tripf = await trip!; |   Trip tripf = await trip!; | ||||||
|   return tripf.landmarks; |   return tripf.landmarks; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -27,8 +27,14 @@ class _MapWidgetState extends State<MapWidget> { | |||||||
|   Set<Marker> markers = <Marker>{}; |   Set<Marker> markers = <Marker>{}; | ||||||
|    |    | ||||||
|  |  | ||||||
|   void _onMapCreated(GoogleMapController controller) { |   void _onMapCreated(GoogleMapController controller) async { | ||||||
|     mapController = controller; |     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(); |     drawLandmarks(); | ||||||
|   } |   } | ||||||
|  |  | ||||||
| @@ -41,7 +47,8 @@ class _MapWidgetState extends State<MapWidget> { | |||||||
|   void drawLandmarks() async { |   void drawLandmarks() async { | ||||||
|     // (re)draws landmarks on the map |     // (re)draws landmarks on the map | ||||||
|     Trip? trip = await widget.trip; |     Trip? trip = await widget.trip; | ||||||
|     LinkedList<Landmark> landmarks = trip!.landmarks; |     LinkedList<Landmark>? landmarks = trip?.landmarks; | ||||||
|  |     if (landmarks != null){ | ||||||
|       setState(() { |       setState(() { | ||||||
|         for (Landmark landmark in landmarks) { |         for (Landmark landmark in landmarks) { | ||||||
|           markers.add(Marker( |           markers.add(Marker( | ||||||
| @@ -52,6 +59,7 @@ class _MapWidgetState extends State<MapWidget> { | |||||||
|         } |         } | ||||||
|       }); |       }); | ||||||
|     } |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   @override |   @override | ||||||
|   | |||||||
| @@ -30,7 +30,7 @@ class _TripsOverviewState extends State<TripsOverview> { | |||||||
|           onTap: () { |           onTap: () { | ||||||
|             Navigator.of(context).push( |             Navigator.of(context).push( | ||||||
|               MaterialPageRoute( |               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:flutter/material.dart'; | ||||||
| import 'package:sliding_up_panel/sliding_up_panel.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/landmarks_overview.dart'; | ||||||
| import 'package:fast_network_navigation/modules/map.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 |   @override | ||||||
|   Widget build(BuildContext context) { |   Widget build(BuildContext context) { | ||||||
|     final ThemeData theme = Theme.of(context); |  | ||||||
|     return SlidingUpPanel( |     return SlidingUpPanel( | ||||||
|         renderPanelSheet: false, |         renderPanelSheet: false, | ||||||
|         panel: _floatingPanel(theme), |         panel: _floatingPanel(), | ||||||
|         collapsed: _floatingCollapsed(theme), |         collapsed: _floatingCollapsed(), | ||||||
|         body: MapWidget(trip: widget.trip) |         body: MapWidget(trip: widget.trip) | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   Widget _floatingCollapsed(ThemeData theme){ |   Widget _floatingCollapsed(){ | ||||||
|  |     final ThemeData theme = Theme.of(context); | ||||||
|     return Container( |     return Container( | ||||||
|       decoration: BoxDecoration( |       decoration: BoxDecoration( | ||||||
|         color: theme.canvasColor, |         color: theme.canvasColor, | ||||||
| @@ -42,11 +43,12 @@ class _NavigationOverviewState extends State<NavigationOverview> { | |||||||
|         boxShadow: [] |         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( |     return Container( | ||||||
|       decoration: BoxDecoration( |       decoration: BoxDecoration( | ||||||
|         color: Colors.white, |         color: Colors.white, | ||||||
| @@ -64,7 +66,7 @@ class _NavigationOverviewState extends State<NavigationOverview> { | |||||||
|         child: SingleChildScrollView( |         child: SingleChildScrollView( | ||||||
|           child: Column( |           child: Column( | ||||||
|             children: <Widget>[ |             children: <Widget>[ | ||||||
|               Greeter(theme, full: true), |               Greeter(standalone: false, trip: widget.trip), | ||||||
|               LandmarksOverview(trip: widget.trip), |               LandmarksOverview(trip: widget.trip), | ||||||
|             ], |             ], | ||||||
|           ), |           ), | ||||||
|   | |||||||
| @@ -21,6 +21,7 @@ final class Landmark extends LinkedListEntry<Landmark>{ | |||||||
|   // final Landmark? next; |   // final Landmark? next; | ||||||
|   final Duration? tripTime; |   final Duration? tripTime; | ||||||
|  |  | ||||||
|  |  | ||||||
|   Landmark({ |   Landmark({ | ||||||
|     required this.uuid, |     required this.uuid, | ||||||
|     required this.name, |     required this.name, | ||||||
| @@ -37,23 +38,28 @@ final class Landmark extends LinkedListEntry<Landmark>{ | |||||||
|     this.tripTime, |     this.tripTime, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  |  | ||||||
|   factory Landmark.fromJson(Map<String, dynamic> json) { |   factory Landmark.fromJson(Map<String, dynamic> json) { | ||||||
|     if (json |     if (json | ||||||
|       case { // automatically match all the non-optionals and cast them to the right type |       case { // automatically match all the non-optionals and cast them to the right type | ||||||
|         'uuid': String uuid, |         'uuid': String uuid, | ||||||
|         'name': String name, |         'name': String name, | ||||||
|         'location': List<double> location, |         'location': List<dynamic> location, | ||||||
|         'type': LandmarkType type, |         'type': String type, | ||||||
|       }) { |       }) { | ||||||
|  |       // refine the parsing on a few | ||||||
|  |       List<double> locationFixed = List<double>.from(location); | ||||||
|       // parse the rest separately, they could be missing |       // parse the rest separately, they could be missing | ||||||
|  |       LandmarkType typeFixed = LandmarkType(name: type); | ||||||
|       final isSecondary = json['is_secondary'] as bool?; |       final isSecondary = json['is_secondary'] as bool?; | ||||||
|       final imageURL = json['image_url'] as String?; |       final imageURL = json['image_url'] as String?; | ||||||
|       final description = json['description'] 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?; |       final visited = json['visited'] as bool?; | ||||||
|        |        | ||||||
|       return Landmark( |       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 { |     } else { | ||||||
|       throw FormatException('Invalid JSON: $json'); |       throw FormatException('Invalid JSON: $json'); | ||||||
|     } |     } | ||||||
| @@ -64,6 +70,19 @@ final class Landmark extends LinkedListEntry<Landmark>{ | |||||||
|   bool operator ==(Object other) { |   bool operator ==(Object other) { | ||||||
|     return other is Landmark && uuid == other.uuid; |     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 { | |||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  | // Helpers | ||||||
| // Helper | // 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) { | (Landmark, String?) getLandmarkFromPrefs(SharedPreferences prefs, String uuid) { | ||||||
|   String? content = prefs.getString('landmark_$uuid'); |   String? content = prefs.getString('landmark_$uuid'); | ||||||
|   Map<String, dynamic> json = jsonDecode(content!); |   Map<String, dynamic> json = jsonDecode(content!); | ||||||
| @@ -89,3 +108,9 @@ class LandmarkType { | |||||||
|   return (Landmark.fromJson(json), nextUUID); |   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; |   final LinkedList<Landmark> landmarks; | ||||||
|   // could be empty as well |   // could be empty as well | ||||||
|  |  | ||||||
|  |  | ||||||
|   Trip({ |   Trip({ | ||||||
|     required this.uuid, |     required this.uuid, | ||||||
|     required this.cityName, |     required this.cityName, | ||||||
|     required this.landmarks, |     required this.landmarks, | ||||||
|   }); |   }); | ||||||
|  |  | ||||||
|  |  | ||||||
|   factory Trip.fromJson(Map<String, dynamic> json) { |   factory Trip.fromJson(Map<String, dynamic> json) { | ||||||
|     return Trip( |     return Trip( | ||||||
|       uuid: json['uuid'], |       uuid: json['uuid'], | ||||||
|       cityName: json['cityName'], |       cityName: json['city_name'], | ||||||
|       landmarks: LinkedList() |       landmarks: LinkedList() | ||||||
|     ); |     ); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   factory Trip.fromPrefs(SharedPreferences prefs, String uuid) { |   factory Trip.fromPrefs(SharedPreferences prefs, String uuid) { | ||||||
|     String? content = prefs.getString('trip_$uuid'); |     String? content = prefs.getString('trip_$uuid'); | ||||||
|     Map<String, dynamic> json = jsonDecode(content!); |     Map<String, dynamic> json = jsonDecode(content!); | ||||||
|     Trip trip = Trip.fromJson(json); |     Trip trip = Trip.fromJson(json); | ||||||
|     String? firstUUID = json['entry_uuid']; |     String? firstUUID = json['entry_uuid']; | ||||||
|     appendLandmarks(trip.landmarks, prefs, firstUUID); |     readLandmarks(trip.landmarks, prefs, firstUUID); | ||||||
|     return trip; |     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) { |   while (firstUUID != null) { | ||||||
|     var (head, nextUUID) = getLandmarkFromPrefs(prefs, firstUUID); |     var (head, nextUUID) = getLandmarkFromPrefs(prefs, firstUUID); | ||||||
|     landmarks.add(head); |     landmarks.add(head); | ||||||
|     firstUUID = nextUUID; |     firstUUID = nextUUID; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  |  | ||||||
|  |  | ||||||
|  | void removeAllTripsFromPrefs () async { | ||||||
|  |   SharedPreferences prefs = await SharedPreferences.getInstance(); | ||||||
|  |   prefs.clear(); | ||||||
|  | } | ||||||
|   | |||||||
| @@ -1,6 +1,5 @@ | |||||||
| import 'dart:collection'; | 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/trip.dart'; | ||||||
| import 'package:fast_network_navigation/structs/landmark.dart'; | import 'package:fast_network_navigation/structs/landmark.dart'; | ||||||
| import 'package:shared_preferences/shared_preferences.dart'; | import 'package:shared_preferences/shared_preferences.dart'; | ||||||
| @@ -18,27 +17,103 @@ Future<List<Trip>> loadTrips() async { | |||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (trips.isEmpty) { |   if (trips.isEmpty) { | ||||||
|     String now = DateTime.now().toString(); |     Trip t1 = Trip(uuid: '1', cityName: 'Paris', landmarks: LinkedList<Landmark>()); | ||||||
|     trips.add( |     t1.landmarks.add( | ||||||
|       Trip(uuid: '1', cityName: 'Paris (generated $now)', landmarks: LinkedList<Landmark>()) |       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: [ |     t1.landmarks.add( | ||||||
|     //     Landmark(name: "Landmark 1", location: [48.85, 2.35], type: LandmarkType(name: "Type 1")), |       Landmark( | ||||||
|     //     Landmark(name: "Landmark 2", location: [48.86, 2.36], type: LandmarkType(name: "Type 2")), |         uuid: "2", | ||||||
|     //     Landmark(name: "Landmark 3", location: [48.75, 2.3], type: LandmarkType(name: "Type 3")), |         name: "Notre Dame Cathedral", | ||||||
|     //     Landmark(name: "Landmark 4", location: [48.9, 2.4], type: LandmarkType(name: "Type 4")), |         location: [48.8530, 2.3498], | ||||||
|     //     Landmark(name: "Landmark 5", location: [48.91, 2.45], type: LandmarkType(name: "Type 5")), |         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" | ||||||
|     // trips.add(Trip(uuid: "2", cityName: "Vienna", landmarks: [])); |       ), | ||||||
|     // trips.add(Trip(uuid: "3", cityName: "London", landmarks: [])); |     ); | ||||||
|     // trips.add(Trip(uuid: "4", cityName: "Madrid", landmarks: [])); |     t1.landmarks.add( | ||||||
|     // trips.add(Trip(uuid: "5", cityName: "Tokyo", landmarks: [])); |       Landmark( | ||||||
|     // trips.add(Trip(uuid: "6", cityName: "New York", landmarks: [])); |         uuid: "3", | ||||||
|     // trips.add(Trip(uuid: "7", cityName: "Los Angeles", landmarks: [])); |         name: "Louvre palace", | ||||||
|     // trips.add(Trip(uuid: "8", cityName: "Zurich", landmarks: [])); |         location: [48.8606, 2.3376], | ||||||
|     // trips.add(Trip(uuid: "9", cityName: "Orschwiller", landmarks: [])); |         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; |   return trips; | ||||||
| } | } | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user