From effb4d7f185f74067de05e95e3fe58d0e0878897 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vanden=20Bossche?= Date: Sun, 14 Jul 2024 17:07:52 +0200 Subject: [PATCH 1/4] Fixed bad bounds --- .../fragments/details/event_details_map.dart | 50 +++--- .../event/screens/event_details_screen.dart | 1 + .../lib/event/widgets/map/journey_map.dart | 10 +- .../screen/import_gpx_tool_screen.dart | 163 ++++++++++-------- .../app/lib/journey/service/journey_api.dart | 4 +- .../journey/widgets/journey_tools_modal.dart | 2 +- .../user_positions/user_positions_bloc.dart | 5 + packages/app/lib/shared/types/geojson.dart | 18 +- .../screens/user_journey_map.dart | 88 +++++----- .../hollybike/api/services/PositionService.kt | 1 + 10 files changed, 188 insertions(+), 154 deletions(-) diff --git a/packages/app/lib/event/fragments/details/event_details_map.dart b/packages/app/lib/event/fragments/details/event_details_map.dart index 45bfc5fa..89b024be 100644 --- a/packages/app/lib/event/fragments/details/event_details_map.dart +++ b/packages/app/lib/event/fragments/details/event_details_map.dart @@ -53,29 +53,7 @@ class _EventDetailsMapState extends State { .of(context) .size .width * 0.1, - child: Column( - mainAxisSize: MainAxisSize.max, - mainAxisAlignment: MainAxisAlignment.center, - children: [ - SizedBox( - height: 100, - child: Lottie.asset( - fit: BoxFit.cover, - 'assets/lottie/lottie_journey.json', - repeat: false, - ), - ), - const SizedBox(height: 16), - Text( - 'Aucun trajet lié à cet évènement ou aucun utilisateur ne partage sa position.', - style: Theme - .of(context) - .textTheme - .bodyMedium, - textAlign: TextAlign.center, - ), - ], - ), + child: _buildPlaceholder(), ), ); } @@ -92,6 +70,32 @@ class _EventDetailsMapState extends State { ); } + Widget _buildPlaceholder() { + return Column( + mainAxisSize: MainAxisSize.max, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + SizedBox( + height: 100, + child: Lottie.asset( + fit: BoxFit.cover, + 'assets/lottie/lottie_journey.json', + repeat: false, + ), + ), + const SizedBox(height: 16), + Text( + 'Aucun trajet lié à cet évènement ou aucun utilisateur ne partage sa position.', + style: Theme + .of(context) + .textTheme + .bodyMedium, + textAlign: TextAlign.center, + ), + ], + ); + } + Future _refreshEventDetails(BuildContext context) { context.read().add( LoadEventDetails(), diff --git a/packages/app/lib/event/screens/event_details_screen.dart b/packages/app/lib/event/screens/event_details_screen.dart index 2a671669..e669777d 100644 --- a/packages/app/lib/event/screens/event_details_screen.dart +++ b/packages/app/lib/event/screens/event_details_screen.dart @@ -330,6 +330,7 @@ class _EventDetailsScreenState extends State profileRepository: RepositoryProvider.of( context, ), + canSeeUserPositions: eventDetails.isParticipating, ), child: EventDetailsMap( eventId: eventDetails.event.id, diff --git a/packages/app/lib/event/widgets/map/journey_map.dart b/packages/app/lib/event/widgets/map/journey_map.dart index fe02999c..86ad5f9c 100644 --- a/packages/app/lib/event/widgets/map/journey_map.dart +++ b/packages/app/lib/event/widgets/map/journey_map.dart @@ -224,7 +224,9 @@ class _JourneyMapState extends State { final bbox = geoJsonRaw == null ? GeoJSON.calculateBbox(userCoordinates) - : GeoJSON.fromJsonString(geoJsonRaw).dynamicBBox(); + : GeoJSON.fromJsonString(geoJsonRaw).dynamicBBox( + extraValues: userCoordinates, + ); final bounds = CoordinateBounds( southwest: Point( @@ -336,7 +338,8 @@ class _JourneyMapState extends State { ? profilePicture.image : placeholderProfilePicture) as Uint8List, iconAnchor: IconAnchor.BOTTOM, - textField: '${user.user.username}\n${(missingPosition.speed * 3.6).round()} km/h', + textField: + '${user.user.username}\n${(missingPosition.speed * 3.6).round()} km/h', textAnchor: TextAnchor.TOP, textSize: 12, textHaloWidth: 2, @@ -373,7 +376,8 @@ class _JourneyMapState extends State { ? profilePicture.image : placeholderProfilePicture) as Uint8List; - point.textField = '${user.user.username}\n${(positionToUpdate.speed * 3.6).round()} km/h'; + point.textField = + '${user.user.username}\n${(positionToUpdate.speed * 3.6).round()} km/h'; } await pointManager.update(point); diff --git a/packages/app/lib/journey/screen/import_gpx_tool_screen.dart b/packages/app/lib/journey/screen/import_gpx_tool_screen.dart index d6650d50..913567f5 100644 --- a/packages/app/lib/journey/screen/import_gpx_tool_screen.dart +++ b/packages/app/lib/journey/screen/import_gpx_tool_screen.dart @@ -4,7 +4,6 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:flutter_inappwebview/flutter_inappwebview.dart'; import 'package:hollybike/shared/utils/safe_set_state.dart'; - import 'package:http/http.dart' as http; import 'package:path/path.dart' as path; @@ -54,94 +53,103 @@ class _ImportGpxToolScreenState extends State { }, child: Scaffold( body: SafeArea( - child: InAppWebView( - initialUrlRequest: URLRequest( - url: Uri.parse(widget.url), - ), - initialOptions: InAppWebViewGroupOptions( - crossPlatform: InAppWebViewOptions( - useOnDownloadStart: true, - useShouldInterceptFetchRequest: true, + child: Builder(builder: (context) { + return InAppWebView( + initialUrlRequest: URLRequest( + url: Uri.parse(widget.url), ), - ), - onWebViewCreated: (controller) { - _controller = controller; - }, - onLoadStart: (controller, url) {}, - onLoadStop: (controller, url) {}, - shouldInterceptFetchRequest: (controller, request) async { - final url = request.url.toString(); - - final isKurvigerFile = - url.startsWith("https://api.kurviger.de/route"); - final isOpenrunnerFile = - url.startsWith("https://api.openrunner.com/api/v2/routes/") && - url.endsWith("/export/gpx-track"); - - if (isKurvigerFile || isOpenrunnerFile) { - final response = await http.get( - Uri.parse(url), - headers: { - 'User-Agent': request.headers?['User-Agent'] ?? '', - 'Accept': request.headers?['Accept'] ?? '', - }, - ); - - if (response.body.contains(' { return file; } + + void _onGpxDownloaded(BuildContext context, File file) async { + print('GPX downloaded: ${file.path}'); + await context.router.maybePop(); + + widget.onGpxDownloaded(file); + } } diff --git a/packages/app/lib/journey/service/journey_api.dart b/packages/app/lib/journey/service/journey_api.dart index 98d8236d..03f4ae55 100644 --- a/packages/app/lib/journey/service/journey_api.dart +++ b/packages/app/lib/journey/service/journey_api.dart @@ -50,7 +50,9 @@ class JourneyApi { } Future getPositions(int journeyId) async { - final response = await client.dio.get('/journeys/$journeyId/positions'); + final response = await client.dio.get( + '/journeys/$journeyId/positions' + ); return Journey.fromJson(response.data); } diff --git a/packages/app/lib/journey/widgets/journey_tools_modal.dart b/packages/app/lib/journey/widgets/journey_tools_modal.dart index c7335119..0930ba73 100644 --- a/packages/app/lib/journey/widgets/journey_tools_modal.dart +++ b/packages/app/lib/journey/widgets/journey_tools_modal.dart @@ -100,7 +100,7 @@ class JourneyToolsModal extends StatelessWidget { ImportGpxToolRoute( url: tool.url, onGpxDownloaded: (file) { - Navigator.of(context).pop(); + print('File downloaded'); onGpxDownloaded(file); }, diff --git a/packages/app/lib/positions/bloc/user_positions/user_positions_bloc.dart b/packages/app/lib/positions/bloc/user_positions/user_positions_bloc.dart index 5f2238ca..034aae2a 100644 --- a/packages/app/lib/positions/bloc/user_positions/user_positions_bloc.dart +++ b/packages/app/lib/positions/bloc/user_positions/user_positions_bloc.dart @@ -23,9 +23,12 @@ class UserPositionsBloc extends Bloc { final AuthPersistence authPersistence; final ProfileRepository profileRepository; + final bool canSeeUserPositions ; + UserPositionsBloc({ required this.authPersistence, required this.profileRepository, + required this.canSeeUserPositions, AuthSession? currentSession, }) : super(UserPositionsInitial()) { on(_onSubscribeToUserPositions); @@ -59,6 +62,8 @@ class UserPositionsBloc extends Bloc { SubscribeToUserPositions event, Emitter emit, ) async { + if (!canSeeUserPositions) return; + emit(UserPositionsLoading(state)); final currentSession = await authPersistence.currentSession; diff --git a/packages/app/lib/shared/types/geojson.dart b/packages/app/lib/shared/types/geojson.dart index bf79b149..e7a7e670 100644 --- a/packages/app/lib/shared/types/geojson.dart +++ b/packages/app/lib/shared/types/geojson.dart @@ -4,7 +4,6 @@ import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:hollybike/shared/types/json_map.dart'; part 'geojson.freezed.dart'; - part 'geojson.g.dart'; @freezed @@ -44,8 +43,8 @@ class GeoJSON with _$GeoJSON { static List calculateBbox( List coordinates, { - double verticalPaddingPercentage = 0.2, - double horizontalPaddingPercentage = 0.5, + double verticalPaddingPercentage = 0.1, + double horizontalPaddingPercentage = 0.1, }) { double min(double a, double b) => (a < b) ? a : b; double max(double a, double b) => (a > b) ? a : b; @@ -73,10 +72,15 @@ class GeoJSON with _$GeoJSON { double paddingWidth = realWidth * horizontalPaddingPercentage; double paddingHeight = realHeight * verticalPaddingPercentage; - bbox[0] -= paddingWidth; - bbox[1] -= paddingHeight; - bbox[2] += paddingWidth; - bbox[3] += paddingHeight; + final adjustedHeight = + realHeight > realWidth ? realHeight : (realWidth - realHeight); + final adjustedWidth = + realWidth > realHeight ? realWidth : (realHeight - realWidth); + + bbox[0] -= (adjustedWidth + paddingWidth); + bbox[1] -= (adjustedHeight + paddingHeight); + bbox[2] += (adjustedWidth + paddingWidth); + bbox[3] += (adjustedHeight + paddingHeight); return bbox; } diff --git a/packages/app/lib/user_journey/screens/user_journey_map.dart b/packages/app/lib/user_journey/screens/user_journey_map.dart index b0ef3288..1256f123 100644 --- a/packages/app/lib/user_journey/screens/user_journey_map.dart +++ b/packages/app/lib/user_journey/screens/user_journey_map.dart @@ -12,9 +12,8 @@ import 'package:hollybike/shared/widgets/bar/top_bar_action_icon.dart'; import 'package:hollybike/shared/widgets/bar/top_bar_title.dart'; import 'package:hollybike/shared/widgets/hud/hud.dart'; import 'package:hollybike/theme/bloc/theme_bloc.dart'; -import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart'; - import 'package:http/http.dart' as http; +import 'package:mapbox_maps_flutter/mapbox_maps_flutter.dart'; @RoutePage() class UserJourneyMapScreen extends StatefulWidget { @@ -46,52 +45,51 @@ class _UserJourneyMapScreenState extends State { title: TopBarTitle(widget.title), ), body: SizedBox( - child: Builder( - builder: (context) { - if (_mapError) { - return Center( - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - const Text("Erreur lors du chargement de la carte"), - const SizedBox(height: 16), - ElevatedButton( - onPressed: () => context.router.maybePop(), - child: const Text("Retour"), - ), - ], - ), - ); - } - - return Stack( - children: [ - MapWidget( - gestureRecognizers: >{ - Factory( - () => EagerGestureRecognizer(), - ), - }, - key: const ValueKey("mapWidget"), - onMapCreated: _onMapCreated, - ), - AnimatedOpacity( - opacity: _mapLoading ? 1 : 0, - duration: const Duration(milliseconds: 500), - child: IgnorePointer( - child: Container( - color: Theme.of(context).scaffoldBackgroundColor, - child: const Center( - child: CircularProgressIndicator(), - ), + child: Builder(builder: (context) { + if (_mapError) { + return Center( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + const Text("Erreur lors du chargement de la carte"), + const SizedBox(height: 16), + ElevatedButton( + onPressed: () => context.router.maybePop(), + child: const Text("Retour"), + ), + ], + ), + ); + } + + return Stack( + children: [ + MapWidget( + gestureRecognizers: >{ + Factory( + () => EagerGestureRecognizer(), + ), + }, + key: const ValueKey("mapWidget"), + onMapCreated: _onMapCreated, + ), + AnimatedOpacity( + opacity: _mapLoading ? 1 : 0, + duration: const Duration(milliseconds: 500), + child: IgnorePointer( + child: Container( + color: Theme.of(context).scaffoldBackgroundColor, + child: const Center( + child: CircularProgressIndicator(), ), ), ), - ], - ); - }), - ), - ); + ), + ], + ); + }), + ), + ); } void _onMapCreated(MapboxMap map) { diff --git a/packages/backend/src/main/kotlin/hollybike/api/services/PositionService.kt b/packages/backend/src/main/kotlin/hollybike/api/services/PositionService.kt index 7f55fa6f..451d434b 100644 --- a/packages/backend/src/main/kotlin/hollybike/api/services/PositionService.kt +++ b/packages/backend/src/main/kotlin/hollybike/api/services/PositionService.kt @@ -143,6 +143,7 @@ class PositionService( url { protocol = URLProtocol.HTTPS host = "nominatim.openstreetmap.org" + headers.append("User-Agent", "HollyBike/1.0") path("reverse") parameters.append("lat", positionRequest.latitude.toString()) parameters.append("lon", positionRequest.longitude.toString()) From cf5869dd616fb349132c675d17993e32b2599fd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vanden=20Bossche?= Date: Sun, 14 Jul 2024 17:12:23 +0200 Subject: [PATCH 2/4] Fixed ui when missing positions --- packages/app/lib/journey/widgets/journey_location.dart | 9 +++++---- packages/app/lib/journey/widgets/journey_position.dart | 6 +----- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/packages/app/lib/journey/widgets/journey_location.dart b/packages/app/lib/journey/widgets/journey_location.dart index b7da94d6..0e5f3dab 100644 --- a/packages/app/lib/journey/widgets/journey_location.dart +++ b/packages/app/lib/journey/widgets/journey_location.dart @@ -17,8 +17,9 @@ class JourneyLocation extends StatelessWidget { Widget build(BuildContext context) { final locations = []; - final start = JourneyPosition(pos: journey.start, isLarge: sizeFactor > 1); - if (start is! SizedBox) { + if (journey.start != null) { + final start = JourneyPosition(pos: journey.start!, isLarge: sizeFactor > 1); + locations.add(Row( children: [ Icon( @@ -35,8 +36,8 @@ class JourneyLocation extends StatelessWidget { locations.add(SizedBox(height: 8 * sizeFactor)); } - final end = JourneyPosition(pos: journey.end, isLarge: sizeFactor > 1); - if (start is! SizedBox) { + if (journey.end != null) { + final end = JourneyPosition(pos: journey.end!, isLarge: sizeFactor > 1); locations.add(Row( children: [ Icon( diff --git a/packages/app/lib/journey/widgets/journey_position.dart b/packages/app/lib/journey/widgets/journey_position.dart index ba97ff55..a904a286 100644 --- a/packages/app/lib/journey/widgets/journey_position.dart +++ b/packages/app/lib/journey/widgets/journey_position.dart @@ -4,7 +4,7 @@ import '../../shared/types/position.dart'; class JourneyPosition extends StatelessWidget { final bool isLarge; - final Position? pos; + final Position pos; const JourneyPosition({ super.key, @@ -14,10 +14,6 @@ class JourneyPosition extends StatelessWidget { @override Widget build(BuildContext context) { - if (pos == null) { - return const SizedBox(); - } - final textStyle = getTextStyle(context); final texts = []; From b238a31607639b9426e469b75395bd9aa9a808d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vanden=20Bossche?= Date: Sun, 14 Jul 2024 17:16:04 +0200 Subject: [PATCH 3/4] Fixed flutter analyze --- packages/app/lib/journey/screen/import_gpx_tool_screen.dart | 1 - packages/app/lib/journey/widgets/journey_position.dart | 6 +++--- packages/app/lib/journey/widgets/journey_tools_modal.dart | 6 +----- 3 files changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/app/lib/journey/screen/import_gpx_tool_screen.dart b/packages/app/lib/journey/screen/import_gpx_tool_screen.dart index 913567f5..040deb69 100644 --- a/packages/app/lib/journey/screen/import_gpx_tool_screen.dart +++ b/packages/app/lib/journey/screen/import_gpx_tool_screen.dart @@ -173,7 +173,6 @@ class _ImportGpxToolScreenState extends State { } void _onGpxDownloaded(BuildContext context, File file) async { - print('GPX downloaded: ${file.path}'); await context.router.maybePop(); widget.onGpxDownloaded(file); diff --git a/packages/app/lib/journey/widgets/journey_position.dart b/packages/app/lib/journey/widgets/journey_position.dart index a904a286..b39cc92c 100644 --- a/packages/app/lib/journey/widgets/journey_position.dart +++ b/packages/app/lib/journey/widgets/journey_position.dart @@ -31,9 +31,9 @@ class JourneyPosition extends StatelessWidget { texts.add(span); } - final countyName = pos?.countyName; - final cityName = pos?.cityName; - final countryName = pos?.countryName; + final countyName = pos.countyName; + final cityName = pos.cityName; + final countryName = pos.countryName; if (cityName != null) { addSpan(TextSpan( diff --git a/packages/app/lib/journey/widgets/journey_tools_modal.dart b/packages/app/lib/journey/widgets/journey_tools_modal.dart index 0930ba73..79c8c15e 100644 --- a/packages/app/lib/journey/widgets/journey_tools_modal.dart +++ b/packages/app/lib/journey/widgets/journey_tools_modal.dart @@ -99,11 +99,7 @@ class JourneyToolsModal extends StatelessWidget { context.router.push( ImportGpxToolRoute( url: tool.url, - onGpxDownloaded: (file) { - print('File downloaded'); - - onGpxDownloaded(file); - }, + onGpxDownloaded: onGpxDownloaded, onClose: () => Navigator.of(context).pop(), ), ); From 34c12c550d13979439978600f1d3b6709820feac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Vanden=20Bossche?= Date: Sun, 14 Jul 2024 17:26:33 +0200 Subject: [PATCH 4/4] Fixed tests --- .../src/test/kotlin/hollybike/api/AuthenticationTest.kt | 4 ++-- packages/backend/src/test/kotlin/hollybike/api/UserTest.kt | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/test/kotlin/hollybike/api/AuthenticationTest.kt b/packages/backend/src/test/kotlin/hollybike/api/AuthenticationTest.kt index 04bf6bd7..dc2acd9d 100644 --- a/packages/backend/src/test/kotlin/hollybike/api/AuthenticationTest.kt +++ b/packages/backend/src/test/kotlin/hollybike/api/AuthenticationTest.kt @@ -283,8 +283,8 @@ class AuthenticationTest : IntegrationSpec({ ) ) }.apply { - status shouldBe HttpStatusCode.NotFound - bodyAsText() shouldBe "Aucune invitation valide" + status shouldBe HttpStatusCode.BadRequest + bodyAsText() shouldBe "Le mot de passe doit faire 8 caractère minimum" } } } diff --git a/packages/backend/src/test/kotlin/hollybike/api/UserTest.kt b/packages/backend/src/test/kotlin/hollybike/api/UserTest.kt index 5c327595..1e73861d 100644 --- a/packages/backend/src/test/kotlin/hollybike/api/UserTest.kt +++ b/packages/backend/src/test/kotlin/hollybike/api/UserTest.kt @@ -405,7 +405,7 @@ class UserTest : IntegrationSpec({ ) ) }.apply { - status shouldBe HttpStatusCode.Forbidden + status shouldBe HttpStatusCode.Unauthorized bodyAsText() shouldBe "Mauvais ancien mot de passe" } }