140 lines
3.7 KiB
Dart
140 lines
3.7 KiB
Dart
// Represents a collection of landmarks that represent a journey
|
|
// Different instances of a Trip can be saved and loaded by the user
|
|
|
|
import 'dart:collection';
|
|
import 'dart:convert';
|
|
import 'dart:developer';
|
|
|
|
import 'package:anyway/structs/landmark.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:geocoding/geocoding.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
|
|
class Trip with ChangeNotifier {
|
|
String uuid;
|
|
int totalTime;
|
|
LinkedList<Landmark> landmarks;
|
|
// could be empty as well
|
|
String? errorDescription;
|
|
|
|
Future<String> get cityName async {
|
|
List<double>? location = landmarks.firstOrNull?.location;
|
|
if (GeocodingPlatform.instance == null) {
|
|
return '$location';
|
|
} else if (location == null) {
|
|
return 'Unknown';
|
|
} else{
|
|
List<Placemark> placemarks = await placemarkFromCoordinates(location[0], location[1]);
|
|
return placemarks.first.locality ?? 'Unknown';
|
|
}
|
|
}
|
|
|
|
Future<int> landmarkPosition (Landmark landmark) async {
|
|
int i = 0;
|
|
for (Landmark l in landmarks) {
|
|
if (l.uuid == landmark.uuid) {
|
|
return i;
|
|
} else if (l.type != typeStart && l.type != typeFinish) {
|
|
i++;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
Trip({
|
|
this.uuid = 'pending',
|
|
this.totalTime = 0,
|
|
LinkedList<Landmark>? landmarks
|
|
// a trip can be created with no landmarks, but the list should be initialized anyway
|
|
}) : landmarks = landmarks ?? LinkedList<Landmark>();
|
|
|
|
|
|
factory Trip.fromJson(Map<String, dynamic> json) {
|
|
Trip trip = Trip(
|
|
uuid: json['uuid'],
|
|
totalTime: json['total_time'],
|
|
);
|
|
|
|
return trip;
|
|
}
|
|
|
|
void loadFromJson(Map<String, dynamic> json) {
|
|
uuid = json['uuid'];
|
|
totalTime = json['total_time'];
|
|
notifyListeners();
|
|
}
|
|
|
|
void addLandmark(Landmark landmark) {
|
|
landmarks.add(landmark);
|
|
notifyListeners();
|
|
}
|
|
|
|
void updateUUID(String newUUID) {
|
|
uuid = newUUID;
|
|
notifyListeners();
|
|
}
|
|
|
|
void removeLandmark (Landmark landmark) async {
|
|
Landmark? previous = landmark.previous;
|
|
Landmark? next = landmark.next;
|
|
landmarks.remove(landmark);
|
|
// removing the landmark means we need to recompute the time between the two adjoined landmarks
|
|
if (previous != null && next != null) {
|
|
// previous.next = next happens automatically since we are using a LinkedList
|
|
previous.tripTime = null;
|
|
// TODO
|
|
}
|
|
notifyListeners();
|
|
}
|
|
|
|
void updateError(String error) {
|
|
errorDescription = error;
|
|
notifyListeners();
|
|
}
|
|
|
|
void notifyUpdate(){
|
|
notifyListeners();
|
|
}
|
|
|
|
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['first_landmark_uuid'];
|
|
log('Loading trip $uuid with first landmark $firstUUID');
|
|
LinkedList<Landmark> landmarks = readLandmarks(prefs, firstUUID);
|
|
trip.landmarks = landmarks;
|
|
return trip;
|
|
}
|
|
|
|
|
|
Map<String, dynamic> toJson() => {
|
|
'uuid': uuid,
|
|
'total_time': totalTime,
|
|
'first_landmark_uuid': landmarks.first.uuid
|
|
};
|
|
|
|
|
|
void toPrefs(SharedPreferences prefs){
|
|
Map<String, dynamic> json = toJson();
|
|
log('Saving trip $uuid : $json');
|
|
prefs.setString('trip_$uuid', jsonEncode(json));
|
|
for (Landmark landmark in landmarks) {
|
|
landmarkToPrefs(prefs, landmark, landmark.next);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// Helper
|
|
LinkedList<Landmark> readLandmarks(SharedPreferences prefs, String? firstUUID) {
|
|
LinkedList<Landmark> landmarks = LinkedList<Landmark>();
|
|
while (firstUUID != null) {
|
|
var (head, nextUUID) = getLandmarkFromPrefs(prefs, firstUUID);
|
|
landmarks.add(head);
|
|
firstUUID = nextUUID;
|
|
}
|
|
return landmarks;
|
|
}
|