Frontend UX improvements #37
@ -1,10 +1,12 @@
|
|||||||
import 'package:anyway/utils/get_first_page.dart';
|
import 'package:anyway/utils/get_first_page.dart';
|
||||||
|
import 'package:anyway/utils/load_trips.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:anyway/constants.dart';
|
import 'package:anyway/constants.dart';
|
||||||
|
|
||||||
void main() => runApp(const App());
|
void main() => runApp(const App());
|
||||||
|
|
||||||
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
final GlobalKey<ScaffoldMessengerState> rootScaffoldMessengerKey = GlobalKey<ScaffoldMessengerState>();
|
||||||
|
final SavedTrips savedTrips = SavedTrips();
|
||||||
|
|
||||||
class App extends StatelessWidget {
|
class App extends StatelessWidget {
|
||||||
const App({super.key});
|
const App({super.key});
|
||||||
|
@ -3,7 +3,6 @@ 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';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
|
||||||
|
|
||||||
|
|
||||||
class saveButton extends StatefulWidget {
|
class saveButton extends StatefulWidget {
|
||||||
@ -19,8 +18,9 @@ class _saveButtonState extends State<saveButton> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ElevatedButton(
|
return ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
savedTrips.addTrip(widget.trip);
|
||||||
setState(() => widget.trip.toPrefs(prefs));
|
// SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
// setState(() => widget.trip.toPrefs(prefs));
|
||||||
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
rootScaffoldMessengerKey.currentState!.showSnackBar(
|
||||||
SnackBar(
|
SnackBar(
|
||||||
content: Text('Trip saved'),
|
content: Text('Trip saved'),
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import 'package:anyway/pages/current_trip.dart';
|
import 'package:anyway/pages/current_trip.dart';
|
||||||
|
import 'package:anyway/utils/load_trips.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
|
|
||||||
|
|
||||||
class TripsOverview extends StatefulWidget {
|
class TripsOverview extends StatefulWidget {
|
||||||
final Future<List<Trip>> trips;
|
final SavedTrips trips;
|
||||||
const TripsOverview({
|
const TripsOverview({
|
||||||
super.key,
|
super.key,
|
||||||
required this.trips,
|
required this.trips,
|
||||||
@ -16,49 +17,34 @@ 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, SavedTrips trips) {
|
||||||
List<Widget> children;
|
List<Widget> children;
|
||||||
if (snapshot.hasData) {
|
List<Trip> items = trips.trips;
|
||||||
children = List<Widget>.generate(snapshot.data!.length, (index) {
|
children = List<Widget>.generate(items.length, (index) {
|
||||||
Trip trip = snapshot.data![index];
|
Trip trip = items[index];
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: FutureBuilder(
|
title: FutureBuilder(
|
||||||
future: trip.cityName,
|
future: trip.cityName,
|
||||||
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
builder: (BuildContext context, AsyncSnapshot<String> snapshot) {
|
||||||
if (snapshot.hasData) {
|
if (snapshot.hasData) {
|
||||||
return Text("Trip to ${snapshot.data}");
|
return Text("Trip to ${snapshot.data}");
|
||||||
} else if (snapshot.hasError) {
|
} else if (snapshot.hasError) {
|
||||||
return Text("Error: ${snapshot.error}");
|
return Text("Error: ${snapshot.error}");
|
||||||
} else {
|
} else {
|
||||||
return const Text("Trip to ...");
|
return const Text("Trip to ...");
|
||||||
}
|
}
|
||||||
},
|
|
||||||
),
|
|
||||||
leading: Icon(Icons.pin_drop),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.of(context).push(
|
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => TripPage(trip: trip)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
|
||||||
});
|
|
||||||
} else if (snapshot.hasError) {
|
|
||||||
children = [
|
|
||||||
const Icon(
|
|
||||||
Icons.error_outline,
|
|
||||||
color: Colors.red,
|
|
||||||
size: 60,
|
|
||||||
),
|
),
|
||||||
Padding(
|
leading: Icon(Icons.pin_drop),
|
||||||
padding: const EdgeInsets.only(top: 16),
|
onTap: () {
|
||||||
child: Text('Error: ${snapshot.error}'),
|
Navigator.of(context).push(
|
||||||
),
|
MaterialPageRoute(
|
||||||
];
|
builder: (context) => TripPage(trip: trip)
|
||||||
} else {
|
)
|
||||||
children = [Center(child: CircularProgressIndicator())];
|
);
|
||||||
}
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
return ListView(
|
return ListView(
|
||||||
children: children,
|
children: children,
|
||||||
@ -68,9 +54,11 @@ class _TripsOverviewState extends State<TripsOverview> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FutureBuilder(
|
return ListenableBuilder(
|
||||||
future: widget.trips,
|
listenable: widget.trips,
|
||||||
builder: listBuild,
|
builder: (BuildContext context, Widget? child) {
|
||||||
|
return listBuild(context, widget.trips);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:anyway/main.dart';
|
||||||
import 'package:anyway/modules/help_dialog.dart';
|
import 'package:anyway/modules/help_dialog.dart';
|
||||||
import 'package:anyway/pages/current_trip.dart';
|
import 'package:anyway/pages/current_trip.dart';
|
||||||
import 'package:anyway/pages/settings.dart';
|
import 'package:anyway/pages/settings.dart';
|
||||||
@ -38,7 +39,8 @@ class _BasePageState extends State<BasePage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
Future<List<Trip>> trips = loadTrips();
|
savedTrips.loadTrips();
|
||||||
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
@ -98,11 +100,11 @@ class _BasePageState extends State<BasePage> {
|
|||||||
// through the options in the drawer if there isn't enough vertical
|
// through the options in the drawer if there isn't enough vertical
|
||||||
// space to fit everything.
|
// space to fit everything.
|
||||||
Expanded(
|
Expanded(
|
||||||
child: TripsOverview(trips: trips),
|
child: TripsOverview(trips: savedTrips),
|
||||||
),
|
),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
removeAllTripsFromPrefs();
|
savedTrips.clearTrips();
|
||||||
},
|
},
|
||||||
child: const Text('Clear trips'),
|
child: const Text('Clear trips'),
|
||||||
),
|
),
|
||||||
|
@ -1,3 +1,6 @@
|
|||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
|
import 'package:anyway/constants.dart';
|
||||||
import 'package:anyway/modules/onboarding_card.dart';
|
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';
|
||||||
@ -33,32 +36,51 @@ class OnboardingPage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _OnboardingPageState extends State<OnboardingPage> {
|
class _OnboardingPageState extends State<OnboardingPage> {
|
||||||
|
final PageController _controller = PageController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final PageController _controller = PageController();
|
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
AnimatedBuilder(
|
||||||
decoration: BoxDecoration(
|
animation: _controller,
|
||||||
gradient: LinearGradient(
|
builder: (context, child) {
|
||||||
colors: [Colors.red, Colors.blue],
|
return Stack(
|
||||||
begin: Alignment.topLeft,
|
children: [
|
||||||
end: Alignment.bottomRight,
|
Container(
|
||||||
),
|
decoration: BoxDecoration(
|
||||||
),
|
gradient: LinearGradient(
|
||||||
child: PageView(
|
begin: Alignment.topLeft,
|
||||||
controller: _controller,
|
end: Alignment.bottomRight,
|
||||||
children: List.generate(
|
colors: APP_GRADIENT.colors,
|
||||||
onboardingCards.length,
|
stops: [
|
||||||
(index) {
|
(_controller.hasClients ? _controller.page ?? _controller.initialPage : _controller.initialPage) / onboardingCards.length,
|
||||||
return Container(
|
(_controller.hasClients ? _controller.page ?? _controller.initialPage + 1 : _controller.initialPage + 1) / onboardingCards.length,
|
||||||
alignment: Alignment.center,
|
],
|
||||||
child: onboardingCards[index],
|
),
|
||||||
);
|
),
|
||||||
}
|
),
|
||||||
),
|
BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(sigmaX: 100, sigmaY: 100),
|
||||||
|
child: Container(
|
||||||
|
color: Colors.black.withOpacity(0),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
PageView(
|
||||||
|
controller: _controller,
|
||||||
|
children: List.generate(
|
||||||
|
onboardingCards.length,
|
||||||
|
(index) {
|
||||||
|
return Container(
|
||||||
|
alignment: Alignment.center,
|
||||||
|
child: onboardingCards[index],
|
||||||
|
);
|
||||||
|
}
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@ -75,10 +97,10 @@ class _OnboardingPageState extends State<OnboardingPage> {
|
|||||||
_controller.nextPage(duration: Duration(milliseconds: 500), curve: Curves.ease);
|
_controller.nextPage(duration: Duration(milliseconds: 500), curve: Curves.ease);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
label: ListenableBuilder(
|
label: AnimatedBuilder(
|
||||||
listenable: _controller,
|
animation: _controller,
|
||||||
builder: (context, child) {
|
builder: (context, child) {
|
||||||
if (_controller.page == onboardingCards.length - 1) {
|
if ((_controller.page ?? _controller.initialPage) == onboardingCards.length - 1) {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
const Text("Start planning!"),
|
const Text("Start planning!"),
|
||||||
|
@ -113,10 +113,3 @@ LinkedList<Landmark> readLandmarks(SharedPreferences prefs, String? firstUUID) {
|
|||||||
}
|
}
|
||||||
return landmarks;
|
return landmarks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void removeAllTripsFromPrefs () async {
|
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
prefs.clear();
|
|
||||||
}
|
|
||||||
|
@ -5,23 +5,37 @@ import 'package:anyway/utils/load_trips.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
Widget getFirstPage() {
|
Widget getFirstPage() {
|
||||||
Future<List<Trip>> trips = loadTrips();
|
SavedTrips trips = SavedTrips();
|
||||||
// test if there are any active trips
|
trips.loadTrips();
|
||||||
// if there are, return the trip list
|
|
||||||
// if there are not, return the onboarding page
|
return ListenableBuilder(
|
||||||
return FutureBuilder(
|
listenable: trips,
|
||||||
future: trips,
|
builder: (BuildContext context, Widget? child) {
|
||||||
builder: (context, snapshot) {
|
List<Trip> items = trips.trips;
|
||||||
if (snapshot.hasData) {
|
if (items.isNotEmpty) {
|
||||||
List<Trip> availableTrips = snapshot.data!;
|
return TripPage(trip: items[0]);
|
||||||
if (availableTrips.isNotEmpty) {
|
|
||||||
return TripPage(trip: availableTrips[0]);
|
|
||||||
} else {
|
|
||||||
return OnboardingPage();
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return CircularProgressIndicator();
|
return OnboardingPage();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
// 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,16 +1,39 @@
|
|||||||
import 'package:anyway/structs/trip.dart';
|
import 'package:anyway/structs/trip.dart';
|
||||||
import 'package:shared_preferences/shared_preferences.dart';
|
import 'package:shared_preferences/shared_preferences.dart';
|
||||||
|
|
||||||
Future<List<Trip>> loadTrips() async {
|
import 'package:flutter/foundation.dart';
|
||||||
SharedPreferences prefs = await SharedPreferences.getInstance();
|
|
||||||
|
|
||||||
List<Trip> trips = [];
|
class SavedTrips extends ChangeNotifier {
|
||||||
Set<String> keys = prefs.getKeys();
|
List<Trip> _trips = [];
|
||||||
for (String key in keys) {
|
|
||||||
if (key.startsWith('trip_')) {
|
List<Trip> get trips => _trips;
|
||||||
String uuid = key.replaceFirst('trip_', '');
|
|
||||||
trips.add(Trip.fromPrefs(prefs, uuid));
|
void loadTrips() async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
|
||||||
|
List<Trip> trips = [];
|
||||||
|
Set<String> keys = prefs.getKeys();
|
||||||
|
for (String key in keys) {
|
||||||
|
if (key.startsWith('trip_')) {
|
||||||
|
String uuid = key.replaceFirst('trip_', '');
|
||||||
|
trips.add(Trip.fromPrefs(prefs, uuid));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
_trips = trips;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void addTrip(Trip trip) async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
trip.toPrefs(prefs);
|
||||||
|
_trips.add(trip);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
void clearTrips () async {
|
||||||
|
SharedPreferences prefs = await SharedPreferences.getInstance();
|
||||||
|
prefs.clear();
|
||||||
|
_trips = [];
|
||||||
|
notifyListeners();
|
||||||
}
|
}
|
||||||
return trips;
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user