diff --git a/Mobile/lib/api.dart b/Mobile/lib/api.dart index 5f8ad2a..6dac053 100644 --- a/Mobile/lib/api.dart +++ b/Mobile/lib/api.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; @@ -69,7 +71,7 @@ Future isLoggedIn(BuildContext context) async { try { String base64 = token.split('.')[1]; - base64 += List.filled(4 - base64.length % 4, '=').join(); + base64 += List.filled(base64.length % 4 == 0 ? 0 : 4 - base64.length % 4, '=').join(); final payload = jsonDecode(String.fromCharCodes(base64Decode(base64))); @@ -81,6 +83,7 @@ Future isLoggedIn(BuildContext context) async { } catch (e) { messenger.showSnackBar(const SnackBar(content: Text('Invalid token, please sign in again'))); prefs.remove('token'); + debugPrint(e.toString()); return false; } diff --git a/Mobile/lib/base/sidemenu.dart b/Mobile/lib/base/sidemenu.dart index 7f74d20..d09c05b 100644 --- a/Mobile/lib/base/sidemenu.dart +++ b/Mobile/lib/base/sidemenu.dart @@ -83,14 +83,14 @@ class _SideMenuState extends State { }, ), ListTile( - title: const Text('Favourites'), + title: const Text('Favorites'), leading: const Icon(Icons.star), selected: _selectedIndex == 1, onTap: () { // Update the state of the app _onItemTapped(1); // Then close the drawer - Navigator.pushReplacementNamed(context, '/favourites'); + Navigator.pushReplacementNamed(context, '/favorites'); }, ), ListTile( diff --git a/Mobile/lib/favorites.dart b/Mobile/lib/favorites.dart new file mode 100644 index 0000000..8afc327 --- /dev/null +++ b/Mobile/lib/favorites.dart @@ -0,0 +1,61 @@ +import 'dart:convert'; +import 'api.dart' as api; +import 'package:flutter/material.dart'; +import 'base/sidemenu.dart'; // Import the base layout widget +import 'models.dart'; + +class FavoritesPage extends StatefulWidget { + const FavoritesPage({super.key}); + + @override + State createState() => _FavoritesPage(); +} + +class _FavoritesPage extends State { + List _favorites = []; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + + api.isLoggedIn(context).then((isLoggedIn) async { + if (!isLoggedIn || !mounted) return; + + final response = await api.request(context, api.ApiService.app, 'GET', '/favorites', null); + if (response == null) return; + + final List favorites = jsonDecode(response); + setState(() { + _favorites = favorites.map((favorite) => Favorite(favorite['id'], favorite['user_id'], favorite['lat'], favorite['lng'])).toList(); + }); + }); + + } + @override + Widget build(BuildContext context) { + return SideMenu( + body: Container( + decoration: BoxDecoration(color: Color(0xFFF9F9F9)), + width: MediaQuery.of(context).size.width, + padding: const EdgeInsets.all(20.0), + child: Column(children: + _favorites.map((favorite) => Container( + width: double.infinity, + padding: const EdgeInsets.all(20.0), + decoration: const BoxDecoration( + boxShadow: [ + BoxShadow( + color: Color(0x20000000), + offset: Offset(0, 1), + blurRadius: 4, + ), + ], + color: Colors.white + ), + child: const Text("Favorite data here"), + )).toList(), + ), + ), + ); + } +} diff --git a/Mobile/lib/favourites.dart b/Mobile/lib/favourites.dart deleted file mode 100644 index fd01f2a..0000000 --- a/Mobile/lib/favourites.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; -import 'base/sidemenu.dart'; // Import the base layout widget - -class FavouritesPage extends StatelessWidget { - const FavouritesPage({super.key}); - - @override - Widget build(BuildContext context) { - return const SideMenu( - body: Center( - child: Text('This is Page 1'), - ), - ); - } -} diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index 65f5548..56b069b 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -1,11 +1,16 @@ +import 'dart:convert'; +import 'dart:developer'; + import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; -import 'package:mobile/favourites.dart'; +import 'package:mobile/favorites.dart'; import 'package:mobile/register.dart'; import 'login.dart'; import 'base/sidemenu.dart'; import 'profile.dart'; +import 'api.dart' as api; +import 'models.dart'; void main() { runApp(const MyApp()); @@ -26,7 +31,7 @@ class MyApp extends StatelessWidget { routes: { '/home': (context) => const MyHomePage(), '/profile': (context) => const ProfilePage(), - '/favourites': (context) => const FavouritesPage(), + '/favorites': (context) => const FavoritesPage(), '/login': (context) => const LoginPage(), '/register': (context) => const RegisterPage(), }, @@ -43,6 +48,26 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { final GlobalKey _scaffoldKey = GlobalKey(); + List _favorites = []; + + @override + void didChangeDependencies() { + super.didChangeDependencies(); + + api.isLoggedIn(context).then((isLoggedIn) async { + if (!isLoggedIn || !mounted) return; + + final response = await api.request(context, api.ApiService.app, 'GET', '/favorites', null); + if (response == null) return; + + final List favorites = jsonDecode(response); + setState(() { + _favorites = favorites.map((favorite) => Favorite(favorite['id'], favorite['user_id'], favorite['lat'], favorite['lng'])).toList(); + }); + }); + + } + @override Widget build(BuildContext context) { return SideMenu( @@ -50,23 +75,24 @@ class _MyHomePageState extends State { key: _scaffoldKey, //drawer: navigationMenu, body: FlutterMap( - options: const MapOptions( - initialCenter: LatLng(55.9397, 9.5156), initialZoom: 7.0), + options: const MapOptions(initialCenter: LatLng(55.9397, 9.5156), initialZoom: 7.0), children: [ openStreetMapTileLayer, - const MarkerLayer(markers: [ - Marker( - point: LatLng(56.465511, 9.411366), - width: 60, - height: 100, - alignment: Alignment.center, - child: Icon( - Icons.location_pin, - size: 60, - color: Colors.purple, - ), - ), - ]), + ..._favorites.map((favorite) => + MarkerLayer(markers: [ + Marker( + point: LatLng(favorite.lat, favorite.lng), + width: 60, + height: 100, + alignment: Alignment.center, + child: const Icon( + Icons.location_pin, + size: 60, + color: Colors.yellow, + ) + ) + ]) + ), ], ), ), diff --git a/Mobile/lib/models.dart b/Mobile/lib/models.dart new file mode 100644 index 0000000..41a6f8a --- /dev/null +++ b/Mobile/lib/models.dart @@ -0,0 +1,8 @@ +class Favorite { + int id; + String userId; + double lat; + double lng; + + Favorite(this.id, this.userId, this.lat, this.lng); +} \ No newline at end of file diff --git a/Mobile/lib/register.dart b/Mobile/lib/register.dart index f72e788..e6ab956 100644 --- a/Mobile/lib/register.dart +++ b/Mobile/lib/register.dart @@ -17,10 +17,10 @@ class _RegisterPageState extends State { Future _register() async { if (passwordInput.text != confirmPasswordInput.text) { - ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Passwords do not match'))); + ScaffoldMessenger.of(context).showSnackBar( + const SnackBar(content: Text('Passwords do not match'))); return; } - final result = await api.request(context, api.ApiService.auth, 'POST', '/api/Users', { 'username': usernameInput.text, 'email': emailInput.text,