ui improvements for trips and landmarks
This commit is contained in:
parent
c87a01b2e8
commit
71d9554d97
@ -141,7 +141,7 @@ Trip getFirstTrip(Future<List<Trip>> trips) {
|
|||||||
uuid: '1',
|
uuid: '1',
|
||||||
name: "Eiffel Tower",
|
name: "Eiffel Tower",
|
||||||
location: [48.859, 2.295],
|
location: [48.859, 2.295],
|
||||||
type: LandmarkType(name: "Tower"),
|
type: monument,
|
||||||
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg"
|
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/a/a8/Tour_Eiffel_Wikimedia_Commons.jpg/1037px-Tour_Eiffel_Wikimedia_Commons.jpg"
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -150,7 +150,7 @@ Trip getFirstTrip(Future<List<Trip>> trips) {
|
|||||||
uuid: "2",
|
uuid: "2",
|
||||||
name: "Notre Dame Cathedral",
|
name: "Notre Dame Cathedral",
|
||||||
location: [48.8530, 2.3498],
|
location: [48.8530, 2.3498],
|
||||||
type: LandmarkType(name: "Monument"),
|
type: 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"
|
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"
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -159,7 +159,7 @@ Trip getFirstTrip(Future<List<Trip>> trips) {
|
|||||||
uuid: "3",
|
uuid: "3",
|
||||||
name: "Louvre palace",
|
name: "Louvre palace",
|
||||||
location: [48.8606, 2.3376],
|
location: [48.8606, 2.3376],
|
||||||
type: LandmarkType(name: "Museum"),
|
type: museum,
|
||||||
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/66/Louvre_Museum_Wikimedia_Commons.jpg/540px-Louvre_Museum_Wikimedia_Commons.jpg"
|
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/6/66/Louvre_Museum_Wikimedia_Commons.jpg/540px-Louvre_Museum_Wikimedia_Commons.jpg"
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -168,7 +168,7 @@ Trip getFirstTrip(Future<List<Trip>> trips) {
|
|||||||
uuid: "4",
|
uuid: "4",
|
||||||
name: "Pont-des-arts",
|
name: "Pont-des-arts",
|
||||||
location: [48.8585, 2.3376],
|
location: [48.8585, 2.3376],
|
||||||
type: LandmarkType(name: "Bridge"),
|
type: monument,
|
||||||
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"
|
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"
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -177,7 +177,7 @@ Trip getFirstTrip(Future<List<Trip>> trips) {
|
|||||||
uuid: "5",
|
uuid: "5",
|
||||||
name: "Panthéon",
|
name: "Panthéon",
|
||||||
location: [48.847, 2.347],
|
location: [48.847, 2.347],
|
||||||
type: LandmarkType(name: "Monument"),
|
type: monument,
|
||||||
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Pantheon_of_Paris_007.JPG/1280px-Pantheon_of_Paris_007.JPG"
|
imageURL: "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Pantheon_of_Paris_007.JPG/1280px-Pantheon_of_Paris_007.JPG"
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@ -24,14 +25,21 @@ class _GreeterState extends State<Greeter> {
|
|||||||
future: widget.trip.cityName,
|
future: widget.trip.cityName,
|
||||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
return Text(
|
return AutoSizeText(
|
||||||
|
maxLines: 1,
|
||||||
'Welcome to ${snapshot.data}!',
|
'Welcome to ${snapshot.data}!',
|
||||||
style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24),
|
style: TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24),
|
||||||
);
|
);
|
||||||
} else if (snapshot.hasError) {
|
} else if (snapshot.hasError) {
|
||||||
return const Text('Welcome to your trip!');
|
return const AutoSizeText(
|
||||||
|
maxLines: 1,
|
||||||
|
'Welcome to your trip!'
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
return const Text('Welcome to ...');
|
return const AutoSizeText(
|
||||||
|
maxLines: 1,
|
||||||
|
'Welcome to ...'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -51,7 +51,7 @@ class _LandmarksOverviewState extends State<LandmarksOverview> {
|
|||||||
];
|
];
|
||||||
} else {
|
} else {
|
||||||
children = [
|
children = [
|
||||||
landmarksWithSteps(trip.landmarks),
|
landmarksWithSteps(),
|
||||||
saveButton(),
|
saveButton(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -71,25 +71,27 @@ class _LandmarksOverviewState extends State<LandmarksOverview> {
|
|||||||
child: const Text('Save'),
|
child: const Text('Save'),
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
Widget landmarksWithSteps() {
|
||||||
|
return ListenableBuilder(
|
||||||
Widget landmarksWithSteps(LinkedList<Landmark> landmarks) {
|
listenable: widget.trip!,
|
||||||
|
builder: (BuildContext context, Widget? child) {
|
||||||
List<Widget> children = [];
|
List<Widget> children = [];
|
||||||
int lkey = 0;
|
for (Landmark landmark in widget.trip!.landmarks) {
|
||||||
for (Landmark landmark in landmarks) {
|
|
||||||
children.add(
|
children.add(
|
||||||
Dismissible(
|
Dismissible(
|
||||||
key: ValueKey<int>(lkey),
|
key: ValueKey<int>(landmark.hashCode),
|
||||||
child: LandmarkCard(landmark),
|
child: LandmarkCard(landmark),
|
||||||
// onDismissed: (direction) {
|
dismissThresholds: {DismissDirection.endToStart: 0.6},
|
||||||
// // Remove the item from the data source.
|
onDismissed: (direction) {
|
||||||
// setState(() {
|
// Remove the item from the data source.
|
||||||
// landmarks.remove(landmark);
|
log(landmark.name);
|
||||||
// });
|
setState(() {
|
||||||
// // Then show a snackbar.
|
widget.trip!.removeLandmark(landmark);
|
||||||
// ScaffoldMessenger.of(context)
|
});
|
||||||
// .showSnackBar(SnackBar(content: Text("${landmark.name} dismissed")));
|
// Then show a snackbar.
|
||||||
// },
|
ScaffoldMessenger.of(context)
|
||||||
|
.showSnackBar(SnackBar(content: Text("We won't show ${landmark.name} again")));
|
||||||
|
},
|
||||||
background: Container(color: Colors.red),
|
background: Container(color: Colors.red),
|
||||||
secondaryBackground: Container(
|
secondaryBackground: Container(
|
||||||
color: Colors.red,
|
color: Colors.red,
|
||||||
@ -102,24 +104,28 @@ Widget landmarksWithSteps(LinkedList<Landmark> landmarks) {
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
lkey++;
|
|
||||||
if (landmark.next != null) {
|
if (landmark.next != null) {
|
||||||
Widget step = stepBetweenLandmarks(landmark);
|
Widget step = stepBetweenLandmarks(landmark, landmark.next!);
|
||||||
children.add(step);
|
children.add(step);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
children: children
|
children: children
|
||||||
);
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget stepBetweenLandmarks(Landmark landmark) {
|
Widget stepBetweenLandmarks(Landmark current, Landmark next) {
|
||||||
// This is a simple widget that draws a line between landmark-cards
|
// This is a simple widget that draws a line between landmark-cards
|
||||||
// It's a vertical dotted line
|
// 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
|
// Next to the line is the icon for the mode of transport (walking for now) and the estimated time
|
||||||
// There is also a button to open the navigation instructions as a new intent
|
// There is also a button to open the navigation instructions as a new intent
|
||||||
|
// next landmark is not actually required, but it ensures that the widget is deleted when the next landmark is removed (which makes sense, because then there will be another step)
|
||||||
|
int timeRounded = 5 * (current.tripTime?.inMinutes ?? 0) ~/ 5;
|
||||||
|
// ~/ is integer division (rounding)
|
||||||
return Container(
|
return Container(
|
||||||
margin: EdgeInsets.all(10),
|
margin: EdgeInsets.all(10),
|
||||||
padding: EdgeInsets.all(10),
|
padding: EdgeInsets.all(10),
|
||||||
@ -138,7 +144,7 @@ Widget stepBetweenLandmarks(Landmark landmark) {
|
|||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.directions_walk),
|
Icon(Icons.directions_walk),
|
||||||
Text("${landmark.tripTime} min", style: TextStyle(fontSize: 10)),
|
Text("~$timeRounded min", style: TextStyle(fontSize: 10)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
@ -146,8 +152,13 @@ Widget stepBetweenLandmarks(Landmark landmark) {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
// Open navigation instructions
|
// Open navigation instructions
|
||||||
},
|
},
|
||||||
child: Text("Navigate"),
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.directions),
|
||||||
|
Text("Directions"),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -4,7 +4,8 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:anyway/structs/landmark.dart';
|
import 'package:anyway/structs/landmark.dart';
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
import 'package:google_maps_flutter/google_maps_flutter.dart';
|
||||||
import 'package:the_widget_marker/the_widget_marker.dart';
|
import 'package:widget_to_marker/widget_to_marker.dart';
|
||||||
|
|
||||||
|
|
||||||
class MapWidget extends StatefulWidget {
|
class MapWidget extends StatefulWidget {
|
||||||
|
|
||||||
@ -25,38 +26,42 @@ class _MapWidgetState extends State<MapWidget> {
|
|||||||
target: LatLng(48.8566, 2.3522),
|
target: LatLng(48.8566, 2.3522),
|
||||||
zoom: 11.0,
|
zoom: 11.0,
|
||||||
);
|
);
|
||||||
Set<Marker> markers = <Marker>{};
|
Set<Marker> mapMarkers = <Marker>{};
|
||||||
final GlobalKey globalKey = GlobalKey();
|
|
||||||
|
|
||||||
|
|
||||||
void _onMapCreated(GoogleMapController controller) async {
|
void _onMapCreated(GoogleMapController controller) async {
|
||||||
mapController = controller;
|
mapController = controller;
|
||||||
List<double>? newLocation = widget.trip?.landmarks.first.location;
|
List<double>? newLocation = widget.trip?.landmarks.firstOrNull?.location;
|
||||||
if (newLocation != null) {
|
if (newLocation != null) {
|
||||||
CameraUpdate update = CameraUpdate.newLatLng(LatLng(newLocation[0], newLocation[1]));
|
CameraUpdate update = CameraUpdate.newLatLng(LatLng(newLocation[0], newLocation[1]));
|
||||||
controller.moveCamera(update);
|
controller.moveCamera(update);
|
||||||
}
|
}
|
||||||
drawLandmarks();
|
// addLandmarkMarker();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void _onCameraIdle() {
|
void _onCameraIdle() {
|
||||||
// print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0)));
|
// print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void drawLandmarks() async {
|
void addLandmarkMarker() async {
|
||||||
// (re)draws landmarks on the map
|
|
||||||
LinkedList<Landmark>? landmarks = widget.trip?.landmarks;
|
LinkedList<Landmark>? landmarks = widget.trip?.landmarks;
|
||||||
if (landmarks != null){
|
int i = mapMarkers.length;
|
||||||
for (Landmark landmark in landmarks) {
|
Landmark? current = landmarks!.elementAtOrNull(i);
|
||||||
markers.add(Marker(
|
if (current != null){
|
||||||
markerId: MarkerId(landmark.name),
|
mapMarkers.add(
|
||||||
position: LatLng(landmark.location[0], landmark.location[1]),
|
Marker(
|
||||||
// infoWindow: InfoWindow(title: landmark.name, snippet: landmark.type.name),
|
markerId: MarkerId(current.name),
|
||||||
icon: await MarkerIcon.widgetToIcon(globalKey),
|
position: LatLng(current.location[0], current.location[1]),
|
||||||
));
|
icon: await CustomMarker(
|
||||||
}
|
landmark: current,
|
||||||
|
position: i+1
|
||||||
|
).toBitmapDescriptor(
|
||||||
|
logicalSize: const Size(150, 150),
|
||||||
|
imageSize: const Size(150, 150)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,39 +69,60 @@ class _MapWidgetState extends State<MapWidget> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Stack(
|
return ListenableBuilder(
|
||||||
children: [
|
listenable: widget.trip!,
|
||||||
MyMarker(globalKey),
|
builder: (context, child) {
|
||||||
|
addLandmarkMarker();
|
||||||
GoogleMap(
|
return GoogleMap(
|
||||||
onMapCreated: _onMapCreated,
|
onMapCreated: _onMapCreated,
|
||||||
initialCameraPosition: _cameraPosition,
|
initialCameraPosition: _cameraPosition,
|
||||||
onCameraIdle: _onCameraIdle,
|
onCameraIdle: _onCameraIdle,
|
||||||
|
|
||||||
// onLongPress: ,
|
// onLongPress: ,
|
||||||
markers: markers,
|
markers: mapMarkers,
|
||||||
cloudMapId: '41c21ac9b81dbfd8',
|
cloudMapId: '41c21ac9b81dbfd8',
|
||||||
)
|
);
|
||||||
]
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class MyMarker extends StatelessWidget {
|
class CustomMarker extends StatelessWidget {
|
||||||
// declare a global key and get it trough Constructor
|
final Landmark landmark;
|
||||||
|
final int position;
|
||||||
|
|
||||||
MyMarker(this.globalKeyMyWidget);
|
CustomMarker({
|
||||||
final GlobalKey globalKeyMyWidget;
|
super.key,
|
||||||
|
required this.landmark,
|
||||||
|
required this.position
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// This returns an outlined circle, with an icon corresponding to the landmark type
|
// This returns an outlined circle, with an icon corresponding to the landmark type
|
||||||
// As a small dot, the number of the landmark is displayed in the top right
|
// As a small dot, the number of the landmark is displayed in the top right
|
||||||
|
Icon icon;
|
||||||
|
if (landmark.type == museum) {
|
||||||
|
icon = Icon(Icons.museum, color: Colors.black, size: 50);
|
||||||
|
} else if (landmark.type == monument) {
|
||||||
|
icon = Icon(Icons.church, color: Colors.black, size: 50);
|
||||||
|
} else if (landmark.type == park) {
|
||||||
|
icon = Icon(Icons.park, color: Colors.black, size: 50);
|
||||||
|
} else if (landmark.type == restaurant) {
|
||||||
|
icon = Icon(Icons.restaurant, color: Colors.black, size: 50);
|
||||||
|
} else if (landmark.type == shop) {
|
||||||
|
icon = Icon(Icons.shopping_cart, color: Colors.black, size: 50);
|
||||||
|
} else {
|
||||||
|
icon = Icon(Icons.location_on, color: Colors.black, size: 50);
|
||||||
|
}
|
||||||
|
|
||||||
return RepaintBoundary(
|
return RepaintBoundary(
|
||||||
key: globalKeyMyWidget,
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
|
// these are not the final sizes, since the final size is set in the toBitmapDescriptor method
|
||||||
|
// they are useful nevertheless to ensure the scale of the components are correct
|
||||||
width: 75,
|
width: 75,
|
||||||
height: 75,
|
height: 75,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
@ -108,7 +134,7 @@ class MyMarker extends StatelessWidget {
|
|||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(color: Colors.black, width: 5),
|
border: Border.all(color: Colors.black, width: 5),
|
||||||
),
|
),
|
||||||
child: Icon(Icons.location_on, color: Colors.black, size: 50),
|
child: icon,
|
||||||
),
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 0,
|
top: 0,
|
||||||
@ -119,7 +145,7 @@ class MyMarker extends StatelessWidget {
|
|||||||
color: Theme.of(context).primaryColor,
|
color: Theme.of(context).primaryColor,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
),
|
),
|
||||||
child: Text('1', style: TextStyle(color: Colors.white, fontSize: 20)),
|
child: Text('$position', style: TextStyle(color: Colors.white, fontSize: 20)),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -25,7 +25,18 @@ class _TripsOverviewState extends State<TripsOverview> {
|
|||||||
children = List<Widget>.generate(snapshot.data!.length, (index) {
|
children = List<Widget>.generate(snapshot.data!.length, (index) {
|
||||||
Trip trip = snapshot.data![index];
|
Trip trip = snapshot.data![index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text("Trip to ${trip.cityName}"),
|
title: FutureBuilder(
|
||||||
|
future: trip.cityName,
|
||||||
|
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
return Text("Trip to ${snapshot.data}");
|
||||||
|
} else if (snapshot.hasError) {
|
||||||
|
return Text("Error: ${snapshot.error}");
|
||||||
|
} else {
|
||||||
|
return const Text("Trip to ...");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
leading: Icon(Icons.pin_drop),
|
leading: Icon(Icons.pin_drop),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
|
@ -2,6 +2,7 @@ import 'package:anyway/structs/preferences.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
|
bool debugMode = false;
|
||||||
|
|
||||||
class ProfilePage extends StatefulWidget {
|
class ProfilePage extends StatefulWidget {
|
||||||
@override
|
@override
|
||||||
@ -12,6 +13,27 @@ class _ProfilePageState extends State<ProfilePage> {
|
|||||||
Future<UserPreferences> _prefs = loadUserPreferences();
|
Future<UserPreferences> _prefs = loadUserPreferences();
|
||||||
|
|
||||||
|
|
||||||
|
Widget debugButton() {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.only(top: 20),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
Text('Debug mode'),
|
||||||
|
Switch(
|
||||||
|
value: debugMode,
|
||||||
|
onChanged: (bool? newValue) {
|
||||||
|
setState(() {
|
||||||
|
debugMode = newValue!;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView(
|
return ListView(
|
||||||
@ -36,7 +58,8 @@ class _ProfilePageState extends State<ProfilePage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
FutureBuilder(future: _prefs, builder: futureSliders)
|
FutureBuilder(future: _prefs, builder: futureSliders),
|
||||||
|
debugButton()
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -59,7 +82,6 @@ class _ProfilePageState extends State<ProfilePage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class PreferenceSliders extends StatefulWidget {
|
class PreferenceSliders extends StatefulWidget {
|
||||||
final List<SinglePreference> prefs;
|
final List<SinglePreference> prefs;
|
||||||
|
|
||||||
|
@ -3,6 +3,14 @@ import 'dart:convert';
|
|||||||
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
|
|
||||||
|
const LandmarkType museum = LandmarkType(name: 'Museum');
|
||||||
|
const LandmarkType monument = LandmarkType(name: 'Monument');
|
||||||
|
const LandmarkType park = LandmarkType(name: 'Park');
|
||||||
|
const LandmarkType restaurant = LandmarkType(name: 'Restaurant');
|
||||||
|
const LandmarkType shop = LandmarkType(name: 'Shop');
|
||||||
|
|
||||||
|
|
||||||
final class Landmark extends LinkedListEntry<Landmark>{
|
final class Landmark extends LinkedListEntry<Landmark>{
|
||||||
// A linked node of a list of Landmarks
|
// A linked node of a list of Landmarks
|
||||||
final String uuid;
|
final String uuid;
|
||||||
@ -55,11 +63,12 @@ final class Landmark extends LinkedListEntry<Landmark>{
|
|||||||
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?;
|
||||||
var duration = Duration(minutes: json['duration'] ?? 0) as Duration?;
|
var duration = Duration(minutes: json['duration'] ?? 0) as Duration?;
|
||||||
if (duration == const Duration()) {duration = null;};
|
// if (duration == const Duration()) {duration = null;};
|
||||||
final visited = json['visited'] as bool?;
|
final visited = json['visited'] as bool?;
|
||||||
|
var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?;
|
||||||
|
|
||||||
return Landmark(
|
return Landmark(
|
||||||
uuid: uuid, name: name, location: locationFixed, type: typeFixed, 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, tripTime: tripTime);
|
||||||
} else {
|
} else {
|
||||||
throw FormatException('Invalid JSON: $json');
|
throw FormatException('Invalid JSON: $json');
|
||||||
}
|
}
|
||||||
@ -81,7 +90,8 @@ final class Landmark extends LinkedListEntry<Landmark>{
|
|||||||
'image_url': imageURL,
|
'image_url': imageURL,
|
||||||
'description': description,
|
'description': description,
|
||||||
'duration': duration?.inMinutes,
|
'duration': duration?.inMinutes,
|
||||||
'visited': visited
|
'visited': visited,
|
||||||
|
'trip_time': tripTime?.inMinutes,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,46 +0,0 @@
|
|||||||
// import "package:anyway/structs/landmark.dart";
|
|
||||||
|
|
||||||
// class Linked<Landmark> {
|
|
||||||
// Landmark? head;
|
|
||||||
|
|
||||||
// Linked();
|
|
||||||
|
|
||||||
// // class methods
|
|
||||||
// bool get isEmpty => head == null;
|
|
||||||
|
|
||||||
// // Add a new node to the end of the list
|
|
||||||
// void add(Landmark value) {
|
|
||||||
// if (isEmpty) {
|
|
||||||
// // If the list is empty, set the new node as the head
|
|
||||||
// head = value;
|
|
||||||
// } else {
|
|
||||||
// Landmark? current = head;
|
|
||||||
// while (current!.next != null) {
|
|
||||||
// // Traverse the list to find the last node
|
|
||||||
// current = current.next;
|
|
||||||
// }
|
|
||||||
// current.next = value; // Set the new node as the next node of the last node
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// // Remove the first node with the given value
|
|
||||||
// void remove(Landmark value) {
|
|
||||||
// if (isEmpty) return;
|
|
||||||
|
|
||||||
// // If the value is in the head node, update the head to the next node
|
|
||||||
// if (head! == value) {
|
|
||||||
// head = head.next;
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// var current = head;
|
|
||||||
// while (current!.next != null) {
|
|
||||||
// if (current.next! == value) {
|
|
||||||
// // If the value is found in the next node, skip the next node
|
|
||||||
// current.next = current.next.next;
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// current = current.next;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
@ -16,12 +16,16 @@ class Trip with ChangeNotifier {
|
|||||||
// could be empty as well
|
// could be empty as well
|
||||||
|
|
||||||
Future<String> get cityName async {
|
Future<String> get cityName async {
|
||||||
|
List<double>? location = landmarks.firstOrNull?.location;
|
||||||
if (GeocodingPlatform.instance == null) {
|
if (GeocodingPlatform.instance == null) {
|
||||||
return '${landmarks.first.location[0]}, ${landmarks.first.location[1]}';
|
return '$location';
|
||||||
}
|
} else if (location == null) {
|
||||||
List<Placemark> placemarks = await placemarkFromCoordinates(landmarks.first.location[0], landmarks.first.location[1]);
|
return 'Unknown';
|
||||||
|
} else{
|
||||||
|
List<Placemark> placemarks = await placemarkFromCoordinates(location[0], location[1]);
|
||||||
return placemarks.first.locality ?? 'Unknown';
|
return placemarks.first.locality ?? 'Unknown';
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
Trip({
|
Trip({
|
||||||
@ -56,6 +60,11 @@ class Trip with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void removeLandmark(Landmark landmark) {
|
||||||
|
landmarks.remove(landmark);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
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!);
|
||||||
|
@ -57,6 +57,13 @@ fetchTrip(
|
|||||||
// only fill in the trip "meta" data for now
|
// only fill in the trip "meta" data for now
|
||||||
trip.loadFromJson(json);
|
trip.loadFromJson(json);
|
||||||
|
|
||||||
|
|
||||||
|
// now fill the trip with landmarks
|
||||||
|
// if (trip.landmarks.isNotEmpty) {
|
||||||
|
// trip.landmarks.clear();
|
||||||
|
// }
|
||||||
|
// we are going to recreate all the landmarks from the information given by the api
|
||||||
|
trip.landmarks.remove(trip.landmarks.first);
|
||||||
String? nextUUID = json["first_landmark_uuid"];
|
String? nextUUID = json["first_landmark_uuid"];
|
||||||
while (nextUUID != null) {
|
while (nextUUID != null) {
|
||||||
var (landmark, newUUID) = await fetchLandmark(nextUUID);
|
var (landmark, newUUID) = await fetchLandmark(nextUUID);
|
||||||
|
@ -1,14 +1,6 @@
|
|||||||
# Generated by pub
|
# Generated by pub
|
||||||
# See https://dart.dev/tools/pub/glossary#lockfile
|
# See https://dart.dev/tools/pub/glossary#lockfile
|
||||||
packages:
|
packages:
|
||||||
args:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: args
|
|
||||||
sha256: "7cf60b9f0cc88203c5a190b4cd62a99feea42759a7fa695010eb5de1c0b2252a"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.5.0"
|
|
||||||
async:
|
async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -17,6 +9,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.11.0"
|
version: "2.11.0"
|
||||||
|
auto_size_text:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: auto_size_text
|
||||||
|
sha256: "3f5261cd3fb5f2a9ab4e2fc3fba84fd9fcaac8821f20a1d4e71f557521b22599"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.0"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -174,14 +174,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.0.21"
|
version: "2.0.21"
|
||||||
flutter_svg:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: flutter_svg
|
|
||||||
sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "2.0.10+1"
|
|
||||||
flutter_test:
|
flutter_test:
|
||||||
dependency: "direct dev"
|
dependency: "direct dev"
|
||||||
description: flutter
|
description: flutter
|
||||||
@ -352,6 +344,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.12.0"
|
version: "1.12.0"
|
||||||
|
nested:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: nested
|
||||||
|
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.0"
|
||||||
octo_image:
|
octo_image:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -368,14 +368,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.9.0"
|
version: "1.9.0"
|
||||||
path_parsing:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: path_parsing
|
|
||||||
sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.1"
|
|
||||||
path_provider:
|
path_provider:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -424,14 +416,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.3.0"
|
version: "2.3.0"
|
||||||
petitparser:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: petitparser
|
|
||||||
sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.0.2"
|
|
||||||
platform:
|
platform:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -448,6 +432,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.8"
|
version: "2.1.8"
|
||||||
|
provider:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: provider
|
||||||
|
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "6.1.2"
|
||||||
rxdart:
|
rxdart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -621,14 +613,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.0"
|
version: "0.7.0"
|
||||||
the_widget_marker:
|
|
||||||
dependency: "direct main"
|
|
||||||
description:
|
|
||||||
name: the_widget_marker
|
|
||||||
sha256: "2476ae6b1fe29bbffa3596546871bd26f724c223ea7da74775801d9b70d64811"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.0.0"
|
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -645,30 +629,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "4.4.2"
|
version: "4.4.2"
|
||||||
vector_graphics:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_graphics
|
|
||||||
sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.11+1"
|
|
||||||
vector_graphics_codec:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_graphics_codec
|
|
||||||
sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.11+1"
|
|
||||||
vector_graphics_compiler:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: vector_graphics_compiler
|
|
||||||
sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81"
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "1.1.11+1"
|
|
||||||
vector_math:
|
vector_math:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -693,6 +653,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.5.1"
|
version: "0.5.1"
|
||||||
|
widget_to_marker:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: widget_to_marker
|
||||||
|
sha256: badc36f23c76f3ca9d43d7780058096be774adf0f661bdb6eb6f6b893f648ab9
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "1.0.6"
|
||||||
xdg_directories:
|
xdg_directories:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@ -701,14 +669,6 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.0.4"
|
version: "1.0.4"
|
||||||
xml:
|
|
||||||
dependency: transitive
|
|
||||||
description:
|
|
||||||
name: xml
|
|
||||||
sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226
|
|
||||||
url: "https://pub.dev"
|
|
||||||
source: hosted
|
|
||||||
version: "6.5.0"
|
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.4.0 <4.0.0"
|
dart: ">=3.4.0 <4.0.0"
|
||||||
flutter: ">=3.22.0"
|
flutter: ">=3.22.0"
|
||||||
|
@ -40,9 +40,11 @@ dependencies:
|
|||||||
shared_preferences: ^2.2.3
|
shared_preferences: ^2.2.3
|
||||||
dio: ^5.5.0+1
|
dio: ^5.5.0+1
|
||||||
google_maps_flutter: ^2.7.0
|
google_maps_flutter: ^2.7.0
|
||||||
the_widget_marker: ^1.0.0
|
|
||||||
cached_network_image: ^3.4.0
|
cached_network_image: ^3.4.0
|
||||||
geocoding: ^3.0.0
|
geocoding: ^3.0.0
|
||||||
|
widget_to_marker: ^1.0.6
|
||||||
|
provider: ^6.1.2
|
||||||
|
auto_size_text: ^3.0.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user