overhaul using a trip struct that notifies its ui dependencies
This commit is contained in:
@@ -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)
|
||||
)
|
||||
);
|
||||
},
|
||||
|
Reference in New Issue
Block a user