From 2d039a04da47e77e4f94f040116a6aa84355901c Mon Sep 17 00:00:00 2001 From: Reimar Date: Tue, 27 Aug 2024 08:53:56 +0200 Subject: [PATCH 1/7] Make location pin prettier --- Mobile/lib/main.dart | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index f98509e..15f4db5 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -81,14 +81,15 @@ class _MyHomePageState extends State { MarkerLayer(markers: [ Marker( point: LatLng(favorite.lat, favorite.lng), - width: 60, - height: 100, + width: 30, + height: 50, alignment: Alignment.center, - child: const Icon( - Icons.location_pin, - size: 60, - color: Colors.yellow, - ) + child: const Stack( + children: [ + Icon(Icons.location_pin, size: 30, color: Colors.yellow), + Icon(Icons.location_on_outlined, size: 30, color: Colors.black), + ] + ), ) ]) ), @@ -99,7 +100,7 @@ class _MyHomePageState extends State { } TileLayer get openStreetMapTileLayer => TileLayer( - urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', - userAgentPackageName: 'dev.fleaflet.flutter_map.example', - ); + urlTemplate: 'https://tile.openstreetmap.org/{z}/{x}/{y}.png', + userAgentPackageName: 'dev.fleaflet.flutter_map.example', + ); } From 13b7ab187a0c90e0893b0fd4ba02994f451d3fc1 Mon Sep 17 00:00:00 2001 From: Reimar Date: Tue, 27 Aug 2024 09:15:21 +0200 Subject: [PATCH 2/7] Show selected point on map --- Mobile/lib/main.dart | 32 +++++++++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index 15f4db5..52d1ee0 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -47,6 +47,11 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { final GlobalKey _scaffoldKey = GlobalKey(); List _favorites = []; + LatLng? _selectedPoint; + + void _showLocation(TapPosition _, LatLng point) { + setState(() => _selectedPoint = point); + } @override void didChangeDependencies() { @@ -63,7 +68,6 @@ class _MyHomePageState extends State { _favorites = favorites.map((favorite) => Favorite(favorite['id'], favorite['user_id'], favorite['lat'], favorite['lng'], favorite['name'], favorite['description'])).toList(); }); }); - } @override @@ -74,7 +78,11 @@ class _MyHomePageState extends State { key: _scaffoldKey, //drawer: navigationMenu, body: FlutterMap( - options: const MapOptions(initialCenter: LatLng(55.9397, 9.5156), initialZoom: 7.0), + options: MapOptions( + initialCenter: const LatLng(55.9397, 9.5156), + initialZoom: 7.0, + onTap: _showLocation, + ), children: [ openStreetMapTileLayer, ..._favorites.map((favorite) => @@ -91,7 +99,25 @@ class _MyHomePageState extends State { ] ), ) - ]) + ]), + ), + ...( + _selectedPoint != null ? [ + MarkerLayer(markers: [ + Marker( + point: _selectedPoint!, + width: 30, + height: 50, + alignment: Alignment.center, + child: const Stack( + children: [ + Icon(Icons.location_pin, size: 30, color: Colors.red), + Icon(Icons.location_on_outlined, size: 30, color: Colors.black), + ] + ), + ) + ]), + ] : [] ), ], ), From cbe1bc8abd48acd8ea6b571f7286f263163ac03d Mon Sep 17 00:00:00 2001 From: Reimar Date: Tue, 27 Aug 2024 09:55:43 +0200 Subject: [PATCH 3/7] Show location information when clicking --- Mobile/lib/api.dart | 2 -- Mobile/lib/main.dart | 53 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/Mobile/lib/api.dart b/Mobile/lib/api.dart index 23d65ac..496e157 100644 --- a/Mobile/lib/api.dart +++ b/Mobile/lib/api.dart @@ -1,9 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:mobile/models.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:http/http.dart' as http; import 'dart:convert'; -import 'base/variables.dart'; enum ApiService { auth, diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index 52d1ee0..e1b83bd 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -9,6 +9,7 @@ import 'base/sidemenu.dart'; import 'profile.dart'; import 'api.dart' as api; import 'models.dart'; +import 'package:http/http.dart' as http; void main() { runApp(const MyApp()); @@ -49,8 +50,58 @@ class _MyHomePageState extends State { List _favorites = []; LatLng? _selectedPoint; - void _showLocation(TapPosition _, LatLng point) { + void _showLocation(TapPosition _, LatLng point) async { setState(() => _selectedPoint = point); + + final location; + try { + final response = await http.get( + Uri.parse('https://nominatim.openstreetmap.org/reverse.php?lat=${point.latitude}&lon=${point.longitude}&zoom=18&format=jsonv2'), + headers: {'User-Agent': 'SkanTravels/1.0'}, + ); + + location = jsonDecode(response.body); + } catch (_) { + if (!mounted) return; + + ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('Unable to fetch information about this location'))); + + setState(() => _selectedPoint = null); + + return; + } + + if (!mounted) return; + + await showModalBottomSheet( + barrierColor: Colors.black.withOpacity(0.3), + context: context, + builder: (builder) { + return Wrap(children: [ + Container( + color: Colors.white, + padding: const EdgeInsets.all(20), + width: MediaQuery.of(context).size.width, + child: Row(children: [ + Expanded(child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(location['name'], style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 24)), + const SizedBox(height: 10), + Text(location['display_name']), + ], + )), + const Column(children: [ + IconButton(icon: Icon(Icons.star), iconSize: 32, onPressed: null), + IconButton(icon: Icon(Icons.rate_review), iconSize: 32, onPressed: null), + ]), + ]), + ), + ]); + }, + ); + + setState(() => _selectedPoint = null); } @override From a1c8a5e25e1166fa70d620cbee31b312948704f2 Mon Sep 17 00:00:00 2001 From: Reimar Date: Tue, 27 Aug 2024 10:40:01 +0200 Subject: [PATCH 4/7] Implement adding/removing favorite from location info menu --- Mobile/lib/favorites.dart | 4 +- Mobile/lib/main.dart | 142 +++++++++++++++++++++++++------------- 2 files changed, 97 insertions(+), 49 deletions(-) diff --git a/Mobile/lib/favorites.dart b/Mobile/lib/favorites.dart index 42a2890..8ac10bf 100644 --- a/Mobile/lib/favorites.dart +++ b/Mobile/lib/favorites.dart @@ -63,7 +63,7 @@ class _FavoritesPage extends State { Widget build(BuildContext context) { return SideMenu( selectedIndex: 1, - body: Container( + body: SingleChildScrollView(child: Container( decoration: const BoxDecoration(color: Color(0xFFF9F9F9)), width: MediaQuery.of(context).size.width, padding: const EdgeInsets.all(20.0), @@ -106,6 +106,6 @@ class _FavoritesPage extends State { )).toList(), ), ), - ); + )); } } diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index e1b83bd..9674023 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -47,13 +47,14 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { final GlobalKey _scaffoldKey = GlobalKey(); + final GlobalKey _locationScaffoldKey = GlobalKey(); List _favorites = []; LatLng? _selectedPoint; void _showLocation(TapPosition _, LatLng point) async { setState(() => _selectedPoint = point); - final location; + final dynamic location; try { final response = await http.get( Uri.parse('https://nominatim.openstreetmap.org/reverse.php?lat=${point.latitude}&lon=${point.longitude}&zoom=18&format=jsonv2'), @@ -77,47 +78,94 @@ class _MyHomePageState extends State { barrierColor: Colors.black.withOpacity(0.3), context: context, builder: (builder) { - return Wrap(children: [ - Container( - color: Colors.white, - padding: const EdgeInsets.all(20), - width: MediaQuery.of(context).size.width, - child: Row(children: [ - Expanded(child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(location['name'], style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 24)), - const SizedBox(height: 10), - Text(location['display_name']), - ], - )), - const Column(children: [ - IconButton(icon: Icon(Icons.star), iconSize: 32, onPressed: null), - IconButton(icon: Icon(Icons.rate_review), iconSize: 32, onPressed: null), + return StatefulBuilder(builder: (BuildContext context, StateSetter setModalState) { + return Wrap(children: [ + Container( + color: Colors.white, + padding: const EdgeInsets.all(20), + width: MediaQuery.of(context).size.width, + child: Row(children: [ + Expanded(child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(location['name'], style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 24)), + const SizedBox(height: 10), + Text(location['display_name']), + ], + )), + Column(children: [ + IconButton( + icon: const Icon(Icons.star), + iconSize: 32, + color: _favorites.where((fav) => fav.lat == point.latitude && fav.lng == point.longitude).isEmpty ? Colors.grey : Colors.yellow, + onPressed: () => _toggleFavorite(point, location['name'], location['display_name'], setModalState, context) + ), + const IconButton(icon: Icon(Icons.rate_review), iconSize: 32, onPressed: null), + ]), ]), - ]), - ), - ]); + ), + ]); + }); }, ); setState(() => _selectedPoint = null); } + void _toggleFavorite(LatLng point, String name, String description, StateSetter setModalState, BuildContext context) async { + final messenger = ScaffoldMessenger.of(context); + final favorite = _favorites.where((fav) => fav.lat == point.latitude && fav.lng == point.longitude).firstOrNull; + + if (!await api.isLoggedIn(context)) { + messenger.showSnackBar(const SnackBar(content: Text('You need to login to do that'))); + return; + } + + if (!context.mounted) return; + + if (favorite == null) { + if (await api.request(context, api.ApiService.app, 'POST', '/favorites', {'lat': point.latitude, 'lng': point.longitude}) == null) { + return; + } + + _fetchFavorites(); + setModalState(() {}); + + messenger.showSnackBar(const SnackBar(content: Text('Added to favorites'))); + + return; + } + + if (await api.request(context, api.ApiService.app, 'DELETE', '/favorites/${favorite.id}', null) == null) { + return; + } + + setState(() { + _favorites = _favorites.where((fav) => fav.id != favorite.id).toList(); + }); + setModalState(() {}); + + messenger.showSnackBar(const SnackBar(content: Text('Removed from favorites'))); + } + + void _fetchFavorites() async { + 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'], favorite['name'], favorite['description'])).toList(); + }); + } + @override void didChangeDependencies() { super.didChangeDependencies(); - api.isLoggedIn(context).then((isLoggedIn) async { + api.isLoggedIn(context).then((isLoggedIn) { 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'], favorite['name'], favorite['description'])).toList(); - }); + _fetchFavorites(); }); } @@ -136,6 +184,24 @@ class _MyHomePageState extends State { ), children: [ openStreetMapTileLayer, + ...( + _selectedPoint != null ? [ + MarkerLayer(markers: [ + Marker( + point: _selectedPoint!, + width: 30, + height: 50, + alignment: Alignment.center, + child: const Stack( + children: [ + Icon(Icons.location_pin, size: 30, color: Colors.red), + Icon(Icons.location_on_outlined, size: 30, color: Colors.black), + ] + ), + ) + ]), + ] : [] + ), ..._favorites.map((favorite) => MarkerLayer(markers: [ Marker( @@ -152,24 +218,6 @@ class _MyHomePageState extends State { ) ]), ), - ...( - _selectedPoint != null ? [ - MarkerLayer(markers: [ - Marker( - point: _selectedPoint!, - width: 30, - height: 50, - alignment: Alignment.center, - child: const Stack( - children: [ - Icon(Icons.location_pin, size: 30, color: Colors.red), - Icon(Icons.location_on_outlined, size: 30, color: Colors.black), - ] - ), - ) - ]), - ] : [] - ), ], ), ), From 7b884e316755a62847809bb6c932e1252d27ab93 Mon Sep 17 00:00:00 2001 From: Reimar Date: Tue, 27 Aug 2024 11:06:33 +0200 Subject: [PATCH 5/7] Fix snackbars --- Mobile/lib/main.dart | 44 ++++++++++++++++++++------------------------ 1 file changed, 20 insertions(+), 24 deletions(-) diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index 9674023..4792b5a 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -47,7 +47,6 @@ class MyHomePage extends StatefulWidget { class _MyHomePageState extends State { final GlobalKey _scaffoldKey = GlobalKey(); - final GlobalKey _locationScaffoldKey = GlobalKey(); List _favorites = []; LatLng? _selectedPoint; @@ -114,10 +113,12 @@ class _MyHomePageState extends State { void _toggleFavorite(LatLng point, String name, String description, StateSetter setModalState, BuildContext context) async { final messenger = ScaffoldMessenger.of(context); + final navigator = Navigator.of(context); final favorite = _favorites.where((fav) => fav.lat == point.latitude && fav.lng == point.longitude).firstOrNull; if (!await api.isLoggedIn(context)) { - messenger.showSnackBar(const SnackBar(content: Text('You need to login to do that'))); + messenger.showSnackBar(const SnackBar(content: Text('You need to login to do that'), behavior: SnackBarBehavior.floating)); + navigator.pop(); return; } @@ -125,18 +126,18 @@ class _MyHomePageState extends State { if (favorite == null) { if (await api.request(context, api.ApiService.app, 'POST', '/favorites', {'lat': point.latitude, 'lng': point.longitude}) == null) { + navigator.pop(); return; } _fetchFavorites(); setModalState(() {}); - messenger.showSnackBar(const SnackBar(content: Text('Added to favorites'))); - return; } if (await api.request(context, api.ApiService.app, 'DELETE', '/favorites/${favorite.id}', null) == null) { + navigator.pop(); return; } @@ -144,8 +145,6 @@ class _MyHomePageState extends State { _favorites = _favorites.where((fav) => fav.id != favorite.id).toList(); }); setModalState(() {}); - - messenger.showSnackBar(const SnackBar(content: Text('Removed from favorites'))); } void _fetchFavorites() async { @@ -184,24 +183,21 @@ class _MyHomePageState extends State { ), children: [ openStreetMapTileLayer, - ...( - _selectedPoint != null ? [ - MarkerLayer(markers: [ - Marker( - point: _selectedPoint!, - width: 30, - height: 50, - alignment: Alignment.center, - child: const Stack( - children: [ - Icon(Icons.location_pin, size: 30, color: Colors.red), - Icon(Icons.location_on_outlined, size: 30, color: Colors.black), - ] - ), - ) - ]), - ] : [] - ), + if (_selectedPoint != null) + MarkerLayer(markers: [ + Marker( + point: _selectedPoint!, + width: 30, + height: 50, + alignment: Alignment.center, + child: const Stack( + children: [ + Icon(Icons.location_pin, size: 30, color: Colors.red), + Icon(Icons.location_on_outlined, size: 30, color: Colors.black), + ] + ), + ) + ]), ..._favorites.map((favorite) => MarkerLayer(markers: [ Marker( From 39e0db1f5df67c771286e6c06582a9a279713a5b Mon Sep 17 00:00:00 2001 From: Reimar Date: Tue, 27 Aug 2024 11:48:11 +0200 Subject: [PATCH 6/7] Allow clicking on favorites --- Mobile/lib/main.dart | 49 ++++++++++++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index 4792b5a..74af895 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -50,7 +50,7 @@ class _MyHomePageState extends State { List _favorites = []; LatLng? _selectedPoint; - void _showLocation(TapPosition _, LatLng point) async { + void _onTap(TapPosition _, LatLng point) async { setState(() => _selectedPoint = point); final dynamic location; @@ -60,6 +60,11 @@ class _MyHomePageState extends State { headers: {'User-Agent': 'SkanTravels/1.0'}, ); + if (mounted && response.statusCode != 200) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Unable to fetch information about this location (HTTP ${response.statusCode})'))); + return; + } + location = jsonDecode(response.body); } catch (_) { if (!mounted) return; @@ -73,6 +78,14 @@ class _MyHomePageState extends State { if (!mounted) return; + if (location['name'] != null && location['display_name'] != null) { + await _showLocation(point, location['name'], location['display_name']); + } + + setState(() => _selectedPoint = null); + } + + Future _showLocation(LatLng point, String name, String description) async { await showModalBottomSheet( barrierColor: Colors.black.withOpacity(0.3), context: context, @@ -87,17 +100,17 @@ class _MyHomePageState extends State { Expanded(child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(location['name'], style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 24)), + Text(name, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 24)), const SizedBox(height: 10), - Text(location['display_name']), + Text(description), ], )), Column(children: [ IconButton( - icon: const Icon(Icons.star), - iconSize: 32, - color: _favorites.where((fav) => fav.lat == point.latitude && fav.lng == point.longitude).isEmpty ? Colors.grey : Colors.yellow, - onPressed: () => _toggleFavorite(point, location['name'], location['display_name'], setModalState, context) + icon: const Icon(Icons.star), + iconSize: 32, + color: _favorites.where((fav) => fav.lat == point.latitude && fav.lng == point.longitude).isEmpty ? Colors.grey : Colors.yellow, + onPressed: () => _toggleFavorite(point, name, description, setModalState, context) ), const IconButton(icon: Icon(Icons.rate_review), iconSize: 32, onPressed: null), ]), @@ -107,8 +120,6 @@ class _MyHomePageState extends State { }); }, ); - - setState(() => _selectedPoint = null); } void _toggleFavorite(LatLng point, String name, String description, StateSetter setModalState, BuildContext context) async { @@ -130,7 +141,7 @@ class _MyHomePageState extends State { return; } - _fetchFavorites(); + await _fetchFavorites(); setModalState(() {}); return; @@ -147,7 +158,7 @@ class _MyHomePageState extends State { setModalState(() {}); } - void _fetchFavorites() async { + Future _fetchFavorites() async { final response = await api.request(context, api.ApiService.app, 'GET', '/favorites', null); if (response == null) return; @@ -179,7 +190,7 @@ class _MyHomePageState extends State { options: MapOptions( initialCenter: const LatLng(55.9397, 9.5156), initialZoom: 7.0, - onTap: _showLocation, + onTap: _onTap, ), children: [ openStreetMapTileLayer, @@ -205,10 +216,18 @@ class _MyHomePageState extends State { width: 30, height: 50, alignment: Alignment.center, - child: const Stack( + child: Stack( children: [ - Icon(Icons.location_pin, size: 30, color: Colors.yellow), - Icon(Icons.location_on_outlined, size: 30, color: Colors.black), + IconButton( + padding: const EdgeInsets.only(bottom: 10), + icon: const Icon(Icons.location_pin, size: 30, color: Colors.yellow), + onPressed: () => _showLocation(LatLng(favorite.lat, favorite.lng), favorite.name, favorite.description), + ), + IconButton( + padding: const EdgeInsets.only(bottom: 10), + icon: const Icon(Icons.location_on_outlined, size: 30, color: Colors.black), + onPressed: () => _showLocation(LatLng(favorite.lat, favorite.lng), favorite.name, favorite.description), + ), ] ), ) From 60dd258b45381881776d4d3123a48718dcf78ca6 Mon Sep 17 00:00:00 2001 From: Reimar Date: Tue, 27 Aug 2024 12:16:07 +0200 Subject: [PATCH 7/7] Send OSM request only on frontend, take zoom into account --- Mobile/lib/api.dart | 2 +- Mobile/lib/main.dart | 21 ++++++++++++++++----- Mobile/lib/models.dart | 11 +++++++++++ rust-backend/src/main.rs | 30 ++++++++++++------------------ rust-backend/src/models.rs | 2 +- 5 files changed, 41 insertions(+), 25 deletions(-) diff --git a/Mobile/lib/api.dart b/Mobile/lib/api.dart index 496e157..25b6bdc 100644 --- a/Mobile/lib/api.dart +++ b/Mobile/lib/api.dart @@ -57,7 +57,7 @@ Future request(BuildContext context, ApiService service, String method, return null; } - return response.body; + return utf8.decode(response.bodyBytes); } Future isLoggedIn(BuildContext context) async { diff --git a/Mobile/lib/main.dart b/Mobile/lib/main.dart index 74af895..d3f8bd9 100644 --- a/Mobile/lib/main.dart +++ b/Mobile/lib/main.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter_map/flutter_map.dart'; import 'package:latlong2/latlong.dart'; @@ -49,6 +50,7 @@ class _MyHomePageState extends State { final GlobalKey _scaffoldKey = GlobalKey(); List _favorites = []; LatLng? _selectedPoint; + double _zoom = 7.0; void _onTap(TapPosition _, LatLng point) async { setState(() => _selectedPoint = point); @@ -56,12 +58,13 @@ class _MyHomePageState extends State { final dynamic location; try { final response = await http.get( - Uri.parse('https://nominatim.openstreetmap.org/reverse.php?lat=${point.latitude}&lon=${point.longitude}&zoom=18&format=jsonv2'), + Uri.parse('https://nominatim.openstreetmap.org/reverse.php?lat=${point.latitude}&lon=${point.longitude}&zoom=${max(12, _zoom.ceil())}&format=jsonv2'), headers: {'User-Agent': 'SkanTravels/1.0'}, ); if (mounted && response.statusCode != 200) { ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('Unable to fetch information about this location (HTTP ${response.statusCode})'))); + debugPrint(response.body); return; } @@ -136,12 +139,19 @@ class _MyHomePageState extends State { if (!context.mounted) return; if (favorite == null) { - if (await api.request(context, api.ApiService.app, 'POST', '/favorites', {'lat': point.latitude, 'lng': point.longitude}) == null) { + final newFavorite = await api.request( + context, api.ApiService.app, 'POST', '/favorites', + {'lat': point.latitude, 'lng': point.longitude, 'name': name, 'description': description}, + ); + + if (newFavorite == null) { navigator.pop(); return; } - await _fetchFavorites(); + setState(() { + _favorites.add(Favorite.fromJson(jsonDecode(newFavorite))); + }); setModalState(() {}); return; @@ -164,7 +174,7 @@ class _MyHomePageState extends State { final List favorites = jsonDecode(response); setState(() { - _favorites = favorites.map((favorite) => Favorite(favorite['id'], favorite['user_id'], favorite['lat'], favorite['lng'], favorite['name'], favorite['description'])).toList(); + _favorites = favorites.map((favorite) => Favorite.fromJson(favorite)).toList(); }); } @@ -189,8 +199,9 @@ class _MyHomePageState extends State { body: FlutterMap( options: MapOptions( initialCenter: const LatLng(55.9397, 9.5156), - initialZoom: 7.0, + initialZoom: _zoom, onTap: _onTap, + onPositionChanged: (pos, _) => _zoom = pos.zoom, ), children: [ openStreetMapTileLayer, diff --git a/Mobile/lib/models.dart b/Mobile/lib/models.dart index 665387c..78fb075 100644 --- a/Mobile/lib/models.dart +++ b/Mobile/lib/models.dart @@ -7,6 +7,17 @@ class Favorite { String description; Favorite(this.id, this.userId, this.lat, this.lng, this.name, this.description); + + factory Favorite.fromJson(Map json) { + return Favorite( + json['id'], + json['user_id'], + json['lat'], + json['lng'], + json['name'], + json['description'], + ); + } } class Login { diff --git a/rust-backend/src/main.rs b/rust-backend/src/main.rs index 815df0d..f059c3a 100644 --- a/rust-backend/src/main.rs +++ b/rust-backend/src/main.rs @@ -56,39 +56,33 @@ fn get_favorites(db: MutexGuard<'_, rusqlite::Connection>, user_id: String) -> O struct CreateFavoriteRequest { lat: f64, lng: f64, -} - -#[derive(Deserialize, Debug)] -struct ReverseLookupResponse { name: String, - display_name: String, + description: String, } #[post("/favorites")] async fn create_favorite(auth: AuthorizedUser, data: web::Data, input: web::Json) -> impl Responder { let db = data.database.lock().unwrap(); - let Ok(response) = reqwest::Client::new() - .get(format!("https://nominatim.openstreetmap.org/reverse.php?lat={}&lon={}&zoom=18&format=jsonv2", input.lat, input.lng)) - .header("User-Agent", "SkanTravels/1.0") - .send().await - else { return HttpResponse::InternalServerError(); }; - - let Ok(response) = response.json::().await - else { return HttpResponse::InternalServerError(); }; - match db.execute( "INSERT INTO favorites (user_id, lat, lng, name, description) VALUES (:user_id, :lat, :lng, :name, :description)", &[ (":user_id", &auth.user_id), (":lat", &input.lat.to_string()), (":lng", &input.lng.to_string()), - (":name", &response.name), - (":description", &response.display_name), + (":name", &input.name), + (":description", &input.description), ], ) { - Ok(_) => HttpResponse::Created(), - Err(_) => HttpResponse::InternalServerError(), + Ok(_) => HttpResponse::Created().json(Favorite { + id: db.last_insert_rowid(), + user_id: auth.user_id, + lat: input.lat, + lng: input.lng, + name: input.name.clone(), + description: input.description.clone(), + }), + Err(_) => HttpResponse::InternalServerError().finish(), } } diff --git a/rust-backend/src/models.rs b/rust-backend/src/models.rs index a9fa37d..4892d0b 100644 --- a/rust-backend/src/models.rs +++ b/rust-backend/src/models.rs @@ -4,7 +4,7 @@ use rusqlite::{Row, Error}; #[derive(Serialize)] pub struct Favorite { - pub id: usize, + pub id: i64, pub user_id: String, pub lat: f64, pub lng: f64,