chore(wip): upgrade dependencies, begin refactor
This commit is contained in:
17
frontend/lib/old/structs/agreement.dart
Normal file
17
frontend/lib/old/structs/agreement.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
final class Agreement{
|
||||
bool agreed;
|
||||
|
||||
Agreement({required this.agreed});
|
||||
}
|
||||
|
||||
void saveAgreement(bool agreed) async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
prefs.setBool('agreed_to_terms_and_conditions', agreed);
|
||||
}
|
||||
|
||||
Future<Agreement> getAgreement() async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
return Agreement(agreed: prefs.getBool('agreed_to_terms_and_conditions') ?? false);
|
||||
}
|
||||
172
frontend/lib/old/structs/landmark.dart
Normal file
172
frontend/lib/old/structs/landmark.dart
Normal file
@@ -0,0 +1,172 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
LandmarkType typeSightseeing = LandmarkType(name: 'sightseeing');
|
||||
LandmarkType typeNature = LandmarkType(name: 'nature');
|
||||
LandmarkType typeShopping = LandmarkType(name: 'shopping');
|
||||
// LandmarkType museum = LandmarkType(name: 'Museum');
|
||||
// LandmarkType restaurant = LandmarkType(name: 'Restaurant');
|
||||
LandmarkType typeStart = LandmarkType(name: 'start');
|
||||
LandmarkType typeFinish = LandmarkType(name: 'finish');
|
||||
|
||||
|
||||
final class Landmark extends LinkedListEntry<Landmark>{
|
||||
// A linked node of a list of Landmarks
|
||||
final String uuid;
|
||||
final String name;
|
||||
final List<double> location;
|
||||
final LandmarkType type;
|
||||
final bool? isSecondary;
|
||||
|
||||
// description to be shown in the overview
|
||||
final String? nameEN;
|
||||
final String? websiteURL;
|
||||
String? imageURL; // not final because it can be patched
|
||||
final String? description;
|
||||
final Duration? duration;
|
||||
bool visited;
|
||||
|
||||
// Next node is implicitly available through the LinkedListEntry mixin
|
||||
// final Landmark? next;
|
||||
Duration? tripTime;
|
||||
// the trip time depends on the next landmark, so it is not final
|
||||
|
||||
|
||||
Landmark({
|
||||
required this.uuid,
|
||||
required this.name,
|
||||
required this.location,
|
||||
required this.type,
|
||||
this.isSecondary,
|
||||
|
||||
this.nameEN,
|
||||
this.websiteURL,
|
||||
this.imageURL,
|
||||
this.description,
|
||||
this.duration,
|
||||
this.visited = false,
|
||||
|
||||
// this.next,
|
||||
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<dynamic> location,
|
||||
'type': String type,
|
||||
}) {
|
||||
// refine the parsing on a few fields
|
||||
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 nameEN = json['name_en'] as String?;
|
||||
final websiteURL = json['website_url'] as String?;
|
||||
final imageURL = json['image_url'] as String?;
|
||||
final description = json['description'] as String?;
|
||||
var duration = Duration(minutes: json['duration']);
|
||||
final visited = json['visited'] ?? false;
|
||||
var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?;
|
||||
|
||||
return Landmark(
|
||||
uuid: uuid,
|
||||
name: name,
|
||||
location: locationFixed,
|
||||
type: typeFixed,
|
||||
isSecondary: isSecondary,
|
||||
nameEN: nameEN,
|
||||
websiteURL: websiteURL,
|
||||
imageURL: imageURL,
|
||||
description: description,
|
||||
duration: duration,
|
||||
visited: visited,
|
||||
tripTime: tripTime
|
||||
);
|
||||
} else {
|
||||
throw FormatException('Invalid JSON: $json');
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@override
|
||||
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,
|
||||
'name_en': nameEN,
|
||||
'website_url': websiteURL,
|
||||
'image_url': imageURL,
|
||||
'description': description,
|
||||
'duration': duration?.inMinutes,
|
||||
'visited': visited,
|
||||
'trip_time': tripTime?.inMinutes,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
class LandmarkType {
|
||||
final String name;
|
||||
// final String description;
|
||||
Icon icon;
|
||||
|
||||
LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) {
|
||||
switch (name) {
|
||||
case 'sightseeing':
|
||||
icon = const Icon(Icons.castle);
|
||||
break;
|
||||
case 'nature':
|
||||
icon = const Icon(Icons.eco);
|
||||
break;
|
||||
case 'shopping':
|
||||
icon = const Icon(Icons.shopping_cart);
|
||||
break;
|
||||
case 'start':
|
||||
icon = const Icon(Icons.play_arrow);
|
||||
break;
|
||||
case 'finish':
|
||||
icon = const Icon(Icons.flag);
|
||||
break;
|
||||
default:
|
||||
icon = const Icon(Icons.location_on);
|
||||
}
|
||||
}
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
if (other is LandmarkType) {
|
||||
return name == other.name;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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!);
|
||||
String? nextUUID = json['next_uuid'];
|
||||
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));
|
||||
}
|
||||
69
frontend/lib/old/structs/preferences.dart
Normal file
69
frontend/lib/old/structs/preferences.dart
Normal file
@@ -0,0 +1,69 @@
|
||||
import 'package:anyway/structs/landmark.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
class SinglePreference {
|
||||
String slug;
|
||||
String name;
|
||||
String description;
|
||||
int value;
|
||||
int minVal;
|
||||
int maxVal;
|
||||
Icon icon;
|
||||
|
||||
SinglePreference({
|
||||
required this.slug,
|
||||
required this.name,
|
||||
required this.description,
|
||||
required this.value,
|
||||
required this.icon,
|
||||
this.minVal = 0,
|
||||
this.maxVal = 5,
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
class UserPreferences {
|
||||
SinglePreference sightseeing = SinglePreference(
|
||||
name: "Sightseeing",
|
||||
slug: "sightseeing",
|
||||
description: "How much do you like sightseeing?",
|
||||
value: 0,
|
||||
icon: typeSightseeing.icon,
|
||||
);
|
||||
SinglePreference shopping = SinglePreference(
|
||||
name: "Shopping",
|
||||
slug: "shopping",
|
||||
description: "How much do you like shopping?",
|
||||
value: 0,
|
||||
icon: typeShopping.icon,
|
||||
);
|
||||
SinglePreference nature = SinglePreference(
|
||||
name: "Nature",
|
||||
slug: "nature",
|
||||
description: "How much do you like nature?",
|
||||
value: 0,
|
||||
icon: typeNature.icon,
|
||||
);
|
||||
|
||||
SinglePreference maxTime = SinglePreference(
|
||||
name: "Trip duration",
|
||||
slug: "duration",
|
||||
description: "How long should your trip be?",
|
||||
value: 30,
|
||||
minVal: 30,
|
||||
maxVal: 720,
|
||||
icon: const Icon(Icons.timer),
|
||||
);
|
||||
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
// This is "opinionated" JSON, corresponding to the backend's expectations
|
||||
return {
|
||||
"sightseeing": {"type": "sightseeing", "score": sightseeing.value},
|
||||
"shopping": {"type": "shopping", "score": shopping.value},
|
||||
"nature": {"type": "nature", "score": nature.value},
|
||||
"max_time_minute": maxTime.value
|
||||
};
|
||||
}
|
||||
}
|
||||
142
frontend/lib/old/structs/trip.dart
Normal file
142
frontend/lib/old/structs/trip.dart
Normal file
@@ -0,0 +1,142 @@
|
||||
// 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;
|
||||
Duration 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 = Duration.zero,
|
||||
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: Duration(minutes: json['total_time']),
|
||||
);
|
||||
|
||||
return trip;
|
||||
}
|
||||
|
||||
void loadFromJson(Map<String, dynamic> json) {
|
||||
uuid = json['uuid'];
|
||||
totalTime = Duration(minutes: 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
|
||||
totalTime -= previous.tripTime ?? Duration.zero;
|
||||
previous.tripTime = null;
|
||||
// TODO
|
||||
}
|
||||
totalTime -= landmark.tripTime ?? Duration.zero;
|
||||
|
||||
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.inMinutes,
|
||||
'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;
|
||||
}
|
||||
Reference in New Issue
Block a user