better visual coherence
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:anyway/constants.dart';
|
||||
import 'package:anyway/structs/trip.dart';
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
|
||||
@@ -20,8 +21,12 @@ class Greeter extends StatefulWidget {
|
||||
class _GreeterState extends State<Greeter> {
|
||||
|
||||
Widget greeterBuilder (BuildContext context, Widget? child) {
|
||||
ThemeData theme = Theme.of(context);
|
||||
TextStyle greeterStyle = TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24);
|
||||
final Shader textGradient = APP_GRADIENT.createShader(Rect.fromLTWH(0.0, 0.0, 200.0, 70.0));
|
||||
TextStyle greeterStyle = TextStyle(
|
||||
foreground: Paint()..shader = textGradient,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 26
|
||||
);
|
||||
|
||||
Widget topGreeter;
|
||||
|
||||
@@ -91,26 +96,10 @@ class _GreeterState extends State<Greeter> {
|
||||
}
|
||||
|
||||
return Center(
|
||||
child: Column(
|
||||
children: [
|
||||
// Padding(padding: EdgeInsets.only(top: 20)),
|
||||
topGreeter,
|
||||
Padding(
|
||||
padding: EdgeInsets.all(20),
|
||||
child: bottomGreeter
|
||||
),
|
||||
],
|
||||
)
|
||||
child: topGreeter,
|
||||
);
|
||||
}
|
||||
|
||||
Widget bottomGreeter = const Text(
|
||||
"Busy day ahead? Here is how to make the most of it!",
|
||||
style: TextStyle(color: Colors.black, fontSize: 18),
|
||||
textAlign: TextAlign.center,
|
||||
);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
@@ -16,7 +16,7 @@ List<Widget> landmarksList(Trip trip) {
|
||||
|
||||
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
||||
|
||||
if (trip.landmarks.isEmpty || trip.landmarks.length <= 1 && trip.landmarks.first.type == start ) {
|
||||
if (trip.landmarks.isEmpty || trip.landmarks.length <= 1 && trip.landmarks.first.type == typeStart ) {
|
||||
children.add(
|
||||
const Text("No landmarks in this trip"),
|
||||
);
|
||||
|
@@ -1,7 +1,7 @@
|
||||
import 'dart:collection';
|
||||
|
||||
import 'package:anyway/constants.dart';
|
||||
import 'package:anyway/modules/themed_marker.dart';
|
||||
import 'package:anyway/modules/landmark_map_marker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:anyway/structs/landmark.dart';
|
||||
import 'package:anyway/structs/trip.dart';
|
||||
|
82
frontend/lib/modules/current_trip_panel.dart
Normal file
82
frontend/lib/modules/current_trip_panel.dart
Normal file
@@ -0,0 +1,82 @@
|
||||
import 'package:anyway/constants.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:anyway/structs/trip.dart';
|
||||
import 'package:anyway/modules/current_trip_summary.dart';
|
||||
import 'package:anyway/modules/current_trip_save_button.dart';
|
||||
import 'package:anyway/modules/current_trip_landmarks_list.dart';
|
||||
import 'package:anyway/modules/current_trip_greeter.dart';
|
||||
|
||||
|
||||
class CurrentTripPanel extends StatefulWidget {
|
||||
final ScrollController controller;
|
||||
final Trip trip;
|
||||
|
||||
const CurrentTripPanel({
|
||||
super.key,
|
||||
required this.controller,
|
||||
required this.trip,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CurrentTripPanel> createState() => _CurrentTripPanelState();
|
||||
}
|
||||
|
||||
class _CurrentTripPanelState extends State<CurrentTripPanel> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ListenableBuilder(
|
||||
listenable: widget.trip,
|
||||
builder: (context, child) {
|
||||
if (widget.trip.uuid != 'pending' && widget.trip.uuid != 'error') {
|
||||
return ListView(
|
||||
controller: widget.controller,
|
||||
padding: const EdgeInsets.only(bottom: 30, left: 5, right: 5),
|
||||
children: [
|
||||
SizedBox(
|
||||
// reuse the exact same height as the panel has when collapsed
|
||||
// this way the greeter will be centered when the panel is collapsed
|
||||
height: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT - 20,
|
||||
child: Greeter(trip: widget.trip),
|
||||
),
|
||||
|
||||
const Padding(padding: EdgeInsets.only(top: 10)),
|
||||
|
||||
// CurrentTripSummary(trip: widget.trip),
|
||||
|
||||
// const Divider(),
|
||||
|
||||
...landmarksList(widget.trip),
|
||||
|
||||
const Padding(padding: EdgeInsets.only(top: 10)),
|
||||
|
||||
Center(child: saveButton(widget.trip)),
|
||||
],
|
||||
);
|
||||
} else if(widget.trip.uuid == 'pending') {
|
||||
return SizedBox(
|
||||
// reuse the exact same height as the panel has when collapsed
|
||||
// this way the greeter will be centered when the panel is collapsed
|
||||
height: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT - 20,
|
||||
child: Greeter(trip: widget.trip)
|
||||
);
|
||||
} else {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.error_outline,
|
||||
color: Colors.red,
|
||||
size: 50,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 10),
|
||||
child: Text('Error: ${widget.trip.errorDescription}'),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
@@ -1,4 +1,5 @@
|
||||
|
||||
import 'package:anyway/main.dart';
|
||||
import 'package:anyway/structs/trip.dart';
|
||||
import 'package:auto_size_text/auto_size_text.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -8,6 +9,13 @@ Widget saveButton(Trip trip) => ElevatedButton(
|
||||
onPressed: () async {
|
||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||
trip.toPrefs(prefs);
|
||||
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text('Trip saved'),
|
||||
duration: Duration(seconds: 2),
|
||||
dismissDirection: DismissDirection.horizontal
|
||||
)
|
||||
);
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 100,
|
||||
|
31
frontend/lib/modules/current_trip_summary.dart
Normal file
31
frontend/lib/modules/current_trip_summary.dart
Normal file
@@ -0,0 +1,31 @@
|
||||
import 'package:anyway/structs/trip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CurrentTripSummary extends StatefulWidget {
|
||||
final Trip trip;
|
||||
const CurrentTripSummary({
|
||||
super.key,
|
||||
required this.trip,
|
||||
});
|
||||
|
||||
@override
|
||||
State<CurrentTripSummary> createState() => _CurrentTripSummaryState();
|
||||
}
|
||||
|
||||
class _CurrentTripSummaryState extends State<CurrentTripSummary> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Text('Summary'),
|
||||
// Text('Start: ${widget.trip.start}'),
|
||||
// Text('End: ${widget.trip.end}'),
|
||||
Text('Total duration: ${widget.trip.totalTime}'),
|
||||
Text('Total distance: ${widget.trip.totalTime}'),
|
||||
// Text('Fuel: ${widget.trip.fuel}'),
|
||||
// Text('Cost: ${widget.trip.cost}'),
|
||||
],
|
||||
);
|
||||
|
||||
}
|
||||
}
|
@@ -36,7 +36,7 @@ class _LandmarkCardState extends State<LandmarkCard> {
|
||||
width: 160,
|
||||
child: CachedNetworkImage(
|
||||
imageUrl: widget.landmark.imageURL ?? '',
|
||||
placeholder: (context, url) => CircularProgressIndicator(),
|
||||
placeholder: (context, url) => Center(child: 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
|
||||
@@ -84,21 +84,18 @@ class _LandmarkCardState extends State<LandmarkCard> {
|
||||
// show the type, the website, and the wikipedia link as buttons/labels in a row
|
||||
children: [
|
||||
TextButton.icon(
|
||||
style: theme.iconButtonTheme.style,
|
||||
onPressed: () {},
|
||||
icon: widget.landmark.type.icon,
|
||||
label: Text(widget.landmark.type.name),
|
||||
),
|
||||
if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0)
|
||||
TextButton.icon(
|
||||
style: theme.iconButtonTheme.style,
|
||||
onPressed: () {},
|
||||
icon: Icon(Icons.hourglass_bottom),
|
||||
label: Text('${widget.landmark.duration!.inMinutes} minutes'),
|
||||
),
|
||||
if (widget.landmark.websiteURL != null)
|
||||
TextButton.icon(
|
||||
style: theme.iconButtonTheme.style,
|
||||
onPressed: () async {
|
||||
// open a browser with the website link
|
||||
await launchUrl(Uri.parse(widget.landmark.websiteURL!));
|
||||
@@ -108,7 +105,6 @@ class _LandmarkCardState extends State<LandmarkCard> {
|
||||
),
|
||||
if (widget.landmark.wikipediaURL != null)
|
||||
TextButton.icon(
|
||||
style: theme.iconButtonTheme.style,
|
||||
onPressed: () async {
|
||||
// open a browser with the wikipedia link
|
||||
await launchUrl(Uri.parse(widget.landmark.wikipediaURL!));
|
||||
|
@@ -17,21 +17,9 @@ class ThemedMarker extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
// 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
|
||||
Icon icon;
|
||||
if (landmark.type == sightseeing) {
|
||||
icon = Icon(Icons.church, color: Colors.black, size: 50);
|
||||
} else if (landmark.type == nature) {
|
||||
icon = Icon(Icons.park, color: Colors.black, size: 50);
|
||||
} else if (landmark.type == shopping) {
|
||||
icon = Icon(Icons.shopping_cart, color: Colors.black, size: 50);
|
||||
} else if (landmark.type == start || landmark.type == finish) {
|
||||
icon = Icon(Icons.flag, color: Colors.black, size: 50);
|
||||
} else {
|
||||
icon = Icon(Icons.location_on, color: Colors.black, size: 50);
|
||||
}
|
||||
|
||||
Widget? positionIndicator;
|
||||
if (landmark.type != start && landmark.type != finish) {
|
||||
if (landmark.type != typeStart && landmark.type != typeFinish) {
|
||||
positionIndicator = Positioned(
|
||||
top: 0,
|
||||
right: 0,
|
||||
@@ -56,8 +44,10 @@ class ThemedMarker extends StatelessWidget {
|
||||
shape: BoxShape.circle,
|
||||
border: Border.all(color: Colors.black, width: 5),
|
||||
),
|
||||
padding: EdgeInsets.all(5),
|
||||
child: icon
|
||||
width: 70,
|
||||
height: 70,
|
||||
padding: const EdgeInsets.all(5),
|
||||
child: Icon(landmark.type.icon.icon, size: 50),
|
||||
),
|
||||
if (positionIndicator != null) positionIndicator,
|
||||
],
|
@@ -42,7 +42,7 @@ class _NewTripLocationSearchState extends State<NewTripLocationSearch> {
|
||||
uuid: 'pending',
|
||||
name: query,
|
||||
location: [location.latitude, location.longitude],
|
||||
type: start
|
||||
type: typeStart
|
||||
)
|
||||
);
|
||||
}
|
||||
@@ -65,9 +65,8 @@ class _NewTripLocationSearchState extends State<NewTripLocationSearch> {
|
||||
|
||||
|
||||
late Widget useCurrentLocationButton = ElevatedButton(
|
||||
onPressed: () {
|
||||
// setTripLocation(location);
|
||||
// TODO: get current location
|
||||
onPressed: () async {
|
||||
|
||||
},
|
||||
child: Text('Use current location'),
|
||||
);
|
||||
|
@@ -2,7 +2,7 @@
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:anyway/constants.dart';
|
||||
import 'package:anyway/modules/themed_marker.dart';
|
||||
import 'package:anyway/modules/landmark_map_marker.dart';
|
||||
import 'package:anyway/structs/landmark.dart';
|
||||
import 'package:anyway/structs/trip.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -37,7 +37,7 @@ class _NewTripMapState extends State<NewTripMap> {
|
||||
uuid: 'pending',
|
||||
name: 'start',
|
||||
location: [location.latitude, location.longitude],
|
||||
type: start
|
||||
type: typeStart
|
||||
)
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user