From 0c2fa9850ae9c2bd49264dd79956c0c96ad4cdcc Mon Sep 17 00:00:00 2001 From: oltimaloku Date: Sat, 11 May 2024 12:30:12 -0700 Subject: [PATCH] feat: clicking on user profile shows geo spheres created by that user --- .../friends/view/user_profile_screen.dart | 42 +++++++++++++++++-- .../services/geo_sphere_service.dart | 21 ++++++++++ .../view_model/geo_sphere_view_model.dart | 11 +++++ .../profile/views/profile_screen.dart | 37 +++++++++++++++- georeal/routes/geofences.py | 16 +++++++ 5 files changed, 123 insertions(+), 4 deletions(-) diff --git a/client/lib/features/friends/view/user_profile_screen.dart b/client/lib/features/friends/view/user_profile_screen.dart index 2fe1d36..dd41a51 100644 --- a/client/lib/features/friends/view/user_profile_screen.dart +++ b/client/lib/features/friends/view/user_profile_screen.dart @@ -1,23 +1,41 @@ // ignore_for_file: public_member_api_docs, sort_constructors_first import 'package:flutter/material.dart'; import 'package:georeal/features/friends/widgets/profile_layout.dart'; +import 'package:georeal/features/geo_sphere/view_model/geo_sphere_view_model.dart'; +import 'package:georeal/features/geo_sphere/widgets/geo_sphere_widget.dart'; import 'package:georeal/global_variables.dart'; import 'package:georeal/models/other_user.dart'; +import 'package:georeal/providers/user_provider'; +import 'package:provider/provider.dart'; -class UserProfileScreen extends StatelessWidget { +class UserProfileScreen extends StatefulWidget { OtherUser user; UserProfileScreen({ super.key, required this.user, }); + @override + State createState() => _UserProfileScreenState(); +} + +class _UserProfileScreenState extends State { + @override + void initState() { + // TODO: implement initState + super.initState(); + Future.microtask(() => + Provider.of(context, listen: false) + .fetchUserGeoSpheres(widget.user.id)); + } + @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( backgroundColor: GlobalVariables.backgroundColor, title: Text( - user.username, + widget.user.username, style: Theme.of(context) .textTheme .titleMedium @@ -25,10 +43,28 @@ class UserProfileScreen extends StatelessWidget { ), ), backgroundColor: GlobalVariables.backgroundColor, - body: const SafeArea( + body: SafeArea( child: Column( children: [ ProfileLayout(), + Expanded( + child: Consumer( + builder: (context, geoSphereViewModel, child) { + // geoSphereViewModel.fetchUserGeoSpheres(user.id); + return ListView.builder( + itemCount: geoSphereViewModel.selectedUserGeoSpheres.length, + itemBuilder: (context, index) { + var geoSphere = + geoSphereViewModel.selectedUserGeoSpheres[index]; + return Padding( + padding: const EdgeInsets.fromLTRB(20, 0, 20, 8), + child: GeoSphereWidget(geoSphere: geoSphere), + ); + }, + ); + }, + ), + ), ], ), ), diff --git a/client/lib/features/geo_sphere/services/geo_sphere_service.dart b/client/lib/features/geo_sphere/services/geo_sphere_service.dart index 43b584e..1575483 100644 --- a/client/lib/features/geo_sphere/services/geo_sphere_service.dart +++ b/client/lib/features/geo_sphere/services/geo_sphere_service.dart @@ -71,6 +71,27 @@ class GeoSphereService { } } + static Future?> getGeoSpheresByUserId(int userId) async { + try { + var response = + await http.get(Uri.parse('${EnvVariables.uri}/geofences/$userId')); + + if (response.statusCode == 200) { + List geofencesData = json.decode(response.body); + List geoSpheres = []; + for (var geofenceData in geofencesData) { + geoSpheres.add(GeoSphere.fromJson(geofenceData)); + } + return geoSpheres; + } else { + throw Exception( + 'Failed to get geospheres. Status code: ${response.statusCode}'); + } + } catch (e) { + throw Exception("Error occurred: $e"); + } + } + static Future deleteGeoSphere(int id) async { log('Deleting geosphere with id: $id'); try { diff --git a/client/lib/features/geo_sphere/view_model/geo_sphere_view_model.dart b/client/lib/features/geo_sphere/view_model/geo_sphere_view_model.dart index 906228f..94b0667 100644 --- a/client/lib/features/geo_sphere/view_model/geo_sphere_view_model.dart +++ b/client/lib/features/geo_sphere/view_model/geo_sphere_view_model.dart @@ -19,12 +19,14 @@ class GeoSphereViewModel extends ChangeNotifier { final LocationViewModel _locationViewModel; final List _geoSpheres = []; + List _selectedUserGeoSpheres = []; GeoSphereViewModel(this._locationViewModel) { fetchGeoSpheres(); } List get geoSpheres => _geoSpheres; + List get selectedUserGeoSpheres => _selectedUserGeoSpheres; Future fetchGeoSpheres() async { List? geoSpheres = await GeoSphereService.getAllGeoSpheres(); @@ -34,6 +36,15 @@ class GeoSphereViewModel extends ChangeNotifier { } } + Future fetchUserGeoSpheres(int userID) async { + List? userGeoSpheres = + await GeoSphereService.getGeoSpheresByUserId(userID); + if (userGeoSpheres != null) { + _selectedUserGeoSpheres = userGeoSpheres; + notifyListeners(); + } + } + Future setAndCreateGeoSphere( double radius, String name, int userID) async { LocationData? locationData = _locationViewModel.currentLocation; diff --git a/client/lib/features/profile/views/profile_screen.dart b/client/lib/features/profile/views/profile_screen.dart index bdbaefa..719571a 100644 --- a/client/lib/features/profile/views/profile_screen.dart +++ b/client/lib/features/profile/views/profile_screen.dart @@ -1,13 +1,30 @@ import 'package:flutter/material.dart'; import 'package:georeal/common/profile_photo.dart'; +import 'package:georeal/features/geo_sphere/view_model/geo_sphere_view_model.dart'; +import 'package:georeal/features/geo_sphere/widgets/geo_sphere_widget.dart'; import 'package:georeal/features/profile/views/friend_request_screen.dart'; import 'package:georeal/global_variables.dart'; import 'package:georeal/providers/user_provider'; import 'package:provider/provider.dart'; -class ProfileScreen extends StatelessWidget { +class ProfileScreen extends StatefulWidget { const ProfileScreen({super.key}); + @override + State createState() => _ProfileScreenState(); +} + +class _ProfileScreenState extends State { + @override + void initState() { + // TODO: implement initState + super.initState(); + Future.microtask(() => + Provider.of(context, listen: false) + .fetchUserGeoSpheres( + Provider.of(context, listen: false).user!.id)); + } + @override Widget build(BuildContext context) { final user = Provider.of(context, listen: false).user!; @@ -102,6 +119,24 @@ class ProfileScreen extends StatelessWidget { ), ), const Divider(), + Expanded( + child: Consumer( + builder: (context, geoSphereViewModel, child) { + // geoSphereViewModel.fetchUserGeoSpheres(user.id); + return ListView.builder( + itemCount: geoSphereViewModel.selectedUserGeoSpheres.length, + itemBuilder: (context, index) { + var geoSphere = + geoSphereViewModel.selectedUserGeoSpheres[index]; + return Padding( + padding: const EdgeInsets.fromLTRB(20, 0, 20, 8), + child: GeoSphereWidget(geoSphere: geoSphere), + ); + }, + ); + }, + ), + ), ], ), ), diff --git a/georeal/routes/geofences.py b/georeal/routes/geofences.py index f58a4c7..74c5258 100644 --- a/georeal/routes/geofences.py +++ b/georeal/routes/geofences.py @@ -25,6 +25,22 @@ def get_geofences() -> tuple[Response, int]: 'radius': g.radius, 'creator_id': g.creator_id, } for g in geofences]), 200 + +@geofences.route("/geofences/", methods=["GET"]) +def get_geofences_by_user(user_id: int) -> tuple[Response, int]: + """ + Get all regions that are geofenced by a specific user. + """ + geofences = Geofence.query.filter_by(creator_id=user_id).all() + return jsonify([{ + 'id': g.id, + 'name': g.name, + 'latitude': g.latitude, + 'longitude': g.longitude, + 'radius': g.radius, + 'creator_id': g.creator_id, + } for g in geofences]), 200 + @geofences.route("/geofences", methods=["POST"]) def create_geofence():