Skip to content

Commit

Permalink
Merge branch 'main' into navigation-to-map
Browse files Browse the repository at this point in the history
  • Loading branch information
Aderfish authored May 30, 2024
2 parents dfe8839 + 4c84b2f commit 1a5c8fd
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 12 deletions.
22 changes: 19 additions & 3 deletions lib/viewmodels/map/map_pin_view_model.dart
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,21 @@ class MapPinViewModel extends AutoDisposeAsyncNotifier<List<MapPinDetails>> {

/// Get nearby posts
Future<List<MapPinDetails>> _getNearbyPosts() async {
//checking if the location services are enabled directly here so that
//we throw the same exception as the challenge case
final locationCheck =
await ref.read(geolocationServiceProvider).checkLocationServices();

if (locationCheck != null) {
throw locationCheck;
}

try {
await ref.watch(livePositionStreamProvider.future);
} catch (e) {
ref.invalidate(livePositionStreamProvider);
}

final position = await ref.watch(livePositionStreamProvider.future);
final postRepository = ref.watch(postRepositoryServiceProvider);
final userRepository = ref.watch(userRepositoryServiceProvider);
Expand Down Expand Up @@ -106,14 +121,15 @@ class MapPinViewModel extends AutoDisposeAsyncNotifier<List<MapPinDetails>> {

/// Get user active challenges
Future<List<MapPinDetails>> _getUserChallenges() async {
final postRepository = ref.watch(postRepositoryServiceProvider);
final challengeRepostory = ref.watch(challengeRepositoryServiceProvider);
final userId = ref.watch(validLoggedInUserIdProvider);
// Only doing a read here, to decrease the number of database reads
// (we don't want to re-read the challenges when the position changes).
final position =
await ref.read(geolocationServiceProvider).getCurrentPosition();

final postRepository = ref.watch(postRepositoryServiceProvider);
final challengeRepostory = ref.watch(challengeRepositoryServiceProvider);
final userId = ref.watch(validLoggedInUserIdProvider);

final userChallenges = await challengeRepostory.getChallenges(
userId,
position,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import "package:flutter/material.dart";
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:proxima/models/ui/map_details.dart";
import "package:proxima/viewmodels/option_selection/map_selection_options_view_model.dart";
import "package:proxima/views/components/options/map/map_selection_options.dart";

Expand All @@ -13,12 +12,9 @@ class MapSelectionOptionChips extends ConsumerWidget {
);

const MapSelectionOptionChips({
required this.mapInfo,
super.key,
});

final MapDetails mapInfo;

@override
Widget build(BuildContext context, WidgetRef ref) {
final currentOption = ref.watch(mapSelectionOptionsViewModelProvider);
Expand Down
13 changes: 9 additions & 4 deletions lib/views/pages/home/content/map/components/post_map.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import "package:flutter/material.dart";
import "package:geolocator/geolocator.dart";
import "package:google_maps_flutter/google_maps_flutter.dart";
import "package:hooks_riverpod/hooks_riverpod.dart";
import "package:proxima/models/ui/map_details.dart";
Expand Down Expand Up @@ -67,11 +68,15 @@ class PostMap extends ConsumerWidget {
},
error: (error, _) {
//Pop up an error dialog if an error occurs
final dialog = ErrorAlert(error: error);

WidgetsBinding.instance.addPostFrameCallback((timestamp) {
showDialog(context: context, builder: dialog.build);
});
//ignore the location service disabled exception
//because we are already handling it in the mapPinViewModel
if (error is! LocationServiceDisabledException) {
final dialog = ErrorAlert(error: error);
WidgetsBinding.instance.addPostFrameCallback((timestamp) {
showDialog(context: context, builder: dialog.build);
});
}
},
loading: () => (),
);
Expand Down
2 changes: 1 addition & 1 deletion lib/views/pages/home/content/map/map_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ class MapScreen extends ConsumerWidget {
key: mapScreenKey,
body: Column(
children: [
MapSelectionOptionChips(mapInfo: value),
const MapSelectionOptionChips(),
const Divider(key: dividerKey),
PostMap(mapInfo: value, initialLocation: initialLocation),
],
Expand Down
3 changes: 3 additions & 0 deletions test/end2end/app_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,9 @@ void main() {
when(geoLocationService.getPositionStream()).thenAnswer(
(_) => Stream.value(startLocation),
);
when(geoLocationService.checkLocationServices()).thenAnswer(
(_) => Future.value(null),
);

firestorePostGenerator = FirestorePostGenerator();
});
Expand Down
8 changes: 8 additions & 0 deletions test/mocks/services/mock_geo_location_service.dart
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,12 @@ class MockGeolocationService extends Mock implements GeolocationService {
returnValue: Stream.value(userPosition0),
);
}

@override
Future<Exception?> checkLocationServices() {
return super.noSuchMethod(
Invocation.method(#checkLocationServices, []),
returnValue: Future.value(null),
);
}
}
88 changes: 88 additions & 0 deletions test/views/pages/map/dynamic_map_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ void main() {
when(geoLocationService.getPositionStream()).thenAnswer(
(_) => Stream.value(userPosition0),
);
when(geoLocationService.checkLocationServices()).thenAnswer(
(_) => Future.value(null),
);

postGenerator = FirestorePostGenerator();
});
Expand Down Expand Up @@ -476,4 +479,89 @@ void main() {
verifyResult: null,
);
});

group("location errors", () {
testWidgets("one error pop up occurs", (tester) async {
//make the location services fail

when(geoLocationService.checkLocationServices()).thenAnswer(
(_) => Future.value(Exception("Location services not enabled")),
);

await beginTest(tester);

//find an dialog with the error message
final errorPopUp = find.byType(Dialog);

expect(errorPopUp, findsExactly(1));

//find the error message
final errorText = find.text("Exception: Location services not enabled");
expect(errorText, findsOneWidget);
});

testWidgets("no error with user posts", (tester) async {
await beginTest(tester);

//disable the location services
when(geoLocationService.checkLocationServices()).thenAnswer(
(_) => Future.value(Exception("Location services not enabled")),
);

//click on user posts tab
final chip = find.byKey(
MapSelectionOptionChips.optionChipKeys[MapSelectionOptions.myPosts]!,
);
expect(chip, findsOneWidget);
await tester.tap(chip);
await tester.pumpAndSettle();

//no error dialog should appear
final errorPopUp = find.byType(Dialog);
expect(errorPopUp, findsNothing);
});

testWidgets("no errors when location services are re-enabled",
(tester) async {
//disable the location services
when(geoLocationService.checkLocationServices()).thenAnswer(
(_) => Future.value(Exception("Location services not enabled")),
);

await beginTest(tester);

//expect an error dialog
final errorPopUp = find.byType(Dialog);
expect(errorPopUp, findsExactly(1));

//make the Dialog disappear by tapping next to it
await tester.tapAt(const Offset(0, 0)); // Top-left corner of the screen
await tester.pumpAndSettle();

//click on the user posts tab
final chip = find.byKey(
MapSelectionOptionChips.optionChipKeys[MapSelectionOptions.myPosts]!,
);
expect(chip, findsOneWidget);
await tester.tap(chip);
await tester.pumpAndSettle();

//re-enable the location services
when(geoLocationService.checkLocationServices()).thenAnswer(
(_) => Future.value(null),
);

//click on the nearby posts tab
final nearbyChip = find.byKey(
MapSelectionOptionChips.optionChipKeys[MapSelectionOptions.nearby]!,
);
expect(nearbyChip, findsOneWidget);
await tester.tap(nearbyChip);
await tester.pumpAndSettle();

//expect no error dialog
final errorPopUpAfter = find.byType(Dialog);
expect(errorPopUpAfter, findsNothing);
});
});
}

0 comments on commit 1a5c8fd

Please sign in to comment.