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'; class LandmarksOverview extends StatefulWidget { final Trip? trip; const LandmarksOverview({super.key, this.trip}); @override State createState() => _LandmarksOverviewState(); } class _LandmarksOverviewState extends State { // final Future> _landmarks = fetchLandmarks(); @override Widget build(BuildContext context) { return ListenableBuilder(//> listenable: widget.trip!, builder: (BuildContext context, Widget? child) { Trip trip = widget.trip!; log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks"); List 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, size: 60, ), Padding( padding: const EdgeInsets.only(top: 16), child: Text('Error: ${trip.cityName}'), ), ]; } else { if (trip.landmarks.length <= 1) { children = [ const Text("No landmarks in this trip"), ]; } else { children = [ landmarksWithSteps(), saveButton(), ]; } } return Column( children: children, ); }, ); } Widget saveButton() => ElevatedButton( onPressed: () async { Trip? trip = await widget.trip; SharedPreferences prefs = await SharedPreferences.getInstance(); trip?.toPrefs(prefs); }, child: const Text('Save'), ); Widget landmarksWithSteps() { return ListenableBuilder( listenable: widget.trip!, builder: (BuildContext context, Widget? child) { List children = []; for (Landmark landmark in widget.trip!.landmarks) { children.add( Dismissible( key: ValueKey(landmark.hashCode), child: LandmarkCard(landmark), dismissThresholds: {DismissDirection.endToStart: 0.6}, onDismissed: (direction) { // Remove the item from the data source. log(landmark.name); setState(() { widget.trip!.removeLandmark(landmark); }); // Then show a snackbar. ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text("We won't show ${landmark.name} again"))); }, background: Container(color: Colors.red), secondaryBackground: Container( color: Colors.red, child: Icon( Icons.delete, color: Colors.white, ), padding: EdgeInsets.all(15), alignment: Alignment.centerRight, ), ) ); if (landmark.next != null) { Widget step = stepBetweenLandmarks(landmark, landmark.next!); children.add(step); } } return Column( children: children ); }, ); } } Widget stepBetweenLandmarks(Landmark current, Landmark next) { // 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 // 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( margin: EdgeInsets.all(10), padding: EdgeInsets.all(10), decoration: BoxDecoration( border: Border( left: BorderSide(width: 3.0, color: Colors.black), ), // gradient: LinearGradient( // begin: Alignment.topLeft, // end: Alignment.bottomRight, // colors: [Colors.grey, Colors.white, Colors.white], // ), ), child: Row( children: [ Column( children: [ Icon(Icons.directions_walk), Text("~$timeRounded min", style: TextStyle(fontSize: 10)), ], ), Spacer(), ElevatedButton( onPressed: () { // Open navigation instructions }, child: Row( children: [ Icon(Icons.directions), Text("Directions"), ], ), ) ], ), ); }