diff --git a/frontend/android/app/src/main/AndroidManifest.xml b/frontend/android/app/src/main/AndroidManifest.xml
index f144d58..b38e92b 100644
--- a/frontend/android/app/src/main/AndroidManifest.xml
+++ b/frontend/android/app/src/main/AndroidManifest.xml
@@ -50,5 +50,5 @@
-
+
diff --git a/frontend/lib/layout.dart b/frontend/lib/layout.dart
index 4d2d85f..6612e48 100644
--- a/frontend/lib/layout.dart
+++ b/frontend/lib/layout.dart
@@ -1,85 +1,117 @@
+import 'package:fast_network_navigation/modules/trips_overview.dart';
+import 'package:fast_network_navigation/pages/new_trip.dart';
+import 'package:fast_network_navigation/pages/tutorial.dart';
+import 'package:fast_network_navigation/structs/trip.dart';
import 'package:flutter/material.dart';
import 'package:fast_network_navigation/pages/overview.dart';
import 'package:fast_network_navigation/pages/profile.dart';
-
// BasePage is the scaffold that holds all other pages
// A side drawer is used to switch between pages
class BasePage extends StatefulWidget {
- const BasePage({super.key, required this.title});
- final String title;
+ final String mainScreen;
+ final String currentMap;
+ final List trips;
+
+ const BasePage({super.key, required this.mainScreen, this.currentMap = "map", this.trips = const []});
@override
State createState() => _BasePageState();
}
class _BasePageState extends State {
- int _selectedIndex = 0;
-
- void _onItemTapped(int index) {
- setState(() {
- _selectedIndex = index;
- });
- }
- Widget currentView = NavigationOverview();
+
@override
Widget build(BuildContext context) {
+ Widget currentView = const Text("loading...");
+ if (widget.mainScreen == "map") {
+ currentView = NavigationOverview();
+ } else if (widget.mainScreen == "tutorial") {
+ currentView = TutorialPage();
+ } else if (widget.mainScreen == "profile") {
+ currentView = ProfilePage();
+ }
+
final ThemeData theme = Theme.of(context);
return Scaffold(
- appBar: AppBar(title: Text(widget.title)),
+ appBar: AppBar(title: Text("City Nav")),
body: Center(child: currentView),
drawer: Drawer(
// Add a ListView to the drawer. This ensures the user can scroll
// through the options in the drawer if there isn't enough vertical
// space to fit everything.
- child: ListView(
- // Important: Remove any padding from the ListView.
- padding: EdgeInsets.zero,
+ child: Column(
children: [
DrawerHeader(
decoration: BoxDecoration(
gradient: LinearGradient(colors: [Colors.cyan, theme.primaryColor])
),
- child: const Text('The fanciest navigation!'),
+ child: Center(
+ child: Text(
+ 'City Nav',
+ style: TextStyle(
+ color: Colors.white,
+ fontSize: 24,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
),
ListTile(
title: const Text('Start'),
leading: const Icon(Icons.map),
- selected: _selectedIndex == 0,
+ selected: widget.mainScreen == "map",
onTap: () {
- // Update the state of the app
- _onItemTapped(0);
- // Then close the drawer
- currentView = NavigationOverview();
- Navigator.pop(context);
+ Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (context) => BasePage(mainScreen: "map")
+ )
+ );
},
),
+ ListTile(
+ title: const Text('Trip Overview'),
+ leading: const Icon(Icons.list),
+ trailing: ElevatedButton(
+ onPressed: () {
+ Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (context) => const NewTripPage()
+ )
+ );
+ },
+ child: const Text('New'),
+ ),
+ ),
+ Expanded(child: TripsOverview()),
+ const Divider(),
ListTile(
title: const Text('How to use'),
leading: Icon(Icons.help),
- selected: _selectedIndex == 1,
+ selected: widget.mainScreen == "tutorial",
onTap: () {
- // Update the state of the app
- _onItemTapped(1);
- currentView = const Text("ghfhggfhgf");
-
- // Then close the drawer
- Navigator.pop(context);
+ Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (context) => BasePage(mainScreen: "tutorial")
+ )
+ );
},
),
- const Divider(),
+
ListTile(
title: const Text('Settings'),
leading: const Icon(Icons.settings),
- selected: _selectedIndex == 2,
+ selected: widget.mainScreen == "profile",
onTap: () {
- _onItemTapped(2);
- currentView = ProfilePage();
- Navigator.pop(context);
- },
+ Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (context) => BasePage(mainScreen: "profile")
+ )
+ );
+ },
),
// settings in the bottom of the drawer
],
diff --git a/frontend/lib/main.dart b/frontend/lib/main.dart
index d818628..1fd9fc2 100644
--- a/frontend/lib/main.dart
+++ b/frontend/lib/main.dart
@@ -12,7 +12,7 @@ class App extends StatelessWidget {
Widget build(BuildContext context) {
return MaterialApp(
title: appTitle,
- home: BasePage(title: appTitle),
+ home: BasePage(mainScreen: "map"),
theme: ThemeData(useMaterial3: true, colorSchemeSeed: Colors.green),
);
}
diff --git a/frontend/lib/modules/greeter.dart b/frontend/lib/modules/greeter.dart
index 99c1be2..e3066ac 100644
--- a/frontend/lib/modules/greeter.dart
+++ b/frontend/lib/modules/greeter.dart
@@ -19,8 +19,8 @@ Widget Greeter (ThemeData theme, {bool full = false}) {
if (full) {
bottomGreeter = Text(
"Busy day ahead? Here is how to make the most of it!",
- style: TextStyle(color: Colors.black, fontSize: 18.0),
- maxLines: 1,
+ style: TextStyle(color: Colors.black, fontSize: 18),
+ textAlign: TextAlign.center,
);
}
Widget greeter = Center(
diff --git a/frontend/lib/modules/landmarks_overview.dart b/frontend/lib/modules/landmarks_overview.dart
index 120fe0e..c967a65 100644
--- a/frontend/lib/modules/landmarks_overview.dart
+++ b/frontend/lib/modules/landmarks_overview.dart
@@ -40,7 +40,7 @@ class _loadLandmarksOverviewState extends State {
),
];
} else {
- children = [LandmarkCard(Landmark(name: "loading", location: [0,0], type: LandmarkType(name: "loading")))];
+ children = [Center(child: CircularProgressIndicator())];
}
return Center(
child: Column(
diff --git a/frontend/lib/modules/trips_overview.dart b/frontend/lib/modules/trips_overview.dart
new file mode 100644
index 0000000..955a109
--- /dev/null
+++ b/frontend/lib/modules/trips_overview.dart
@@ -0,0 +1,65 @@
+import 'package:flutter/material.dart';
+
+import 'package:fast_network_navigation/layout.dart';
+import 'package:fast_network_navigation/structs/trip.dart';
+import 'package:fast_network_navigation/utils/get_trips.dart';
+
+
+class TripsOverview extends StatefulWidget {
+
+ const TripsOverview({super.key});
+
+ @override
+ State createState() => _TripsOverviewState();
+}
+
+class _TripsOverviewState extends State {
+ final Future> _trips = loadTrips();
+
+
+ Widget listBuild (BuildContext context, AsyncSnapshot> snapshot) {
+ List children;
+ if (snapshot.hasData) {
+ children = List.generate(snapshot.data!.length, (index) {
+ Trip trip = snapshot.data![index];
+ return ListTile(
+ title: Text("Trip to ${trip.cityName} (${trip.landmarks.length} stops)"),
+ leading: Icon(Icons.pin_drop),
+ onTap: () {
+ Navigator.of(context).push(
+ MaterialPageRoute(
+ builder: (context) => BasePage(mainScreen: "map") //, trip: trip)
+ )
+ );
+ },
+ );
+ });
+ } else if (snapshot.hasError) {
+ children = [
+ const Icon(
+ Icons.error_outline,
+ color: Colors.red,
+ size: 60,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(top: 16),
+ child: Text('Error: ${snapshot.error}'),
+ ),
+ ];
+ } else {
+ children = [Center(child: CircularProgressIndicator())];
+ }
+
+ return ListView(
+ children: children,
+ );
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return FutureBuilder(
+ future: _trips,
+ builder: listBuild,
+ );
+ }
+}
\ No newline at end of file
diff --git a/frontend/lib/pages/new_trip.dart b/frontend/lib/pages/new_trip.dart
new file mode 100644
index 0000000..47e2c5b
--- /dev/null
+++ b/frontend/lib/pages/new_trip.dart
@@ -0,0 +1,30 @@
+
+import 'package:flutter/material.dart';
+
+class NewTripPage extends StatefulWidget {
+ const NewTripPage({Key? key}) : super(key: key);
+
+ @override
+ _NewTripPageState createState() => _NewTripPageState();
+}
+
+class _NewTripPageState extends State {
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: const Text('New Trip'),
+ ),
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ const Text(
+ 'Create a new trip',
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
\ No newline at end of file
diff --git a/frontend/lib/pages/profile.dart b/frontend/lib/pages/profile.dart
index 42f08d7..10fefe8 100644
--- a/frontend/lib/pages/profile.dart
+++ b/frontend/lib/pages/profile.dart
@@ -30,7 +30,7 @@ class _ProfilePageState extends State {
Padding(
padding: EdgeInsets.only(left: 10, right: 10, top: 0, bottom: 10),
- child: Text('Please rate your personal preferences so that we can taylor your experience.', style: TextStyle(fontSize: 20), )
+ child: Text('Please rate your personal preferences so that we can taylor your experience.', style: TextStyle(fontSize: 18))
),
// Now the sliders
diff --git a/frontend/lib/pages/tutorial.dart b/frontend/lib/pages/tutorial.dart
new file mode 100644
index 0000000..3b19421
--- /dev/null
+++ b/frontend/lib/pages/tutorial.dart
@@ -0,0 +1,27 @@
+import 'package:flutter/material.dart';
+
+
+
+class TutorialPage extends StatelessWidget {
+ @override
+ Widget build(BuildContext context) {
+ return Scaffold(
+ appBar: AppBar(
+ title: Text("Tutorial"),
+ ),
+ body: Center(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ Text(
+ 'Welcome to the tutorial page!',
+ ),
+ Text(
+ 'This is where you will learn how to use the app.',
+ ),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/frontend/lib/structs/landmark.dart b/frontend/lib/structs/landmark.dart
index a65dbe8..14d1b5b 100644
--- a/frontend/lib/structs/landmark.dart
+++ b/frontend/lib/structs/landmark.dart
@@ -38,6 +38,17 @@ class Landmark {
};
}
+
+ Map toJson() {
+ return {
+ 'name': name,
+ 'location': location,
+ 'type': type.name,
+ // 'description': description,
+ // 'duration': duration.inMinutes,
+ // 'visited': visited
+ };
+ }
}
diff --git a/frontend/lib/structs/trip.dart b/frontend/lib/structs/trip.dart
new file mode 100644
index 0000000..dc02332
--- /dev/null
+++ b/frontend/lib/structs/trip.dart
@@ -0,0 +1,25 @@
+// Represents a collection of landmarks that represent a journey
+// Different instances of a Trip can be saved and loaded by the user
+
+import 'package:fast_network_navigation/structs/landmark.dart';
+
+class Trip {
+ final String uuid;
+ final String cityName;
+ final List landmarks;
+
+
+ Trip({required this.uuid, required this.cityName, required this.landmarks});
+
+ factory Trip.fromJson(Map json) {
+ List landmarks = [];
+ for (var landmark in json['landmarks']) {
+ landmarks.add(Landmark.fromJson(landmark));
+ }
+ return Trip(
+ uuid: json['uuid'],
+ cityName: json['cityName'],
+ landmarks: landmarks,
+ );
+ }
+}
\ No newline at end of file
diff --git a/frontend/lib/utils/get_landmarks.dart b/frontend/lib/utils/get_landmarks.dart
index 3c47728..5390849 100644
--- a/frontend/lib/utils/get_landmarks.dart
+++ b/frontend/lib/utils/get_landmarks.dart
@@ -16,6 +16,8 @@ Future> fetchLandmarks() async {
Landmark(name: "Landmark 4", location: [48.9, 2.4], type: LandmarkType(name: "Type 4")),
Landmark(name: "Landmark 5", location: [48.91, 2.45], type: LandmarkType(name: "Type 5")),
];
+ // sleep 10 seconds
+ await Future.delayed(Duration(seconds: 10));
return landmarks;
// } else {
// // If the server did not return a 200 OK response,
diff --git a/frontend/lib/utils/get_trips.dart b/frontend/lib/utils/get_trips.dart
new file mode 100644
index 0000000..0a64080
--- /dev/null
+++ b/frontend/lib/utils/get_trips.dart
@@ -0,0 +1,37 @@
+import 'dart:convert';
+
+import 'package:fast_network_navigation/structs/trip.dart';
+import 'package:fast_network_navigation/structs/landmark.dart';
+import 'package:shared_preferences/shared_preferences.dart';
+
+Future> loadTrips() async {
+ SharedPreferences prefs = await SharedPreferences.getInstance();
+
+ Set keys = prefs.getKeys();
+ List itineraries = [];
+ for (String key in keys) {
+ if (key.startsWith("itinerary_")) {
+ String json = prefs.getString(key)!;
+ itineraries.add(Trip.fromJson(jsonDecode(json)));
+ }
+ }
+ itineraries.add(Trip(uuid: "1", cityName: "Paris", landmarks: [
+ Landmark(name: "Landmark 1", location: [48.85, 2.35], type: LandmarkType(name: "Type 1")),
+ Landmark(name: "Landmark 2", location: [48.86, 2.36], type: LandmarkType(name: "Type 2")),
+ Landmark(name: "Landmark 3", location: [48.75, 2.3], type: LandmarkType(name: "Type 3")),
+ Landmark(name: "Landmark 4", location: [48.9, 2.4], type: LandmarkType(name: "Type 4")),
+ Landmark(name: "Landmark 5", location: [48.91, 2.45], type: LandmarkType(name: "Type 5")),
+ ]));
+ itineraries.add(Trip(uuid: "2", cityName: "Vienna", landmarks: []));
+ itineraries.add(Trip(uuid: "3", cityName: "London", landmarks: []));
+ itineraries.add(Trip(uuid: "4", cityName: "Madrid", landmarks: []));
+ itineraries.add(Trip(uuid: "5", cityName: "Tokyo", landmarks: []));
+ itineraries.add(Trip(uuid: "6", cityName: "New York", landmarks: []));
+ itineraries.add(Trip(uuid: "7", cityName: "Los Angeles", landmarks: []));
+ itineraries.add(Trip(uuid: "8", cityName: "Zurich", landmarks: []));
+ itineraries.add(Trip(uuid: "9", cityName: "Orschwiller", landmarks: []));
+
+ await Future.delayed(Duration(seconds: 3));
+
+ return itineraries;
+}
diff --git a/frontend/test/widget_test.dart b/frontend/test/widget_test.dart
index 143b24f..f17a55a 100644
--- a/frontend/test/widget_test.dart
+++ b/frontend/test/widget_test.dart
@@ -14,7 +14,7 @@ import 'package:fast_network_navigation/layout.dart';
void main() {
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
// Build our app and trigger a frame.
- await tester.pumpWidget(BasePage(title: "City Nav"));
+ await tester.pumpWidget(BasePage(mainScreen: "map",));
// Verfiy that the title is displayed
expect(find.text('City Nav'), findsOneWidget);