overhaul using a trip struct that notifies its ui dependencies
This commit is contained in:
parent
5748630b99
commit
c87a01b2e8
@ -37,7 +37,7 @@ def new_trip(preferences: Preferences, start: tuple[float, float], end: tuple[fl
|
||||
logger.info("No end coordinates provided. Using start=end.")
|
||||
|
||||
start_landmark = Landmark(name='start', type='start', location=(start[0], start[1]), osm_type='start', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
|
||||
end_landmark = Landmark(name='end', type='finish', location=(end[0], end[1]), osm_type='end', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
|
||||
end_landmark = Landmark(name='finish', type='finish', location=(end[0], end[1]), osm_type='end', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
|
||||
|
||||
# Generate the landmarks from the start location
|
||||
landmarks, landmarks_short = manager.generate_landmarks_list(
|
||||
|
@ -1,3 +1,6 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:anyway/structs/landmark.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:anyway/constants.dart';
|
||||
@ -15,12 +18,12 @@ import 'package:anyway/pages/profile.dart';
|
||||
// A side drawer is used to switch between pages
|
||||
class BasePage extends StatefulWidget {
|
||||
final String mainScreen;
|
||||
final Future<Trip>? trip;
|
||||
|
||||
final Trip? trip;
|
||||
|
||||
const BasePage({
|
||||
super.key,
|
||||
required this.mainScreen,
|
||||
this.trip
|
||||
this.trip,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -53,13 +56,13 @@ class _BasePageState extends State<BasePage> {
|
||||
children: [
|
||||
DrawerHeader(
|
||||
decoration: BoxDecoration(
|
||||
gradient: LinearGradient(colors: [Colors.cyan, theme.primaryColor])
|
||||
gradient: LinearGradient(colors: [Colors.red, Colors.yellow])
|
||||
),
|
||||
child: Center(
|
||||
child: Text(
|
||||
APP_NAME,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
color: Colors.grey[800],
|
||||
fontSize: 24,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
@ -129,9 +132,54 @@ class _BasePageState extends State<BasePage> {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
Future<Trip> getFirstTrip (Future<List<Trip>> trips) async {
|
||||
List<Trip> tripsf = await trips;
|
||||
return tripsf[0];
|
||||
// This function is used to get the first trip from a list of trips
|
||||
// TODO: Implement this function
|
||||
Trip getFirstTrip(Future<List<Trip>> trips) {
|
||||
Trip t1 = Trip(uuid: '1', 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"
|
||||
),
|
||||
);
|
||||
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"
|
||||
),
|
||||
);
|
||||
return t1;
|
||||
}
|
@ -13,7 +13,7 @@ class App extends StatelessWidget {
|
||||
return MaterialApp(
|
||||
title: APP_NAME,
|
||||
home: BasePage(mainScreen: "map"),
|
||||
theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.green),
|
||||
theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.red[600]),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,10 @@ import 'package:anyway/structs/trip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class Greeter extends StatefulWidget {
|
||||
final Future<Trip> trip;
|
||||
final bool standalone;
|
||||
final Trip trip;
|
||||
|
||||
Greeter({
|
||||
required this.standalone,
|
||||
required this.trip
|
||||
required this.trip,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -18,55 +16,66 @@ class Greeter extends StatefulWidget {
|
||||
|
||||
|
||||
class _GreeterState extends State<Greeter> {
|
||||
Widget greeterBuild (BuildContext context, AsyncSnapshot<Trip> snapshot) {
|
||||
Widget greeterBuilder (BuildContext context, Widget? child) {
|
||||
ThemeData theme = Theme.of(context);
|
||||
Widget topGreeter;
|
||||
if (snapshot.hasData) {
|
||||
topGreeter = Padding(
|
||||
padding: const EdgeInsets.only(top: 20, bottom: 20),
|
||||
child: Text(
|
||||
'Welcome to ${snapshot.data?.cityName}!',
|
||||
style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24),
|
||||
)
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
topGreeter = const Padding(
|
||||
padding: EdgeInsets.only(top: 20, bottom: 20),
|
||||
child: Text('Error while fetching trip')
|
||||
if (widget.trip.landmarks.length > 1) {
|
||||
topGreeter = FutureBuilder(
|
||||
future: widget.trip.cityName,
|
||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Text(
|
||||
'Welcome to ${snapshot.data}!',
|
||||
style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24),
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
return const Text('Welcome to your trip!');
|
||||
} else {
|
||||
return const Text('Welcome to ...');
|
||||
}
|
||||
}
|
||||
);
|
||||
} else {
|
||||
// still awaiting the cityname
|
||||
// still awaiting the trip
|
||||
// We can hopefully infer the city name from the cityName future
|
||||
// Show a linear loader at the bottom and an info message above
|
||||
topGreeter = Column(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 20, bottom: 20),
|
||||
child: const Text('Generating your trip...', style: TextStyle(fontSize: 20),)
|
||||
FutureBuilder(
|
||||
future: widget.trip.cityName,
|
||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||
if (snapshot.hasData) {
|
||||
return Text(
|
||||
'Generating your trip to ${snapshot.data}...',
|
||||
style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24),
|
||||
);
|
||||
} else if (snapshot.hasError) {
|
||||
return const Text('Error while fetching city name');
|
||||
}
|
||||
return const Text('Generating your trip...');
|
||||
}
|
||||
),
|
||||
const LinearProgressIndicator()
|
||||
Padding(
|
||||
padding: EdgeInsets.all(5),
|
||||
child: const LinearProgressIndicator()
|
||||
)
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (widget.standalone) {
|
||||
return Center(
|
||||
child: topGreeter,
|
||||
);
|
||||
} else {
|
||||
return Center(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(padding: EdgeInsets.only(top: 24.0)),
|
||||
topGreeter,
|
||||
bottomGreeter,
|
||||
Padding(padding: EdgeInsets.only(bottom: 24.0)),
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
return Center(
|
||||
child: Column(
|
||||
children: [
|
||||
// Padding(padding: EdgeInsets.only(top: 20)),
|
||||
topGreeter,
|
||||
Padding(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: bottomGreeter
|
||||
),
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Widget bottomGreeter = const Text(
|
||||
@ -79,9 +88,9 @@ class _GreeterState extends State<Greeter> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: widget.trip,
|
||||
builder: greeterBuild,
|
||||
return ListenableBuilder(
|
||||
listenable: widget.trip,
|
||||
builder: greeterBuilder,
|
||||
);
|
||||
}
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
import 'package:anyway/structs/landmark.dart';
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
||||
@ -31,9 +32,10 @@ class _LandmarkCardState extends State<LandmarkCard> {
|
||||
height: double.infinity,
|
||||
// force a fixed width
|
||||
width: 160,
|
||||
child: Image.network(
|
||||
widget.landmark.imageURL ?? '',
|
||||
errorBuilder: (context, error, stackTrace) => Icon(Icons.question_mark_outlined),
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: widget.landmark.imageURL ?? '',
|
||||
placeholder: (context, url) => CircularProgressIndicator(),
|
||||
errorWidget: (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
|
||||
fit: BoxFit.cover,
|
||||
|
@ -1,17 +1,17 @@
|
||||
import 'dart:collection';
|
||||
import 'dart:developer';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
import 'package:anyway/modules/landmark_card.dart';
|
||||
import 'package:anyway/structs/landmark.dart';
|
||||
|
||||
import 'package:anyway/structs/trip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
|
||||
|
||||
|
||||
class LandmarksOverview extends StatefulWidget {
|
||||
final Future<Trip>? trip;
|
||||
final Trip? trip;
|
||||
const LandmarksOverview({super.key, this.trip});
|
||||
|
||||
@override
|
||||
@ -23,18 +23,17 @@ class _LandmarksOverviewState extends State<LandmarksOverview> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final Future<LinkedList<Landmark>> _landmarks = getLandmarks(widget.trip);
|
||||
return DefaultTextStyle(
|
||||
style: Theme.of(context).textTheme.displayMedium!,
|
||||
textAlign: TextAlign.center,
|
||||
child: FutureBuilder<LinkedList<Landmark>>(
|
||||
future: _landmarks,
|
||||
builder: (BuildContext context, AsyncSnapshot<LinkedList<Landmark>> snapshot) {
|
||||
List<Widget> children;
|
||||
if (snapshot.hasData) {
|
||||
children = [landmarksWithSteps(snapshot.data!), saveButton()];
|
||||
} else if (snapshot.hasError) {
|
||||
children = <Widget>[
|
||||
return ListenableBuilder(//<LinkedList<Landmark>>
|
||||
listenable: widget.trip!,
|
||||
builder: (BuildContext context, Widget? child) {
|
||||
Trip trip = widget.trip!;
|
||||
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
||||
List<Widget> children;
|
||||
if (trip.uuid == 'pending') {
|
||||
// the trip is still being fetched from the api
|
||||
children = [Center(child: CircularProgressIndicator())];
|
||||
} else if (trip.uuid == 'error') {
|
||||
children = [
|
||||
const Icon(
|
||||
Icons.error_outline,
|
||||
color: Colors.red,
|
||||
@ -42,20 +41,25 @@ class _LandmarksOverviewState extends State<LandmarksOverview> {
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 16),
|
||||
child: Text('Error: ${snapshot.error}', style: TextStyle(fontSize: 12)),
|
||||
child: Text('Error: ${trip.cityName}'),
|
||||
),
|
||||
];
|
||||
} else {
|
||||
if (trip.landmarks.length <= 1) {
|
||||
children = [
|
||||
const Text("No landmarks in this trip"),
|
||||
];
|
||||
} else {
|
||||
children = [Center(child: CircularProgressIndicator())];
|
||||
children = [
|
||||
landmarksWithSteps(trip.landmarks),
|
||||
saveButton(),
|
||||
];
|
||||
}
|
||||
return Center(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: children,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
}
|
||||
return Column(
|
||||
children: children,
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
Widget saveButton() => ElevatedButton(
|
||||
@ -100,7 +104,7 @@ Widget landmarksWithSteps(LinkedList<Landmark> landmarks) {
|
||||
);
|
||||
lkey++;
|
||||
if (landmark.next != null) {
|
||||
Widget step = stepBetweenLandmarks(landmark, landmark.next!);
|
||||
Widget step = stepBetweenLandmarks(landmark);
|
||||
children.add(step);
|
||||
}
|
||||
}
|
||||
@ -111,7 +115,7 @@ Widget landmarksWithSteps(LinkedList<Landmark> landmarks) {
|
||||
}
|
||||
|
||||
|
||||
Widget stepBetweenLandmarks(Landmark before, Landmark after) {
|
||||
Widget stepBetweenLandmarks(Landmark landmark) {
|
||||
// This is a simple widget that draws a line between landmark-cards
|
||||
// It's a vertical dotted line
|
||||
// Next to the line is the icon for the mode of transport (walking for now) and the estimated time
|
||||
@ -134,7 +138,7 @@ Widget stepBetweenLandmarks(Landmark before, Landmark after) {
|
||||
Column(
|
||||
children: [
|
||||
Icon(Icons.directions_walk),
|
||||
Text("5 min", style: TextStyle(fontSize: 10)),
|
||||
Text("${landmark.tripTime} min", style: TextStyle(fontSize: 10)),
|
||||
],
|
||||
),
|
||||
Spacer(),
|
||||
@ -149,8 +153,5 @@ Widget stepBetweenLandmarks(Landmark before, Landmark after) {
|
||||
);
|
||||
}
|
||||
|
||||
Future<LinkedList<Landmark>> getLandmarks (Future<Trip>? trip) async {
|
||||
Trip tripf = await trip!;
|
||||
return tripf.landmarks;
|
||||
}
|
||||
|
||||
|
||||
|
@ -8,7 +8,7 @@ import 'package:the_widget_marker/the_widget_marker.dart';
|
||||
|
||||
class MapWidget extends StatefulWidget {
|
||||
|
||||
final Future<Trip>? trip;
|
||||
final Trip? trip;
|
||||
|
||||
MapWidget({
|
||||
this.trip
|
||||
@ -31,8 +31,7 @@ class _MapWidgetState extends State<MapWidget> {
|
||||
|
||||
void _onMapCreated(GoogleMapController controller) async {
|
||||
mapController = controller;
|
||||
Trip? trip = await widget.trip;
|
||||
List<double>? newLocation = trip?.landmarks.first.location;
|
||||
List<double>? newLocation = widget.trip?.landmarks.first.location;
|
||||
if (newLocation != null) {
|
||||
CameraUpdate update = CameraUpdate.newLatLng(LatLng(newLocation[0], newLocation[1]));
|
||||
controller.moveCamera(update);
|
||||
@ -48,8 +47,7 @@ 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 = widget.trip?.landmarks;
|
||||
if (landmarks != null){
|
||||
for (Landmark landmark in landmarks) {
|
||||
markers.add(Marker(
|
||||
|
@ -30,7 +30,7 @@ class _TripsOverviewState extends State<TripsOverview> {
|
||||
onTap: () {
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => BasePage(mainScreen: "map", trip: Future.value(trip))
|
||||
builder: (context) => BasePage(mainScreen: "map", trip: trip)
|
||||
)
|
||||
);
|
||||
},
|
||||
|
@ -1,8 +1,10 @@
|
||||
import 'package:anyway/structs/landmark.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:geocoding/geocoding.dart';
|
||||
|
||||
import 'package:anyway/layout.dart';
|
||||
import 'package:anyway/structs/preferences.dart';
|
||||
import 'package:anyway/utils/fetch_trip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:anyway/structs/preferences.dart';
|
||||
import "package:anyway/structs/trip.dart";
|
||||
|
||||
|
||||
@ -64,7 +66,16 @@ class _NewTripPageState extends State<NewTripPage> {
|
||||
double.parse(lonController.text)
|
||||
];
|
||||
Future<UserPreferences> preferences = loadUserPreferences();
|
||||
Future<Trip>? trip = fetchTrip(startPoint, preferences);
|
||||
Trip trip = Trip();
|
||||
trip.landmarks.add(
|
||||
Landmark(
|
||||
location: startPoint,
|
||||
name: "start",
|
||||
type: LandmarkType(name: 'start'),
|
||||
uuid: "pending"
|
||||
)
|
||||
);
|
||||
fetchTrip(trip, preferences);
|
||||
Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => BasePage(mainScreen: "map", trip: trip)
|
||||
|
@ -10,10 +10,10 @@ import 'package:anyway/modules/greeter.dart';
|
||||
|
||||
|
||||
class NavigationOverview extends StatefulWidget {
|
||||
final Future<Trip> trip;
|
||||
final Trip trip;
|
||||
|
||||
NavigationOverview({
|
||||
required this.trip
|
||||
required this.trip,
|
||||
});
|
||||
|
||||
@override
|
||||
@ -27,53 +27,56 @@ class _NavigationOverviewState extends State<NavigationOverview> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return SlidingUpPanel(
|
||||
renderPanelSheet: false,
|
||||
panel: _floatingPanel(),
|
||||
collapsed: _floatingCollapsed(),
|
||||
body: MapWidget(trip: widget.trip)
|
||||
// collapsed: _floatingCollapsed(),
|
||||
body: MapWidget(trip: widget.trip),
|
||||
// renderPanelSheet: false,
|
||||
// backdropEnabled: true,
|
||||
maxHeight: MediaQuery.of(context).size.height * 0.8,
|
||||
padding: EdgeInsets.all(10),
|
||||
// panelSnapping: false,
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
blurRadius: 20.0,
|
||||
color: Colors.black,
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _floatingCollapsed(){
|
||||
final ThemeData theme = Theme.of(context);
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: theme.canvasColor,
|
||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(24.0), topRight: Radius.circular(24.0)),
|
||||
boxShadow: []
|
||||
),
|
||||
|
||||
child: Greeter(standalone: true, trip: widget.trip)
|
||||
return Greeter(
|
||||
trip: widget.trip
|
||||
);
|
||||
}
|
||||
|
||||
Widget _floatingPanel(){
|
||||
final ThemeData theme = Theme.of(context);
|
||||
return Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius: BorderRadius.all(Radius.circular(24.0)),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
blurRadius: 20.0,
|
||||
color: theme.shadowColor,
|
||||
),
|
||||
]
|
||||
),
|
||||
child: Center(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
Greeter(standalone: false, trip: widget.trip),
|
||||
LandmarksOverview(trip: widget.trip),
|
||||
],
|
||||
),
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(15),
|
||||
child:
|
||||
Center(
|
||||
child: Container(
|
||||
width: 40,
|
||||
height: 5,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.grey[300],
|
||||
borderRadius: BorderRadius.all(Radius.circular(12.0)),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: ListView(
|
||||
children: [
|
||||
Greeter(trip: widget.trip),
|
||||
LandmarksOverview(trip: widget.trip)
|
||||
]
|
||||
)
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -5,35 +5,56 @@ import 'dart:collection';
|
||||
import 'dart:convert';
|
||||
|
||||
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 {
|
||||
final String uuid;
|
||||
final String cityName;
|
||||
// TODO: cityName should be inferred from coordinates of the Landmarks
|
||||
final int totalTime;
|
||||
final LinkedList<Landmark> landmarks;
|
||||
class Trip with ChangeNotifier {
|
||||
String uuid;
|
||||
int totalTime;
|
||||
LinkedList<Landmark> landmarks;
|
||||
// could be empty as well
|
||||
|
||||
Future<String> get cityName async {
|
||||
if (GeocodingPlatform.instance == null) {
|
||||
return '${landmarks.first.location[0]}, ${landmarks.first.location[1]}';
|
||||
}
|
||||
List<Placemark> placemarks = await placemarkFromCoordinates(landmarks.first.location[0], landmarks.first.location[1]);
|
||||
return placemarks.first.locality ?? 'Unknown';
|
||||
}
|
||||
|
||||
|
||||
Trip({
|
||||
required this.uuid,
|
||||
required this.cityName,
|
||||
required this.landmarks,
|
||||
this.totalTime = 0
|
||||
});
|
||||
|
||||
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'],
|
||||
cityName: json['city_name'] ?? 'Not communicated',
|
||||
landmarks: LinkedList()
|
||||
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();
|
||||
}
|
||||
|
||||
factory Trip.fromPrefs(SharedPreferences prefs, String uuid) {
|
||||
String? content = prefs.getString('trip_$uuid');
|
||||
@ -47,7 +68,7 @@ class Trip {
|
||||
|
||||
Map<String, dynamic> toJson() => {
|
||||
'uuid': uuid,
|
||||
'city_name': cityName,
|
||||
'total_time': totalTime,
|
||||
'first_landmark_uuid': landmarks.first.uuid
|
||||
};
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
import "dart:convert";
|
||||
import "dart:developer";
|
||||
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import 'package:anyway/constants.dart';
|
||||
import "package:anyway/structs/landmark.dart";
|
||||
import "package:anyway/structs/trip.dart";
|
||||
@ -25,14 +25,14 @@ Dio dio = Dio(
|
||||
),
|
||||
);
|
||||
|
||||
Future<Trip>? fetchTrip(
|
||||
List<double> startPoint,
|
||||
fetchTrip(
|
||||
Trip trip,
|
||||
Future<UserPreferences> preferences,
|
||||
) async {
|
||||
UserPreferences prefs = await preferences;
|
||||
Map<String, dynamic> data = {
|
||||
"preferences": prefs.toJson(),
|
||||
"start": startPoint
|
||||
"start": trip.landmarks!.first.location,
|
||||
};
|
||||
String dataString = jsonEncode(data);
|
||||
log(dataString);
|
||||
@ -44,24 +44,25 @@ Future<Trip>? fetchTrip(
|
||||
|
||||
// handle errors
|
||||
if (response.statusCode != 200) {
|
||||
trip.updateUUID("error");
|
||||
throw Exception('Failed to load trip');
|
||||
}
|
||||
if (response.data["error"] != null) {
|
||||
trip.updateUUID("error");
|
||||
throw Exception(response.data["error"]);
|
||||
}
|
||||
log(response.data.toString());
|
||||
Map<String, dynamic> json = response.data;
|
||||
|
||||
// only fetch the trip "meta" data for now
|
||||
Trip trip = Trip.fromJson(json);
|
||||
// only fill in the trip "meta" data for now
|
||||
trip.loadFromJson(json);
|
||||
|
||||
String? nextUUID = json["first_landmark_uuid"];
|
||||
while (nextUUID != null) {
|
||||
var (landmark, newUUID) = await fetchLandmark(nextUUID);
|
||||
trip.landmarks.add(landmark);
|
||||
trip.addLandmark(landmark);
|
||||
nextUUID = newUUID;
|
||||
}
|
||||
return trip;
|
||||
}
|
||||
|
||||
|
||||
|
@ -17,7 +17,7 @@ Future<List<Trip>> loadTrips() async {
|
||||
}
|
||||
|
||||
if (trips.isEmpty) {
|
||||
Trip t1 = Trip(uuid: '1', cityName: 'Paris', landmarks: LinkedList<Landmark>());
|
||||
Trip t1 = Trip(uuid: '1', landmarks: LinkedList<Landmark>());
|
||||
t1.landmarks.add(
|
||||
Landmark(
|
||||
uuid: '1',
|
||||
@ -66,7 +66,7 @@ Future<List<Trip>> loadTrips() async {
|
||||
trips.add(t1);
|
||||
|
||||
|
||||
Trip t2 = Trip(uuid: '2', cityName: 'Vienna', landmarks: LinkedList<Landmark>());
|
||||
Trip t2 = Trip(uuid: '2', landmarks: LinkedList<Landmark>());
|
||||
|
||||
t2.landmarks.add(
|
||||
Landmark(
|
||||
|
@ -25,6 +25,30 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.1"
|
||||
cached_network_image:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: cached_network_image
|
||||
sha256: "4a5d8d2c728b0f3d0245f69f921d7be90cae4c2fd5288f773088672c0893f819"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.4.0"
|
||||
cached_network_image_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_platform_interface
|
||||
sha256: ff0c949e323d2a1b52be73acce5b4a7b04063e61414c8ca542dbba47281630a7
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.1.0"
|
||||
cached_network_image_web:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: cached_network_image_web
|
||||
sha256: "6322dde7a5ad92202e64df659241104a43db20ed594c41ca18de1014598d7996"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
characters:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -168,6 +192,38 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
geocoding:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: geocoding
|
||||
sha256: d580c801cba9386b4fac5047c4c785a4e19554f46be42f4f5e5b7deacd088a66
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.0"
|
||||
geocoding_android:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: geocoding_android
|
||||
sha256: "1b13eca79b11c497c434678fed109c2be020b158cec7512c848c102bc7232603"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.3.1"
|
||||
geocoding_ios:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: geocoding_ios
|
||||
sha256: "94ddba60387501bd1c11e18dca7c5a9e8c645d6e3da9c38b9762434941870c24"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.0.1"
|
||||
geocoding_platform_interface:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: geocoding_platform_interface
|
||||
sha256: "8c2c8226e5c276594c2e18bfe88b19110ed770aeb7c1ab50ede570be8b92229b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.2.0"
|
||||
google_maps:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -296,6 +352,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.12.0"
|
||||
octo_image:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: octo_image
|
||||
sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "2.1.0"
|
||||
path:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -41,6 +41,8 @@ dependencies:
|
||||
dio: ^5.5.0+1
|
||||
google_maps_flutter: ^2.7.0
|
||||
the_widget_marker: ^1.0.0
|
||||
cached_network_image: ^3.4.0
|
||||
geocoding: ^3.0.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
Loading…
x
Reference in New Issue
Block a user