better visual coherence
This commit is contained in:
parent
d323194ea7
commit
88b825ea31
@ -13,6 +13,11 @@ const Color GRADIENT_END = Color(0xFFE72E77);
|
|||||||
|
|
||||||
const Color PRIMARY_COLOR = Color(0xFFF38F1A);
|
const Color PRIMARY_COLOR = Color(0xFFF38F1A);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const double TRIP_PANEL_MAX_HEIGHT = 0.8;
|
||||||
|
const double TRIP_PANEL_MIN_HEIGHT = 0.12;
|
||||||
|
|
||||||
ThemeData APP_THEME = ThemeData(
|
ThemeData APP_THEME = ThemeData(
|
||||||
primaryColor: PRIMARY_COLOR,
|
primaryColor: PRIMARY_COLOR,
|
||||||
|
|
||||||
@ -33,20 +38,43 @@ ThemeData APP_THEME = ThemeData(
|
|||||||
),
|
),
|
||||||
|
|
||||||
|
|
||||||
textButtonTheme: TextButtonThemeData(
|
textButtonTheme: const TextButtonThemeData(
|
||||||
|
style: ButtonStyle(
|
||||||
style: TextButton.styleFrom(
|
foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR),
|
||||||
backgroundColor: PRIMARY_COLOR,
|
side: WidgetStatePropertyAll(
|
||||||
textStyle: TextStyle(
|
BorderSide(
|
||||||
color: Colors.red
|
color: PRIMARY_COLOR,
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
),
|
|
||||||
buttonTheme: ButtonThemeData(
|
elevatedButtonTheme: const ElevatedButtonThemeData(
|
||||||
buttonColor: PRIMARY_COLOR,
|
style: ButtonStyle(
|
||||||
textTheme: ButtonTextTheme.primary,
|
foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR),
|
||||||
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
|
outlinedButtonTheme: const OutlinedButtonThemeData(
|
||||||
|
style: ButtonStyle(
|
||||||
|
foregroundColor: WidgetStatePropertyAll(PRIMARY_COLOR),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
|
cardTheme: const CardTheme(
|
||||||
|
shadowColor: Colors.grey,
|
||||||
|
elevation: 2,
|
||||||
|
margin: EdgeInsets.all(10),
|
||||||
|
),
|
||||||
|
|
||||||
|
sliderTheme: const SliderThemeData(
|
||||||
|
trackHeight: 15,
|
||||||
|
inactiveTrackColor: Colors.grey,
|
||||||
|
thumbColor: PRIMARY_COLOR,
|
||||||
|
activeTrackColor: GRADIENT_END
|
||||||
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:anyway/constants.dart';
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
|
||||||
@ -20,8 +21,12 @@ class Greeter extends StatefulWidget {
|
|||||||
class _GreeterState extends State<Greeter> {
|
class _GreeterState extends State<Greeter> {
|
||||||
|
|
||||||
Widget greeterBuilder (BuildContext context, Widget? child) {
|
Widget greeterBuilder (BuildContext context, Widget? child) {
|
||||||
ThemeData theme = Theme.of(context);
|
final Shader textGradient = APP_GRADIENT.createShader(Rect.fromLTWH(0.0, 0.0, 200.0, 70.0));
|
||||||
TextStyle greeterStyle = TextStyle(color: theme.primaryColor, fontWeight: FontWeight.bold, fontSize: 24);
|
TextStyle greeterStyle = TextStyle(
|
||||||
|
foreground: Paint()..shader = textGradient,
|
||||||
|
fontWeight: FontWeight.bold,
|
||||||
|
fontSize: 26
|
||||||
|
);
|
||||||
|
|
||||||
Widget topGreeter;
|
Widget topGreeter;
|
||||||
|
|
||||||
@ -91,26 +96,10 @@ class _GreeterState extends State<Greeter> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: topGreeter,
|
||||||
children: [
|
|
||||||
// Padding(padding: EdgeInsets.only(top: 20)),
|
|
||||||
topGreeter,
|
|
||||||
Padding(
|
|
||||||
padding: EdgeInsets.all(20),
|
|
||||||
child: bottomGreeter
|
|
||||||
),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
@ -16,7 +16,7 @@ List<Widget> landmarksList(Trip trip) {
|
|||||||
|
|
||||||
log("Trip ${trip.uuid} ${trip.landmarks.length} landmarks");
|
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(
|
children.add(
|
||||||
const Text("No landmarks in this trip"),
|
const Text("No landmarks in this trip"),
|
||||||
);
|
);
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
|
|
||||||
import 'package:anyway/constants.dart';
|
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: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';
|
||||||
|
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:anyway/structs/trip.dart';
|
||||||
import 'package:auto_size_text/auto_size_text.dart';
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -8,6 +9,13 @@ Widget saveButton(Trip trip) => ElevatedButton(
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
trip.toPrefs(prefs);
|
trip.toPrefs(prefs);
|
||||||
|
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text('Trip saved'),
|
||||||
|
duration: Duration(seconds: 2),
|
||||||
|
dismissDirection: DismissDirection.horizontal
|
||||||
|
)
|
||||||
|
);
|
||||||
},
|
},
|
||||||
child: SizedBox(
|
child: SizedBox(
|
||||||
width: 100,
|
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,
|
width: 160,
|
||||||
child: CachedNetworkImage(
|
child: CachedNetworkImage(
|
||||||
imageUrl: widget.landmark.imageURL ?? '',
|
imageUrl: widget.landmark.imageURL ?? '',
|
||||||
placeholder: (context, url) => 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),
|
||||||
// TODO: make this a switch statement to load a placeholder if null
|
// TODO: make this a switch statement to load a placeholder if null
|
||||||
// cover the whole container meaning the image will be cropped
|
// 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
|
// show the type, the website, and the wikipedia link as buttons/labels in a row
|
||||||
children: [
|
children: [
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
style: theme.iconButtonTheme.style,
|
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
icon: widget.landmark.type.icon,
|
icon: widget.landmark.type.icon,
|
||||||
label: Text(widget.landmark.type.name),
|
label: Text(widget.landmark.type.name),
|
||||||
),
|
),
|
||||||
if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0)
|
if (widget.landmark.duration != null && widget.landmark.duration!.inMinutes > 0)
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
style: theme.iconButtonTheme.style,
|
|
||||||
onPressed: () {},
|
onPressed: () {},
|
||||||
icon: Icon(Icons.hourglass_bottom),
|
icon: Icon(Icons.hourglass_bottom),
|
||||||
label: Text('${widget.landmark.duration!.inMinutes} minutes'),
|
label: Text('${widget.landmark.duration!.inMinutes} minutes'),
|
||||||
),
|
),
|
||||||
if (widget.landmark.websiteURL != null)
|
if (widget.landmark.websiteURL != null)
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
style: theme.iconButtonTheme.style,
|
|
||||||
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!));
|
||||||
@ -108,7 +105,6 @@ class _LandmarkCardState extends State<LandmarkCard> {
|
|||||||
),
|
),
|
||||||
if (widget.landmark.wikipediaURL != null)
|
if (widget.landmark.wikipediaURL != null)
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
style: theme.iconButtonTheme.style,
|
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
// open a browser with the wikipedia link
|
// open a browser with the wikipedia link
|
||||||
await launchUrl(Uri.parse(widget.landmark.wikipediaURL!));
|
await launchUrl(Uri.parse(widget.landmark.wikipediaURL!));
|
||||||
|
@ -17,21 +17,9 @@ class ThemedMarker extends StatelessWidget {
|
|||||||
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 == 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;
|
Widget? positionIndicator;
|
||||||
if (landmark.type != start && landmark.type != finish) {
|
if (landmark.type != typeStart && landmark.type != typeFinish) {
|
||||||
positionIndicator = Positioned(
|
positionIndicator = Positioned(
|
||||||
top: 0,
|
top: 0,
|
||||||
right: 0,
|
right: 0,
|
||||||
@ -56,8 +44,10 @@ class ThemedMarker extends StatelessWidget {
|
|||||||
shape: BoxShape.circle,
|
shape: BoxShape.circle,
|
||||||
border: Border.all(color: Colors.black, width: 5),
|
border: Border.all(color: Colors.black, width: 5),
|
||||||
),
|
),
|
||||||
padding: EdgeInsets.all(5),
|
width: 70,
|
||||||
child: icon
|
height: 70,
|
||||||
|
padding: const EdgeInsets.all(5),
|
||||||
|
child: Icon(landmark.type.icon.icon, size: 50),
|
||||||
),
|
),
|
||||||
if (positionIndicator != null) positionIndicator,
|
if (positionIndicator != null) positionIndicator,
|
||||||
],
|
],
|
@ -42,7 +42,7 @@ class _NewTripLocationSearchState extends State<NewTripLocationSearch> {
|
|||||||
uuid: 'pending',
|
uuid: 'pending',
|
||||||
name: query,
|
name: query,
|
||||||
location: [location.latitude, location.longitude],
|
location: [location.latitude, location.longitude],
|
||||||
type: start
|
type: typeStart
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -65,9 +65,8 @@ class _NewTripLocationSearchState extends State<NewTripLocationSearch> {
|
|||||||
|
|
||||||
|
|
||||||
late Widget useCurrentLocationButton = ElevatedButton(
|
late Widget useCurrentLocationButton = ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () async {
|
||||||
// setTripLocation(location);
|
|
||||||
// TODO: get current location
|
|
||||||
},
|
},
|
||||||
child: Text('Use current location'),
|
child: Text('Use current location'),
|
||||||
);
|
);
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:anyway/constants.dart';
|
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/landmark.dart';
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -37,7 +37,7 @@ class _NewTripMapState extends State<NewTripMap> {
|
|||||||
uuid: 'pending',
|
uuid: 'pending',
|
||||||
name: 'start',
|
name: 'start',
|
||||||
location: [location.latitude, location.longitude],
|
location: [location.latitude, location.longitude],
|
||||||
type: start
|
type: typeStart
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import 'package:anyway/modules/current_trip_save_button.dart';
|
import 'package:anyway/constants.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:sliding_up_panel/sliding_up_panel.dart';
|
import 'package:sliding_up_panel/sliding_up_panel.dart';
|
||||||
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:anyway/modules/current_trip_landmarks_list.dart';
|
|
||||||
import 'package:anyway/modules/current_trip_greeter.dart';
|
|
||||||
import 'package:anyway/modules/current_trip_map.dart';
|
import 'package:anyway/modules/current_trip_map.dart';
|
||||||
|
import 'package:anyway/modules/current_trip_panel.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -27,15 +26,20 @@ class _TripPageState extends State<TripPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SlidingUpPanel(
|
return SlidingUpPanel(
|
||||||
panelBuilder: (sc) => _panelFull(sc),
|
// use panelBuilder instead of panel so that we can reuse the scrollcontroller for the listview
|
||||||
// collapsed: _floatingCollapsed(),
|
panelBuilder: (scrollcontroller) => CurrentTripPanel(controller: scrollcontroller, trip: widget.trip),
|
||||||
|
// using collapsed and panelBuilder seems to show both at the same time, so we include the greeter in the panelBuilder
|
||||||
|
// collapsed: Greeter(trip: widget.trip),
|
||||||
body: CurrentTripMap(trip: widget.trip),
|
body: CurrentTripMap(trip: widget.trip),
|
||||||
// renderPanelSheet: false,
|
minHeight: MediaQuery.of(context).size.height * TRIP_PANEL_MIN_HEIGHT,
|
||||||
// backdropEnabled: true,
|
maxHeight: MediaQuery.of(context).size.height * TRIP_PANEL_MAX_HEIGHT,
|
||||||
maxHeight: MediaQuery.of(context).size.height * 0.8,
|
// padding in this context is annoying: it offsets the notion of vertical alignment.
|
||||||
padding: EdgeInsets.only(left: 10, right: 10, top: 25, bottom: 10),
|
// children that want to be centered vertically need to have their size adjusted by 2x the padding
|
||||||
// panelSnapping: false,
|
padding: const EdgeInsets.only(top: 10),
|
||||||
borderRadius: BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)),
|
// Panel snapping should not be disabled because it significantly improves the user experience
|
||||||
|
// panelSnapping: false
|
||||||
|
borderRadius: const BorderRadius.only(topLeft: Radius.circular(25), topRight: Radius.circular(25)),
|
||||||
|
parallaxEnabled: true,
|
||||||
boxShadow: const [
|
boxShadow: const [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
blurRadius: 20.0,
|
blurRadius: 20.0,
|
||||||
@ -44,41 +48,4 @@ class _TripPageState extends State<TripPage> {
|
|||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Widget _panelFull(ScrollController sc) {
|
|
||||||
return ListenableBuilder(
|
|
||||||
listenable: widget.trip,
|
|
||||||
builder: (context, child) {
|
|
||||||
if (widget.trip.uuid != 'pending' && widget.trip.uuid != 'error') {
|
|
||||||
return ListView(
|
|
||||||
controller: sc,
|
|
||||||
padding: EdgeInsets.only(bottom: 35),
|
|
||||||
children: [
|
|
||||||
Greeter(trip: widget.trip),
|
|
||||||
...landmarksList(widget.trip),
|
|
||||||
Padding(padding: EdgeInsets.only(top: 10)),
|
|
||||||
Center(child: saveButton(widget.trip)),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
} else if(widget.trip.uuid == 'pending') {
|
|
||||||
return Greeter(trip: widget.trip);
|
|
||||||
} else {
|
|
||||||
return Column(
|
|
||||||
children: [
|
|
||||||
const Icon(
|
|
||||||
Icons.error_outline,
|
|
||||||
color: Colors.red,
|
|
||||||
size: 60,
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.only(top: 16),
|
|
||||||
child: Text('Error: ${widget.trip.errorDescription}'),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -28,25 +28,26 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> {
|
|||||||
// child: Icon(Icons.person, size: 100),
|
// child: Icon(Icons.person, size: 100),
|
||||||
// )
|
// )
|
||||||
// ),
|
// ),
|
||||||
|
Padding(padding: EdgeInsets.only(top: 30)),
|
||||||
Center(
|
Center(
|
||||||
child: FutureBuilder(
|
child: FutureBuilder(
|
||||||
future: widget.trip.cityName,
|
future: widget.trip.cityName,
|
||||||
builder: (context, snapshot) => Text(
|
builder: (context, snapshot) => Text(
|
||||||
'New trip to ${snapshot.hasData ? snapshot.data! : "..."}',
|
'Your trip to ${snapshot.hasData ? snapshot.data! : "..."}',
|
||||||
style: TextStyle(fontSize: 24)
|
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
|
|
||||||
Divider(indent: 25, endIndent: 25, height: 50),
|
|
||||||
|
|
||||||
Center(
|
Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.only(left: 10, right: 10, top: 0, bottom: 10),
|
padding: EdgeInsets.only(left: 10, right: 10, top: 20, bottom: 0),
|
||||||
child: Text('Tell us about your ideal trip.', style: TextStyle(fontSize: 18))
|
child: Text('Tell us about your ideal trip.', style: TextStyle(fontSize: 18))
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
Divider(indent: 25, endIndent: 25, height: 50),
|
||||||
|
|
||||||
durationPicker(preferences.maxTime),
|
durationPicker(preferences.maxTime),
|
||||||
|
|
||||||
preferenceSliders([preferences.sightseeing, preferences.shopping, preferences.nature]),
|
preferenceSliders([preferences.sightseeing, preferences.shopping, preferences.nature]),
|
||||||
@ -63,7 +64,7 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> {
|
|||||||
shadowColor: Colors.grey,
|
shadowColor: Colors.grey,
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: Icon(Icons.timer),
|
leading: Icon(Icons.timer),
|
||||||
title: Text('How long should the trip be?'),
|
title: Text(preferences.maxTime.description),
|
||||||
subtitle: CupertinoTimerPicker(
|
subtitle: CupertinoTimerPicker(
|
||||||
mode: CupertinoTimerPickerMode.hm,
|
mode: CupertinoTimerPickerMode.hm,
|
||||||
initialTimerDuration: Duration(minutes: 90),
|
initialTimerDuration: Duration(minutes: 90),
|
||||||
@ -84,8 +85,6 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> {
|
|||||||
for (SinglePreference pref in prefs) {
|
for (SinglePreference pref in prefs) {
|
||||||
sliders.add(
|
sliders.add(
|
||||||
Card(
|
Card(
|
||||||
margin: const EdgeInsets.only(left: 10, right: 10, top: 10, bottom: 0),
|
|
||||||
shadowColor: Colors.grey,
|
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
leading: pref.icon,
|
leading: pref.icon,
|
||||||
title: Text(pref.name),
|
title: Text(pref.name),
|
||||||
|
@ -174,8 +174,8 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
Text('Our privacy policy is available under:'),
|
Text('Our privacy policy is available under:'),
|
||||||
|
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
icon: Icon(Icons.info, color: Colors.white),
|
icon: Icon(Icons.info),
|
||||||
label: Text(PRIVACY_URL, style: TextStyle(color: Colors.white)),
|
label: Text(PRIVACY_URL),
|
||||||
onPressed: () async{
|
onPressed: () async{
|
||||||
await launchUrl(Uri.parse(PRIVACY_URL));
|
await launchUrl(Uri.parse(PRIVACY_URL));
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,13 @@ import 'dart:convert';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
LandmarkType sightseeing = LandmarkType(name: 'sightseeing');
|
LandmarkType typeSightseeing = LandmarkType(name: 'sightseeing');
|
||||||
LandmarkType nature = LandmarkType(name: 'nature');
|
LandmarkType typeNature = LandmarkType(name: 'nature');
|
||||||
LandmarkType shopping = LandmarkType(name: 'shopping');
|
LandmarkType typeShopping = LandmarkType(name: 'shopping');
|
||||||
// LandmarkType museum = LandmarkType(name: 'Museum');
|
// LandmarkType museum = LandmarkType(name: 'Museum');
|
||||||
// LandmarkType restaurant = LandmarkType(name: 'Restaurant');
|
// LandmarkType restaurant = LandmarkType(name: 'Restaurant');
|
||||||
LandmarkType start = LandmarkType(name: 'start');
|
LandmarkType typeStart = LandmarkType(name: 'start');
|
||||||
LandmarkType finish = LandmarkType(name: 'finish');
|
LandmarkType typeFinish = LandmarkType(name: 'finish');
|
||||||
|
|
||||||
|
|
||||||
final class Landmark extends LinkedListEntry<Landmark>{
|
final class Landmark extends LinkedListEntry<Landmark>{
|
||||||
@ -130,22 +130,22 @@ class LandmarkType {
|
|||||||
LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) {
|
LandmarkType({required this.name, this.icon = const Icon(Icons.location_on)}) {
|
||||||
switch (name) {
|
switch (name) {
|
||||||
case 'sightseeing':
|
case 'sightseeing':
|
||||||
icon = Icon(Icons.church);
|
icon = const Icon(Icons.church);
|
||||||
break;
|
break;
|
||||||
case 'nature':
|
case 'nature':
|
||||||
icon = Icon(Icons.eco);
|
icon = const Icon(Icons.eco);
|
||||||
break;
|
break;
|
||||||
case 'shopping':
|
case 'shopping':
|
||||||
icon = Icon(Icons.shopping_cart);
|
icon = const Icon(Icons.shopping_cart);
|
||||||
break;
|
break;
|
||||||
case 'start':
|
case 'start':
|
||||||
icon = Icon(Icons.play_arrow);
|
icon = const Icon(Icons.play_arrow);
|
||||||
break;
|
break;
|
||||||
case 'finish':
|
case 'finish':
|
||||||
icon = Icon(Icons.flag);
|
icon = const Icon(Icons.flag);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
icon = Icon(Icons.location_on);
|
icon = const Icon(Icons.location_on);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@override
|
@override
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:anyway/structs/landmark.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
@ -28,27 +29,27 @@ class UserPreferences {
|
|||||||
slug: "sightseeing",
|
slug: "sightseeing",
|
||||||
description: "How much do you like sightseeing?",
|
description: "How much do you like sightseeing?",
|
||||||
value: 0,
|
value: 0,
|
||||||
icon: Icon(Icons.church),
|
icon: typeSightseeing.icon,
|
||||||
);
|
);
|
||||||
SinglePreference shopping = SinglePreference(
|
SinglePreference shopping = SinglePreference(
|
||||||
name: "Shopping",
|
name: "Shopping",
|
||||||
slug: "shopping",
|
slug: "shopping",
|
||||||
description: "How much do you like shopping?",
|
description: "How much do you like shopping?",
|
||||||
value: 0,
|
value: 0,
|
||||||
icon: Icon(Icons.shopping_bag),
|
icon: typeShopping.icon,
|
||||||
);
|
);
|
||||||
SinglePreference nature = SinglePreference(
|
SinglePreference nature = SinglePreference(
|
||||||
name: "Nature",
|
name: "Nature",
|
||||||
slug: "nature",
|
slug: "nature",
|
||||||
description: "How much do you like nature?",
|
description: "How much do you like nature?",
|
||||||
value: 0,
|
value: 0,
|
||||||
icon: Icon(Icons.landscape),
|
icon: typeNature.icon,
|
||||||
);
|
);
|
||||||
|
|
||||||
SinglePreference maxTime = SinglePreference(
|
SinglePreference maxTime = SinglePreference(
|
||||||
name: "Trip duration",
|
name: "Trip duration",
|
||||||
slug: "duration",
|
slug: "duration",
|
||||||
description: "How long do you want your trip to be?",
|
description: "How long should your trip be?",
|
||||||
value: 30,
|
value: 30,
|
||||||
minVal: 30,
|
minVal: 30,
|
||||||
maxVal: 720,
|
maxVal: 720,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user