more pleasant progress handling, although somewhat flawed
This commit is contained in:
parent
aed407e2d0
commit
8f6dfd404d
@ -7,14 +7,11 @@ import 'package:anyway/structs/landmark.dart';
|
|||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
|
||||||
|
|
||||||
|
// Returns a list of widgets that represent the landmarks matching the given selector
|
||||||
List<Widget> landmarksList(Trip trip) {
|
List<Widget> landmarksList(Trip trip, {required bool Function(Landmark) selector}) {
|
||||||
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
|
||||||
|
|
||||||
List<Widget> children = [];
|
List<Widget> children = [];
|
||||||
|
|
||||||
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
|
||||||
|
|
||||||
if (trip.landmarks.isEmpty || trip.landmarks.length <= 1 && trip.landmarks.first.type == typeStart ) {
|
if (trip.landmarks.isEmpty || trip.landmarks.length <= 1 && trip.landmarks.first.type == typeStart ) {
|
||||||
children.add(
|
children.add(
|
||||||
const Text("No landmarks in this trip"),
|
const Text("No landmarks in this trip"),
|
||||||
@ -23,16 +20,18 @@ List<Widget> landmarksList(Trip trip) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (Landmark landmark in trip.landmarks) {
|
for (Landmark landmark in trip.landmarks) {
|
||||||
|
if (selector(landmark)) {
|
||||||
children.add(
|
children.add(
|
||||||
LandmarkCard(landmark, trip),
|
LandmarkCard(landmark, trip),
|
||||||
);
|
);
|
||||||
|
|
||||||
if (landmark.next != null) {
|
if (!landmark.visited && landmark.next != null) {
|
||||||
children.add(
|
children.add(
|
||||||
StepBetweenLandmarks(current: landmark, next: landmark.next!)
|
StepBetweenLandmarks(current: landmark, next: landmark.next!)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return children;
|
return children;
|
||||||
}
|
}
|
||||||
|
@ -9,14 +9,10 @@ import 'package:google_maps_flutter/google_maps_flutter.dart';
|
|||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
import 'package:widget_to_marker/widget_to_marker.dart';
|
import 'package:widget_to_marker/widget_to_marker.dart';
|
||||||
|
|
||||||
|
|
||||||
class CurrentTripMap extends StatefulWidget {
|
class CurrentTripMap extends StatefulWidget {
|
||||||
|
|
||||||
final Trip? trip;
|
final Trip? trip;
|
||||||
|
|
||||||
CurrentTripMap({
|
CurrentTripMap({this.trip});
|
||||||
this.trip
|
|
||||||
});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<CurrentTripMap> createState() => _CurrentTripMapState();
|
State<CurrentTripMap> createState() => _CurrentTripMapState();
|
||||||
@ -30,7 +26,23 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
|
|||||||
zoom: 11.0,
|
zoom: 11.0,
|
||||||
);
|
);
|
||||||
Set<Marker> mapMarkers = <Marker>{};
|
Set<Marker> mapMarkers = <Marker>{};
|
||||||
|
Set<Polyline> mapPolylines = <Polyline>{};
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
widget.trip?.addListener(setMapMarkers);
|
||||||
|
widget.trip?.addListener(setMapRoute);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
widget.trip?.removeListener(setMapMarkers);
|
||||||
|
widget.trip?.removeListener(setMapRoute);
|
||||||
|
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
void _onMapCreated(GoogleMapController controller) async {
|
void _onMapCreated(GoogleMapController controller) async {
|
||||||
mapController = controller;
|
mapController = controller;
|
||||||
@ -40,16 +52,17 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
|
|||||||
controller.moveCamera(update);
|
controller.moveCamera(update);
|
||||||
}
|
}
|
||||||
setMapMarkers();
|
setMapMarkers();
|
||||||
|
setMapRoute();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onCameraIdle() {
|
void _onCameraIdle() {
|
||||||
// print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0)));
|
// print(mapController.getLatLng(ScreenCoordinate(x: 0, y: 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void setMapMarkers() async {
|
void setMapMarkers() async {
|
||||||
List<Landmark> landmarks = widget.trip?.landmarks.toList() ?? [];
|
List<Landmark> landmarks = widget.trip?.landmarks.toList() ?? [];
|
||||||
Set<Marker> newMarkers = <Marker>{};
|
Set<Marker> markers = <Marker>{};
|
||||||
|
|
||||||
for (int i = 0; i < landmarks.length; i++) {
|
for (int i = 0; i < landmarks.length; i++) {
|
||||||
Landmark landmark = landmarks[i];
|
Landmark landmark = landmarks[i];
|
||||||
List<double> location = landmark.location;
|
List<double> location = landmark.location;
|
||||||
@ -58,20 +71,47 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
|
|||||||
position: LatLng(location[0], location[1]),
|
position: LatLng(location[0], location[1]),
|
||||||
icon: await ThemedMarker(landmark: landmark, position: i).toBitmapDescriptor(
|
icon: await ThemedMarker(landmark: landmark, position: i).toBitmapDescriptor(
|
||||||
logicalSize: const Size(150, 150),
|
logicalSize: const Size(150, 150),
|
||||||
imageSize: const Size(150, 150)
|
imageSize: const Size(150, 150),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
newMarkers.add(marker);
|
markers.add(marker);
|
||||||
}
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
mapMarkers = newMarkers;
|
mapMarkers = markers;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setMapRoute() async {
|
||||||
|
List<Landmark> landmarks = widget.trip?.landmarks.toList() ?? [];
|
||||||
|
Set<Polyline> polyLines = <Polyline>{};
|
||||||
|
|
||||||
|
if (landmarks.length < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (Landmark landmark in landmarks) {
|
||||||
|
if (landmark.next != null) {
|
||||||
|
List<LatLng> step = [
|
||||||
|
LatLng(landmark.location[0], landmark.location[1]),
|
||||||
|
LatLng(landmark.next!.location[0], landmark.next!.location[1])
|
||||||
|
];
|
||||||
|
Polyline stepLine = Polyline(
|
||||||
|
polylineId: PolylineId('step-${landmark.uuid}'),
|
||||||
|
points: step,
|
||||||
|
color: landmark.visited ? Colors.grey : PRIMARY_COLOR,
|
||||||
|
width: 5,
|
||||||
|
);
|
||||||
|
polyLines.add(stepLine);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
mapPolylines = polyLines;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
widget.trip?.addListener(setMapMarkers);
|
|
||||||
Future<SharedPreferences> preferences = SharedPreferences.getInstance();
|
Future<SharedPreferences> preferences = SharedPreferences.getInstance();
|
||||||
|
|
||||||
return FutureBuilder(
|
return FutureBuilder(
|
||||||
@ -84,7 +124,7 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
|
|||||||
} else {
|
} else {
|
||||||
return const CircularProgressIndicator();
|
return const CircularProgressIndicator();
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,8 +133,8 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
|
|||||||
onMapCreated: _onMapCreated,
|
onMapCreated: _onMapCreated,
|
||||||
initialCameraPosition: _cameraPosition,
|
initialCameraPosition: _cameraPosition,
|
||||||
onCameraIdle: _onCameraIdle,
|
onCameraIdle: _onCameraIdle,
|
||||||
// onLongPress: ,
|
|
||||||
markers: mapMarkers,
|
markers: mapMarkers,
|
||||||
|
polylines: mapPolylines,
|
||||||
cloudMapId: MAP_ID,
|
cloudMapId: MAP_ID,
|
||||||
mapToolbarEnabled: false,
|
mapToolbarEnabled: false,
|
||||||
zoomControlsEnabled: false,
|
zoomControlsEnabled: false,
|
||||||
@ -102,5 +142,4 @@ class _CurrentTripMapState extends State<CurrentTripMap> {
|
|||||||
myLocationButtonEnabled: false,
|
myLocationButtonEnabled: false,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
import 'package:anyway/modules/current_trip_error_message.dart';
|
import 'package:anyway/modules/current_trip_error_message.dart';
|
||||||
import 'package:anyway/modules/current_trip_loading_indicator.dart';
|
import 'package:anyway/modules/current_trip_loading_indicator.dart';
|
||||||
|
import 'package:anyway/structs/landmark.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
@ -63,13 +64,40 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
|
|||||||
child: CurrentTripGreeter(trip: widget.trip),
|
child: CurrentTripGreeter(trip: widget.trip),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
Padding(
|
||||||
|
padding: EdgeInsets.all(10),
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.grey[100],
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
CurrentTripSummary(trip: widget.trip),
|
||||||
|
ExpansionTile(
|
||||||
|
leading: Icon(Icons.location_on),
|
||||||
|
title: Text('Visited Landmarks (tap to expand)'),
|
||||||
|
children: [
|
||||||
|
...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited),
|
||||||
|
],
|
||||||
|
visualDensity: VisualDensity.compact,
|
||||||
|
collapsedShape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
const Padding(padding: EdgeInsets.only(top: 10)),
|
const Padding(padding: EdgeInsets.only(top: 10)),
|
||||||
|
|
||||||
// CurrentTripSummary(trip: widget.trip),
|
// upcoming landmarks
|
||||||
|
...landmarksList(widget.trip, selector: (Landmark landmark) => landmark.visited == false),
|
||||||
// const Divider(),
|
|
||||||
|
|
||||||
...landmarksList(widget.trip),
|
|
||||||
|
|
||||||
const Padding(padding: EdgeInsets.only(top: 10)),
|
const Padding(padding: EdgeInsets.only(top: 10)),
|
||||||
|
|
||||||
|
@ -15,17 +15,27 @@ class CurrentTripSummary extends StatefulWidget {
|
|||||||
class _CurrentTripSummaryState extends State<CurrentTripSummary> {
|
class _CurrentTripSummaryState extends State<CurrentTripSummary> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 10, horizontal: 20),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text('Summary'),
|
Row(
|
||||||
// Text('Start: ${widget.trip.start}'),
|
children: [
|
||||||
// Text('End: ${widget.trip.end}'),
|
Icon(Icons.flag, size: 20),
|
||||||
Text('Total duration: ${widget.trip.totalTime}'),
|
Padding(padding: EdgeInsets.only(right: 10)),
|
||||||
Text('Total distance: ${widget.trip.totalTime}'),
|
Text('Stops: ${widget.trip.landmarks.length}', style: Theme.of(context).textTheme.bodyLarge,),
|
||||||
// Text('Fuel: ${widget.trip.fuel}'),
|
]
|
||||||
// Text('Cost: ${widget.trip.cost}'),
|
),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.hourglass_bottom_rounded, size: 20),
|
||||||
|
Padding(padding: EdgeInsets.only(right: 10)),
|
||||||
|
Text('Duration: ${widget.trip.totalTime} minutes', style: Theme.of(context).textTheme.bodyLarge,),
|
||||||
|
]
|
||||||
|
),
|
||||||
],
|
],
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:anyway/constants.dart';
|
||||||
import 'package:anyway/main.dart';
|
import 'package:anyway/main.dart';
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -31,108 +32,151 @@ class _LandmarkCardState extends State<LandmarkCard> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
// else:
|
|
||||||
return Container(
|
return Container(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minHeight: 50,
|
||||||
|
maxHeight: 200,
|
||||||
|
),
|
||||||
child: Card(
|
child: Card(
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(15.0),
|
borderRadius: BorderRadius.circular(15.0),
|
||||||
),
|
),
|
||||||
elevation: 5,
|
elevation: 5,
|
||||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||||
// if the image is available, display it on the left side of the card, otherwise only display the text
|
|
||||||
child: widget.landmark.imageURL != null ? splitLayout() : textLayout(),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget splitLayout() {
|
// if the image is available, display it on the left side of the card, otherwise only display the text
|
||||||
// If an image is available, display it on the left side of the card
|
child: Row(
|
||||||
return Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
// Image and landmark "type" on the left
|
||||||
// the image on the left
|
AspectRatio(
|
||||||
width: 160,
|
aspectRatio: 3 / 4,
|
||||||
height: 160,
|
child: Column(
|
||||||
|
children: [
|
||||||
|
if (widget.landmark.imageURL != null && widget.landmark.imageURL!.isNotEmpty)
|
||||||
|
Expanded(
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: widget.landmark.imageURL ?? '',
|
imageUrl: widget.landmark.imageURL!,
|
||||||
placeholder: (context, url) => Center(child: CircularProgressIndicator()),
|
placeholder: (context, url) => Center(child: CircularProgressIndicator()),
|
||||||
errorWidget: (context, error, stackTrace) => Icon(Icons.question_mark_outlined),
|
errorWidget: (context, error, stackTrace) => Icon(Icons.question_mark_outlined),
|
||||||
fit: BoxFit.cover,
|
fit: BoxFit.cover,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else
|
||||||
|
Expanded(
|
||||||
|
child:
|
||||||
|
Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
colors: [GRADIENT_START, GRADIENT_END],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Center(
|
||||||
|
child: Icon(widget.landmark.type.icon.icon, size: 50),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Flexible(
|
|
||||||
child: textLayout(),
|
|
||||||
),
|
),
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget textLayout() {
|
Container(
|
||||||
return Padding(
|
color: PRIMARY_COLOR,
|
||||||
padding: EdgeInsets.all(10),
|
child: Center(
|
||||||
child: Column(
|
child: Padding(
|
||||||
|
padding: EdgeInsets.all(5),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
spacing: 5,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Icon(widget.landmark.type.icon.icon, size: 16),
|
||||||
children: [
|
Text(widget.landmark.type.name, style: TextStyle(fontWeight: FontWeight.bold)),
|
||||||
Flexible(
|
],
|
||||||
child: Text(
|
)
|
||||||
widget.landmark.name,
|
)
|
||||||
style: const TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
fontWeight: FontWeight.bold,
|
|
||||||
),
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
// Main information, useful buttons on the right
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
widget.landmark.name,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
),
|
),
|
||||||
)
|
|
||||||
],
|
|
||||||
),
|
|
||||||
if (widget.landmark.nameEN != null)
|
if (widget.landmark.nameEN != null)
|
||||||
Row(
|
Text(
|
||||||
children: [
|
|
||||||
Flexible(
|
|
||||||
child: Text(
|
|
||||||
widget.landmark.nameEN!,
|
widget.landmark.nameEN!,
|
||||||
style: const TextStyle(
|
style: Theme.of(context).textTheme.bodyMedium,
|
||||||
fontSize: 16,
|
|
||||||
),
|
|
||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
),
|
||||||
)
|
|
||||||
],
|
// fill the vspace
|
||||||
),
|
const Spacer(),
|
||||||
Padding(padding: EdgeInsets.only(top: 10)),
|
|
||||||
Align(
|
SingleChildScrollView(
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
// allows the buttons to be scrolled
|
// allows the buttons to be scrolled
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: Wrap(
|
child: Wrap(
|
||||||
spacing: 10,
|
spacing: 10,
|
||||||
// show the type, the website, and the wikipedia link as buttons/labels in a row
|
// show the type, the website, and the wikipedia link as buttons/labels in a row
|
||||||
children: [
|
children: [
|
||||||
TextButton.icon(
|
doneToggleButton(),
|
||||||
onPressed: () {},
|
// if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0)
|
||||||
icon: widget.landmark.type.icon,
|
// TextButton.icon(
|
||||||
label: Text(widget.landmark.type.name),
|
// onPressed: () {},
|
||||||
),
|
// icon: Icon(Icons.hourglass_bottom),
|
||||||
if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0)
|
// label: Text('${widget.landmark.duration!.inMinutes} minutes'),
|
||||||
TextButton.icon(
|
// ),
|
||||||
onPressed: () {},
|
|
||||||
icon: Icon(Icons.hourglass_bottom),
|
|
||||||
label: Text('${widget.landmark.duration!.inMinutes} minutes'),
|
|
||||||
),
|
|
||||||
if (widget.landmark.websiteURL != null)
|
if (widget.landmark.websiteURL != null)
|
||||||
TextButton.icon(
|
websiteButton(),
|
||||||
|
|
||||||
|
optionsButton()
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget doneToggleButton() {
|
||||||
|
return TextButton.icon(
|
||||||
|
onPressed: () async {
|
||||||
|
widget.landmark.visited = !widget.landmark.visited;
|
||||||
|
widget.parentTrip.notifyUpdate();
|
||||||
|
},
|
||||||
|
icon: Icon(widget.landmark.visited ? Icons.undo_sharp : Icons.check),
|
||||||
|
label: Text(widget.landmark.visited ? "Add to overview" : "Done!"),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget websiteButton () => TextButton.icon(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// open a browser with the website link
|
// open a browser with the website link
|
||||||
await launchUrl(Uri.parse(widget.landmark.websiteURL!));
|
await launchUrl(Uri.parse(widget.landmark.websiteURL!));
|
||||||
},
|
},
|
||||||
icon: Icon(Icons.link),
|
icon: Icon(Icons.link),
|
||||||
label: Text('Website'),
|
label: Text('Website'),
|
||||||
),
|
);
|
||||||
PopupMenuButton(
|
|
||||||
|
Widget optionsButton () => PopupMenuButton(
|
||||||
icon: Icon(Icons.settings),
|
icon: Icon(Icons.settings),
|
||||||
style: TextButtonTheme.of(context).style,
|
style: TextButtonTheme.of(context).style,
|
||||||
itemBuilder: (context) => [
|
itemBuilder: (context) => [
|
||||||
@ -159,14 +203,5 @@ class _LandmarkCardState extends State<LandmarkCard> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
)
|
|
||||||
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,7 @@ class ThemedMarker extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: APP_GRADIENT,
|
gradient: landmark.visited ? LinearGradient(colors: [Colors.grey, Colors.white]) : APP_GRADIENT,
|
||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(color: Colors.black, width: 5),
|
border: Border.all(color: Colors.black, width: 5),
|
||||||
),
|
),
|
||||||
|
@ -27,7 +27,7 @@ final class Landmark extends LinkedListEntry<Landmark>{
|
|||||||
String? imageURL; // not final because it can be patched
|
String? imageURL; // not final because it can be patched
|
||||||
final String? description;
|
final String? description;
|
||||||
final Duration? duration;
|
final Duration? duration;
|
||||||
final bool? visited;
|
bool visited;
|
||||||
|
|
||||||
// Next node
|
// Next node
|
||||||
// final Landmark? next;
|
// final Landmark? next;
|
||||||
@ -46,7 +46,7 @@ final class Landmark extends LinkedListEntry<Landmark>{
|
|||||||
this.imageURL,
|
this.imageURL,
|
||||||
this.description,
|
this.description,
|
||||||
this.duration,
|
this.duration,
|
||||||
this.visited,
|
this.visited = false,
|
||||||
|
|
||||||
// this.next,
|
// this.next,
|
||||||
this.tripTime,
|
this.tripTime,
|
||||||
@ -71,7 +71,7 @@ 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?;
|
||||||
final visited = json['visited'] as bool?;
|
final visited = json['visited'] ?? false as bool;
|
||||||
var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?;
|
var tripTime = Duration(minutes: json['time_to_reach_next'] ?? 0) as Duration?;
|
||||||
|
|
||||||
return Landmark(
|
return Landmark(
|
||||||
|
@ -52,6 +52,7 @@ class Trip with ChangeNotifier {
|
|||||||
totalTime = json['total_time'];
|
totalTime = json['total_time'];
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
void addLandmark(Landmark landmark) {
|
void addLandmark(Landmark landmark) {
|
||||||
landmarks.add(landmark);
|
landmarks.add(landmark);
|
||||||
notifyListeners();
|
notifyListeners();
|
||||||
@ -72,6 +73,10 @@ class Trip with ChangeNotifier {
|
|||||||
notifyListeners();
|
notifyListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void notifyUpdate(){
|
||||||
|
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!);
|
||||||
@ -80,7 +85,6 @@ class Trip with ChangeNotifier {
|
|||||||
log('Loading trip $uuid with first landmark $firstUUID');
|
log('Loading trip $uuid with first landmark $firstUUID');
|
||||||
LinkedList<Landmark> landmarks = readLandmarks(prefs, firstUUID);
|
LinkedList<Landmark> landmarks = readLandmarks(prefs, firstUUID);
|
||||||
trip.landmarks = landmarks;
|
trip.landmarks = landmarks;
|
||||||
// notifyListeners();
|
|
||||||
return trip;
|
return trip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user