working save and load functionality with custom datastructures
This commit is contained in:
parent
db41528702
commit
eede94add4
@ -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!";
|
|
||||||
} catch (e) {
|
|
||||||
greeterText = "Welcome ...";
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget topGreeter = Text(
|
Greeter({
|
||||||
greeterText,
|
required this.standalone,
|
||||||
style: TextStyle(color: theme.primaryColor, fontSize: 24.0, fontWeight: FontWeight.bold),
|
required this.trip
|
||||||
maxLines: 1,
|
});
|
||||||
);
|
|
||||||
|
|
||||||
Widget bottomGreeter = Container();
|
@override
|
||||||
if (full) {
|
State<Greeter> createState() => _GreeterState();
|
||||||
bottomGreeter = 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)),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
|
|
||||||
return greeter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String getCityName() {
|
class _GreeterState extends State<Greeter> {
|
||||||
return "Paris";
|
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(
|
||||||
|
'Welcome to $cityName!',
|
||||||
|
style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24),
|
||||||
|
);
|
||||||
|
|
||||||
|
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,
|
||||||
|
);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return FutureBuilder(
|
||||||
|
future: widget.trip,
|
||||||
|
builder: greeterBuild,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
@ -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,12 +27,18 @@ 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();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _onCameraIdle() {
|
void _onCameraIdle() {
|
||||||
// print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0)));
|
// print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0)));
|
||||||
}
|
}
|
||||||
@ -41,16 +47,18 @@ 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;
|
||||||
setState(() {
|
if (landmarks != null){
|
||||||
for (Landmark landmark in landmarks) {
|
setState(() {
|
||||||
markers.add(Marker(
|
for (Landmark landmark in landmarks) {
|
||||||
markerId: MarkerId(landmark.name),
|
markers.add(Marker(
|
||||||
position: LatLng(landmark.location[0], landmark.location[1]),
|
markerId: MarkerId(landmark.name),
|
||||||
infoWindow: InfoWindow(title: landmark.name, snippet: landmark.type.name),
|
position: LatLng(landmark.location[0], landmark.location[1]),
|
||||||
));
|
infoWindow: InfoWindow(title: landmark.name, snippet: landmark.type.name),
|
||||||
}
|
));
|
||||||
});
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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,
|
||||||
}) {
|
}) {
|
||||||
// parse the rest separately, they could be missing
|
// refine the parsing on a few
|
||||||
final isSecondary = json['is_secondary'] as bool?;
|
List<double> locationFixed = List<double>.from(location);
|
||||||
final imageURL = json['image_url'] as String?;
|
// parse the rest separately, they could be missing
|
||||||
final description = json['description'] as String?;
|
LandmarkType typeFixed = LandmarkType(name: type);
|
||||||
final duration = json['duration'] as Duration?;
|
final isSecondary = json['is_secondary'] as bool?;
|
||||||
final visited = json['visited'] as bool?;
|
final imageURL = json['image_url'] as String?;
|
||||||
|
final description = json['description'] as String?;
|
||||||
return Landmark(
|
var duration = Duration(minutes: json['duration'] ?? 0) as Duration?;
|
||||||
uuid: uuid, name: name, location: location, type: type, isSecondary: isSecondary, imageURL: imageURL, description: description, duration: duration, visited: visited);
|
if (duration == const Duration()) {duration = null;};
|
||||||
|
final visited = json['visited'] as bool?;
|
||||||
|
|
||||||
|
return Landmark(
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user