diff --git a/CHANGELOG.md b/CHANGELOG.md index 3bb4049a441..11074b8910f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,5 +6,7 @@ Notable changes to the samples in this repository are listed here. ### compass_app +* Refresh the home screen after returning from the booking flow so newly + created trips appear immediately ([#2877](https://github.com/flutter/samples/issues/2877)). * Scope `LogoutViewModel` to the home route so it is not recreated on every `HomeHeader` rebuild ([#2604](https://github.com/flutter/samples/issues/2604)). diff --git a/compass_app/app/lib/ui/home/widgets/home_screen_container.dart b/compass_app/app/lib/ui/home/widgets/home_screen_container.dart index 5ec0cbcf701..49e339505f0 100644 --- a/compass_app/app/lib/ui/home/widgets/home_screen_container.dart +++ b/compass_app/app/lib/ui/home/widgets/home_screen_container.dart @@ -1,8 +1,14 @@ +// Copyright 2024 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + import 'package:flutter/widgets.dart'; +import 'package:go_router/go_router.dart'; import 'package:provider/provider.dart'; import '../../../data/repositories/booking/booking_repository.dart'; import '../../../data/repositories/user/user_repository.dart'; +import '../../../routing/routes.dart'; import '../../auth/logout/view_models/logout_viewmodel.dart'; import '../view_models/home_viewmodel.dart'; import 'home_screen.dart'; @@ -18,6 +24,8 @@ class HomeScreenContainer extends StatefulWidget { class _HomeScreenContainerState extends State { late final HomeViewModel _viewModel; + GoRouter? _router; + String? _currentPath; @override void initState() { @@ -29,6 +37,19 @@ class _HomeScreenContainerState extends State { ); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + + final router = GoRouter.of(context); + if (identical(_router, router)) return; + + _router?.routerDelegate.removeListener(_onRouteChanged); + _router = router; + _currentPath = router.routerDelegate.currentConfiguration.uri.path; + router.routerDelegate.addListener(_onRouteChanged); + } + @override Widget build(BuildContext context) { return HomeScreen( @@ -39,7 +60,16 @@ class _HomeScreenContainerState extends State { @override void dispose() { + _router?.routerDelegate.removeListener(_onRouteChanged); _viewModel.dispose(); super.dispose(); } + + void _onRouteChanged() { + final path = _router!.routerDelegate.currentConfiguration.uri.path; + if (path == Routes.home && _currentPath != Routes.home) { + _viewModel.load.execute(); + } + _currentPath = path; + } } diff --git a/compass_app/app/test/ui/home/widgets/home_screen_container_test.dart b/compass_app/app/test/ui/home/widgets/home_screen_container_test.dart new file mode 100644 index 00000000000..65448f7dbbb --- /dev/null +++ b/compass_app/app/test/ui/home/widgets/home_screen_container_test.dart @@ -0,0 +1,80 @@ +// Copyright 2024 The Flutter team. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +import 'package:compass_app/data/repositories/booking/booking_repository.dart'; +import 'package:compass_app/data/repositories/user/user_repository.dart'; +import 'package:compass_app/ui/auth/logout/view_models/logout_viewmodel.dart'; +import 'package:compass_app/ui/core/localization/applocalization.dart'; +import 'package:compass_app/ui/core/themes/theme.dart'; +import 'package:compass_app/ui/home/widgets/home_screen_container.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:go_router/go_router.dart'; +import 'package:provider/provider.dart'; + +import '../../../../testing/fakes/repositories/fake_auth_repository.dart'; +import '../../../../testing/fakes/repositories/fake_booking_repository.dart'; +import '../../../../testing/fakes/repositories/fake_itinerary_config_repository.dart'; +import '../../../../testing/fakes/repositories/fake_user_repository.dart'; +import '../../../../testing/models/booking.dart'; + +void main() { + testWidgets('reloads bookings when the home route becomes active', ( + tester, + ) async { + tester.view.devicePixelRatio = 1.0; + await tester.binding.setSurfaceSize(const Size(1200, 800)); + + final bookingRepository = FakeBookingRepository(); + final logoutViewModel = LogoutViewModel( + authRepository: FakeAuthRepository(), + itineraryConfigRepository: FakeItineraryConfigRepository(), + ); + final router = GoRouter( + routes: [ + GoRoute( + path: '/', + builder: (context, state) => + HomeScreenContainer(logoutViewModel: logoutViewModel), + routes: [ + GoRoute( + path: 'details', + builder: (context, state) => const SizedBox(), + ), + ], + ), + ], + ); + addTearDown(router.dispose); + + await tester.pumpWidget( + MultiProvider( + providers: [ + Provider.value(value: bookingRepository), + Provider.value(value: FakeUserRepository()), + ], + child: MaterialApp.router( + routerConfig: router, + localizationsDelegates: [ + GlobalWidgetsLocalizations.delegate, + GlobalMaterialLocalizations.delegate, + AppLocalizationDelegate(), + ], + theme: AppTheme.lightTheme, + ), + ), + ); + await tester.pumpAndSettle(); + + router.go('/details'); + await tester.pumpAndSettle(); + await bookingRepository.createBooking(kBooking); + + router.go('/'); + await tester.pumpAndSettle(); + + expect(find.text('name1, Europe'), findsOneWidget); + }); +}