better help and onboarding
All checks were successful
All checks were successful
This commit is contained in:
parent
d58ef2562d
commit
3f1fe463bf
@ -1,6 +1,6 @@
|
|||||||
|
import 'package:anyway/utils/get_first_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
import 'package:anyway/layout.dart';
|
|
||||||
|
|
||||||
void main() => runApp(const App());
|
void main() => runApp(const App());
|
||||||
|
|
||||||
@ -14,7 +14,7 @@ class App extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: APP_NAME,
|
title: APP_NAME,
|
||||||
home: BasePage(mainScreen: "map"),
|
home: getFirstPage(),
|
||||||
theme: APP_THEME,
|
theme: APP_THEME,
|
||||||
scaffoldMessengerKey: rootScaffoldMessengerKey
|
scaffoldMessengerKey: rootScaffoldMessengerKey
|
||||||
);
|
);
|
||||||
|
@ -73,7 +73,7 @@ class _CurrentTripPanelState extends State<CurrentTripPanel> {
|
|||||||
|
|
||||||
const Padding(padding: EdgeInsets.only(top: 10)),
|
const Padding(padding: EdgeInsets.only(top: 10)),
|
||||||
|
|
||||||
Center(child: saveButton(widget.trip)),
|
Center(child: saveButton(trip: widget.trip)),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,22 @@ import 'package:auto_size_text/auto_size_text.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
Widget saveButton(Trip trip) => ElevatedButton(
|
|
||||||
|
class saveButton extends StatefulWidget {
|
||||||
|
Trip trip;
|
||||||
|
saveButton({super.key, required this.trip});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<saveButton> createState() => _saveButtonState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _saveButtonState extends State<saveButton> {
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
trip.toPrefs(prefs);
|
setState(() => widget.trip.toPrefs(prefs));
|
||||||
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text('Trip saved'),
|
content: Text('Trip saved'),
|
||||||
@ -38,4 +50,6 @@ Widget saveButton(Trip trip) => ElevatedButton(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
25
frontend/lib/modules/help_dialog.dart
Normal file
25
frontend/lib/modules/help_dialog.dart
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
Future<void> helpDialog(BuildContext context, String title, String content) {
|
||||||
|
return showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return AlertDialog(
|
||||||
|
title: Text(title),
|
||||||
|
content: Text(content),
|
||||||
|
actions: <Widget>[
|
||||||
|
TextButton(
|
||||||
|
style: TextButton.styleFrom(
|
||||||
|
textStyle: Theme.of(context).textTheme.labelLarge,
|
||||||
|
),
|
||||||
|
child: const Text('Got it!'),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.of(context).pop();
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
@ -17,7 +17,6 @@ class LandmarkCard extends StatefulWidget {
|
|||||||
class _LandmarkCardState extends State<LandmarkCard> {
|
class _LandmarkCardState extends State<LandmarkCard> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
ThemeData theme = Theme.of(context);
|
|
||||||
return Container(
|
return Container(
|
||||||
height: 160,
|
height: 160,
|
||||||
child: Card(
|
child: Card(
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:anyway/layout.dart';
|
|
||||||
import 'package:anyway/main.dart';
|
import 'package:anyway/main.dart';
|
||||||
|
import 'package:anyway/pages/current_trip.dart';
|
||||||
import 'package:anyway/structs/preferences.dart';
|
import 'package:anyway/structs/preferences.dart';
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:anyway/utils/fetch_trip.dart';
|
import 'package:anyway/utils/fetch_trip.dart';
|
||||||
@ -57,7 +57,7 @@ class _NewTripButtonState extends State<NewTripButton> {
|
|||||||
fetchTrip(trip, widget.preferences);
|
fetchTrip(trip, widget.preferences);
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => BasePage(mainScreen: "map", trip: trip)
|
builder: (context) => TripPage(trip: trip)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -2,13 +2,11 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
|
||||||
class OnboardingCard extends StatelessWidget {
|
class OnboardingCard extends StatelessWidget {
|
||||||
int index;
|
final String title;
|
||||||
String title;
|
final String description;
|
||||||
String description;
|
final String imagePath;
|
||||||
String imagePath;
|
|
||||||
|
|
||||||
OnboardingCard({
|
const OnboardingCard({
|
||||||
required this.index,
|
|
||||||
required this.title,
|
required this.title,
|
||||||
required this.description,
|
required this.description,
|
||||||
required this.imagePath,
|
required this.imagePath,
|
||||||
@ -16,13 +14,8 @@ class OnboardingCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Color baseColor = Theme.of(context).colorScheme.secondary;
|
|
||||||
// have a different color for each card, incrementing the hue
|
return Padding(
|
||||||
Color currentColor = baseColor.withAlpha(baseColor.alpha - index * 30);
|
|
||||||
return Container(
|
|
||||||
color: currentColor,
|
|
||||||
alignment: Alignment.center,
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.all(20),
|
padding: EdgeInsets.all(20),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
@ -50,7 +43,6 @@ class OnboardingCard extends StatelessWidget {
|
|||||||
|
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
)
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,6 @@
|
|||||||
|
import 'package:anyway/pages/current_trip.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:anyway/layout.dart';
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
|
||||||
|
|
||||||
@ -16,7 +16,6 @@ class TripsOverview extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _TripsOverviewState extends State<TripsOverview> {
|
class _TripsOverviewState extends State<TripsOverview> {
|
||||||
|
|
||||||
Widget listBuild (BuildContext context, AsyncSnapshot<List<Trip>> snapshot) {
|
Widget listBuild (BuildContext context, AsyncSnapshot<List<Trip>> snapshot) {
|
||||||
List<Widget> children;
|
List<Widget> children;
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
@ -39,7 +38,7 @@ class _TripsOverviewState extends State<TripsOverview> {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => BasePage(mainScreen: "map", trip: trip)
|
builder: (context) => TripPage(trip: trip)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import 'package:anyway/modules/help_dialog.dart';
|
||||||
|
import 'package:anyway/pages/current_trip.dart';
|
||||||
import 'package:anyway/pages/settings.dart';
|
import 'package:anyway/pages/settings.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@ -8,22 +10,24 @@ import 'package:anyway/modules/trips_saved_list.dart';
|
|||||||
import 'package:anyway/utils/load_trips.dart';
|
import 'package:anyway/utils/load_trips.dart';
|
||||||
|
|
||||||
import 'package:anyway/pages/new_trip_location.dart';
|
import 'package:anyway/pages/new_trip_location.dart';
|
||||||
import 'package:anyway/pages/current_trip.dart';
|
|
||||||
import 'package:anyway/pages/onboarding.dart';
|
import 'package:anyway/pages/onboarding.dart';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// BasePage is the scaffold that holds all other pages
|
// BasePage is the scaffold that holds a child page and a side drawer
|
||||||
// A side drawer is used to switch between pages
|
// The side drawer is the main way to switch between pages
|
||||||
|
|
||||||
class BasePage extends StatefulWidget {
|
class BasePage extends StatefulWidget {
|
||||||
final String mainScreen;
|
final Widget mainScreen;
|
||||||
final Trip? trip;
|
final Widget title;
|
||||||
|
final List<String> helpTexts;
|
||||||
|
|
||||||
const BasePage({
|
const BasePage({
|
||||||
super.key,
|
super.key,
|
||||||
required this.mainScreen,
|
required this.mainScreen,
|
||||||
this.trip,
|
this.title = const Text(APP_NAME),
|
||||||
|
this.helpTexts = const [],
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -34,53 +38,24 @@ class _BasePageState extends State<BasePage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Widget currentView = const Text("loading...");
|
|
||||||
Future<List<Trip>> trips = loadTrips();
|
Future<List<Trip>> trips = loadTrips();
|
||||||
|
|
||||||
|
|
||||||
if (widget.mainScreen == "map") {
|
|
||||||
if (widget.trip != null) {
|
|
||||||
currentView = TripPage(trip: widget.trip!);
|
|
||||||
} else {
|
|
||||||
currentView = FutureBuilder(
|
|
||||||
future: trips,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.hasData) {
|
|
||||||
List<Trip> availableTrips = snapshot.data!;
|
|
||||||
if (availableTrips.isNotEmpty) {
|
|
||||||
return TripPage(trip: availableTrips[0]);
|
|
||||||
} else {
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Center(
|
appBar: AppBar(
|
||||||
child: Text("Wow, so empty!"),
|
title: widget.title,
|
||||||
),
|
actions: [
|
||||||
floatingActionButton: FloatingActionButton.extended(
|
IconButton(
|
||||||
|
icon: const Icon(Icons.help),
|
||||||
|
tooltip: 'Help',
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.of(context).push(
|
if (widget.helpTexts.isNotEmpty) {
|
||||||
MaterialPageRoute(
|
helpDialog(context, widget.helpTexts[0], widget.helpTexts[1]);
|
||||||
builder: (context) => const NewTripPage()
|
}
|
||||||
)
|
}
|
||||||
);
|
|
||||||
},
|
|
||||||
label: Text("Plan a trip"),
|
|
||||||
),
|
),
|
||||||
);
|
],
|
||||||
}
|
),
|
||||||
} else {
|
body: Center(child: widget.mainScreen),
|
||||||
return const Text("loading...");
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
} else if (widget.mainScreen == "tutorial") {
|
|
||||||
currentView = OnboardingPage();
|
|
||||||
} else if (widget.mainScreen == "settings") {
|
|
||||||
currentView = SettingsPage();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(title: Text(APP_NAME)),
|
|
||||||
body: Center(child: currentView),
|
|
||||||
drawer: Drawer(
|
drawer: Drawer(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
@ -104,7 +79,8 @@ class _BasePageState extends State<BasePage> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Your Trips'),
|
title: const Text('Your Trips'),
|
||||||
leading: const Icon(Icons.map),
|
leading: const Icon(Icons.map),
|
||||||
selected: widget.mainScreen == "map",
|
// TODO: this is not working!
|
||||||
|
selected: widget.mainScreen is TripPage,
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
trailing: ElevatedButton(
|
trailing: ElevatedButton(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
@ -134,11 +110,12 @@ class _BasePageState extends State<BasePage> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('How to use'),
|
title: const Text('How to use'),
|
||||||
leading: Icon(Icons.help),
|
leading: Icon(Icons.help),
|
||||||
selected: widget.mainScreen == "tutorial",
|
// TODO: this is not working!
|
||||||
|
selected: widget.mainScreen is OnboardingPage,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => BasePage(mainScreen: "tutorial")
|
builder: (context) => OnboardingPage()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -148,11 +125,12 @@ class _BasePageState extends State<BasePage> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
title: const Text('Settings'),
|
title: const Text('Settings'),
|
||||||
leading: const Icon(Icons.settings),
|
leading: const Icon(Icons.settings),
|
||||||
selected: widget.mainScreen == "settings",
|
// TODO: this is not working!
|
||||||
|
selected: widget.mainScreen is SettingsPage,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => BasePage(mainScreen: "settings")
|
builder: (context) => SettingsPage()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
},
|
},
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
|
import 'package:anyway/pages/base_page.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';
|
||||||
|
|
||||||
@ -31,7 +32,8 @@ class _TripPageState extends State<TripPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SlidingUpPanel(
|
return BasePage(
|
||||||
|
mainScreen: SlidingUpPanel(
|
||||||
// use panelBuilder instead of panel so that we can reuse the scrollcontroller for the listview
|
// use panelBuilder instead of panel so that we can reuse the scrollcontroller for the listview
|
||||||
panelBuilder: (scrollcontroller) => CurrentTripPanel(controller: scrollcontroller, trip: widget.trip),
|
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
|
// using collapsed and panelBuilder seems to show both at the same time, so we include the greeter in the panelBuilder
|
||||||
@ -52,6 +54,13 @@ class _TripPageState extends State<TripPage> {
|
|||||||
color: Colors.black,
|
color: Colors.black,
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
|
),
|
||||||
|
title: FutureBuilder(
|
||||||
|
future: widget.trip.cityName,
|
||||||
|
builder: (context, snapshot) => Text(
|
||||||
|
'Your trip to ${snapshot.hasData ? snapshot.data! : "..."}',
|
||||||
|
)
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import 'package:anyway/modules/new_trip_button.dart';
|
|
||||||
import 'package:anyway/modules/new_trip_options_button.dart';
|
import 'package:anyway/modules/new_trip_options_button.dart';
|
||||||
|
import 'package:anyway/pages/base_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import "package:anyway/structs/trip.dart";
|
import "package:anyway/structs/trip.dart";
|
||||||
@ -19,13 +19,12 @@ class _NewTripPageState extends State<NewTripPage> {
|
|||||||
final TextEditingController lonController = TextEditingController();
|
final TextEditingController lonController = TextEditingController();
|
||||||
Trip trip = Trip();
|
Trip trip = Trip();
|
||||||
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
// floating search bar and map as a background
|
// floating search bar and map as a background
|
||||||
return Scaffold(
|
return BasePage(
|
||||||
appBar: AppBar(
|
mainScreen: Scaffold(
|
||||||
title: const Text('New Trip'),
|
|
||||||
),
|
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
NewTripMap(trip),
|
NewTripMap(trip),
|
||||||
@ -36,6 +35,12 @@ class _NewTripPageState extends State<NewTripPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
floatingActionButton: NewTripOptionsButton(trip: trip),
|
floatingActionButton: NewTripOptionsButton(trip: trip),
|
||||||
|
),
|
||||||
|
title: Text("New Trip"),
|
||||||
|
helpTexts: [
|
||||||
|
"Setting the start location",
|
||||||
|
"To set the starting point, type a city name in the search bar. You can also navigate the map like you're used to and long press anywhere to set a starting point."
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:anyway/modules/new_trip_button.dart';
|
import 'package:anyway/modules/new_trip_button.dart';
|
||||||
|
import 'package:anyway/pages/base_page.dart';
|
||||||
import 'package:anyway/structs/preferences.dart';
|
import 'package:anyway/structs/preferences.dart';
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
@ -19,7 +20,8 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return BasePage(
|
||||||
|
mainScreen: Scaffold(
|
||||||
body: ListView(
|
body: ListView(
|
||||||
children: [
|
children: [
|
||||||
// Center(
|
// Center(
|
||||||
@ -28,16 +30,16 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> {
|
|||||||
// child: Icon(Icons.person, size: 100),
|
// child: Icon(Icons.person, size: 100),
|
||||||
// )
|
// )
|
||||||
// ),
|
// ),
|
||||||
Padding(padding: EdgeInsets.only(top: 30)),
|
// 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(
|
||||||
'Your trip to ${snapshot.hasData ? snapshot.data! : "..."}',
|
// 'Your trip to ${snapshot.hasData ? snapshot.data! : "..."}',
|
||||||
style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)
|
// style: TextStyle(fontSize: 24, fontWeight: FontWeight.bold)
|
||||||
)
|
// )
|
||||||
)
|
// )
|
||||||
),
|
// ),
|
||||||
|
|
||||||
Center(
|
Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
@ -54,6 +56,18 @@ class _NewTripPreferencesPageState extends State<NewTripPreferencesPage> {
|
|||||||
]
|
]
|
||||||
),
|
),
|
||||||
floatingActionButton: NewTripButton(trip: widget.trip, preferences: preferences),
|
floatingActionButton: NewTripButton(trip: widget.trip, preferences: preferences),
|
||||||
|
),
|
||||||
|
|
||||||
|
title: FutureBuilder(
|
||||||
|
future: widget.trip.cityName,
|
||||||
|
builder: (context, snapshot) => Text(
|
||||||
|
'Your trip to ${snapshot.hasData ? snapshot.data! : "..."}',
|
||||||
|
)
|
||||||
|
),
|
||||||
|
helpTexts: [
|
||||||
|
'Trip preferences',
|
||||||
|
'Set your preferences for this trip. These will be used to generate a custom itinerary.'
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,26 @@ import 'package:anyway/modules/onboarding_card.dart';
|
|||||||
import 'package:anyway/pages/new_trip_location.dart';
|
import 'package:anyway/pages/new_trip_location.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
|
||||||
|
const List<Widget> onboardingCards = [
|
||||||
|
OnboardingCard(
|
||||||
|
title: "Welcome to anyway!",
|
||||||
|
description: "Anyway helps you plan a city trip that suits your wishes.",
|
||||||
|
imagePath: "assets/city.svg"
|
||||||
|
),
|
||||||
|
OnboardingCard(
|
||||||
|
title: "Find your way",
|
||||||
|
description: "Bored by churches? No problem! Hate shopping? No worries! Instead of suggesting the generic trips that bore you, anyway will try to give you recommendations that really suit you.",
|
||||||
|
imagePath: "assets/plan.svg"
|
||||||
|
),
|
||||||
|
OnboardingCard(
|
||||||
|
title: "Change your mind",
|
||||||
|
description: "Feet get sore, the weather changes. Anyway understands that! Move or remove destinations, visit hidden gems along your journey, do your own thing. Anyway adapts to your spontaneous decisions.",
|
||||||
|
imagePath: "assets/cat.svg"
|
||||||
|
),
|
||||||
|
];
|
||||||
|
|
||||||
|
|
||||||
class OnboardingPage extends StatefulWidget {
|
class OnboardingPage extends StatefulWidget {
|
||||||
const OnboardingPage({super.key});
|
const OnboardingPage({super.key});
|
||||||
|
|
||||||
@ -13,24 +33,32 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final PageController _controller = PageController();
|
final PageController _controller = PageController();
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
PageView(
|
|
||||||
// horizontally scrollable list of pages
|
// horizontally scrollable list of pages
|
||||||
|
PageView(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
|
|
||||||
children: [
|
children: List.generate(
|
||||||
OnboardingCard(index: 1, title: "Welcome to anyway!", description: "Anyway helps you plan a city trip that suits your wishes.", imagePath: "assets/city.svg"),
|
onboardingCards.length,
|
||||||
OnboardingCard(index: 2, title: "Find your way", description: "Bored by churches? No problem! Hate shopping? No worries! More than showing you the typical 'must-sees' of a city, anyway will try to give you recommendations that really suit you.", imagePath: "assets/plan.svg"),
|
(index) {
|
||||||
OnboardingCard(index: 3, title: "Change your mind", description: "Life happens when you're busy making plans. Anyway understands that! Move or remove destinations, visit hidden gems along your journey, do your own thing. Anyway adapts to your spontaneous decisions.", imagePath: "assets/cat.svg"),
|
Color currentColor = Colors.red.withAlpha(Colors.red.alpha - index * 30);
|
||||||
],
|
return Container(
|
||||||
|
color: currentColor,
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: onboardingCards[index],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
|
floatingActionButton: FloatingActionButton.extended(
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (_controller.page == 2) {
|
if (_controller.page == onboardingCards.length - 1) {
|
||||||
Navigator.of(context).push(
|
Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (context) => const NewTripPage()
|
builder: (context) => const NewTripPage()
|
||||||
@ -40,7 +68,24 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||||||
_controller.nextPage(duration: Duration(milliseconds: 500), curve: Curves.ease);
|
_controller.nextPage(duration: Duration(milliseconds: 500), curve: Curves.ease);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
child: Icon(Icons.arrow_forward),
|
label: ListenableBuilder(
|
||||||
|
listenable: _controller,
|
||||||
|
builder: (context, child) {
|
||||||
|
if (_controller.page == onboardingCards.length - 1) {
|
||||||
|
// icon and text side by side
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
const Text("Start planning!"),
|
||||||
|
Padding(padding: const EdgeInsets.only(right: 8.0)),
|
||||||
|
const Icon(Icons.map_outlined)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return const Icon(Icons.arrow_forward);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
import 'package:anyway/main.dart';
|
import 'package:anyway/main.dart';
|
||||||
|
import 'package:anyway/pages/base_page.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
@ -16,7 +17,8 @@ class SettingsPage extends StatefulWidget {
|
|||||||
class _SettingsPageState extends State<SettingsPage> {
|
class _SettingsPageState extends State<SettingsPage> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListView(
|
return BasePage(
|
||||||
|
mainScreen: ListView(
|
||||||
padding: EdgeInsets.all(15),
|
padding: EdgeInsets.all(15),
|
||||||
children: [
|
children: [
|
||||||
// First a round, centered image
|
// First a round, centered image
|
||||||
@ -40,6 +42,12 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
|
|
||||||
privacyInfo(),
|
privacyInfo(),
|
||||||
]
|
]
|
||||||
|
),
|
||||||
|
title: Text('Settings'),
|
||||||
|
helpTexts: [
|
||||||
|
'Settings',
|
||||||
|
'Preferences set in this page are global and will affect the entire application.'
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -169,7 +177,9 @@ class _SettingsPageState extends State<SettingsPage> {
|
|||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Text('Our privacy policy is available under:'),
|
Text('AnyWay does not collect or store any of the data that is submitted via the app. The location of your trip is not stored. The location feature is only used to show your current location on the map, it is not transmitted to our servers.', textAlign: TextAlign.center),
|
||||||
|
Padding(padding: EdgeInsets.only(top: 3)),
|
||||||
|
Text('Our full privacy policy is available under:', textAlign: TextAlign.center),
|
||||||
|
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
icon: Icon(Icons.info),
|
icon: Icon(Icons.info),
|
||||||
|
27
frontend/lib/utils/get_first_page.dart
Normal file
27
frontend/lib/utils/get_first_page.dart
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import 'package:anyway/pages/current_trip.dart';
|
||||||
|
import 'package:anyway/pages/onboarding.dart';
|
||||||
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
import 'package:anyway/utils/load_trips.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
|
Widget getFirstPage() {
|
||||||
|
Future<List<Trip>> trips = loadTrips();
|
||||||
|
// test if there are any active trips
|
||||||
|
// if there are, return the trip list
|
||||||
|
// if there are not, return the onboarding page
|
||||||
|
return FutureBuilder(
|
||||||
|
future: trips,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.hasData) {
|
||||||
|
List<Trip> availableTrips = snapshot.data!;
|
||||||
|
if (availableTrips.isNotEmpty) {
|
||||||
|
return TripPage(trip: availableTrips[0]);
|
||||||
|
} else {
|
||||||
|
return OnboardingPage();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return CircularProgressIndicator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
@ -1,7 +1,4 @@
|
|||||||
import 'dart:collection';
|
|
||||||
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:anyway/structs/landmark.dart';
|
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
Future<List<Trip>> loadTrips() async {
|
Future<List<Trip>> loadTrips() async {
|
||||||
|
@ -1,30 +0,0 @@
|
|||||||
// This is a basic Flutter widget test.
|
|
||||||
//
|
|
||||||
// To perform an interaction with a widget in your test, use the WidgetTester
|
|
||||||
// utility in the flutter_test package. For example, you can send tap and scroll
|
|
||||||
// gestures. You can also use WidgetTester to find child widgets in the widget
|
|
||||||
// tree, read text, and verify that the values of widget properties are correct.
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_test/flutter_test.dart';
|
|
||||||
|
|
||||||
// import 'package:anyway/main.dart';
|
|
||||||
import 'package:anyway/layout.dart';
|
|
||||||
|
|
||||||
void main() {
|
|
||||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
|
||||||
// Build our app and trigger a frame.
|
|
||||||
await tester.pumpWidget(BasePage(mainScreen: "map",));
|
|
||||||
|
|
||||||
// Verfiy that the title is displayed
|
|
||||||
expect(find.text('City Nav'), findsOneWidget);
|
|
||||||
|
|
||||||
// Tap the '+' icon and trigger a frame.
|
|
||||||
await tester.tap(find.byIcon(Icons.add));
|
|
||||||
await tester.pump();
|
|
||||||
|
|
||||||
// Verify that our counter has incremented.
|
|
||||||
expect(find.text('0'), findsNothing);
|
|
||||||
expect(find.text('1'), findsOneWidget);
|
|
||||||
});
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user