1
0
mirror of https://github.com/flutter/samples.git synced 2026-08-25 01:21:59 +00:00

Release 3.47 (#2879)

Minor updates for release 3.47

## Pre-launch Checklist

- [x] I read the [Flutter Style Guide] _recently_, and have followed its
advice.
- [x] I signed the [CLA].
- [x] I read the [Contributors Guide].
- [x] I have added sample code updates to the [changelog].
- [x] I updated/added relevant documentation (doc comments with `///`).


If you need help, consider asking for advice on the #hackers-devrel
channel on [Discord].

<!-- Links -->
[Flutter Style Guide]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Style-guide-for-Flutter-repo.md
[CLA]: https://cla.developers.google.com/
[Discord]:
https://github.com/flutter/flutter/blob/master/docs/contributing/Chat.md
[Contributors Guide]:
https://github.com/flutter/samples/blob/main/CONTRIBUTING.md
[changelog]: ../CHANGELOG.md

---------

Co-authored-by: Parker Lougheed <parlough@gmail.com>
This commit is contained in:
Eric Windmill
2026-08-12 12:21:23 -07:00
committed by GitHub
parent e0136e5ebb
commit 0c5ca75d29
96 changed files with 1711 additions and 723 deletions

View File

@@ -1,5 +1,3 @@
include: package:flutter_lints/flutter.yaml
linter:
rules:
- combinators_ordering
@@ -9,3 +7,14 @@ linter:
- prefer_final_in_for_each
- prefer_final_locals
- prefer_relative_imports
analyzer:
exclude:
- build/**
- android/**
- ios/**
- web/**
- windows/**
- macos/**
- linux/**

View File

@@ -31,7 +31,7 @@ class BookingRepositoryRemote implements BookingRepository {
.map((activity) => activity.ref)
.toList(),
);
return _apiClient.postBooking(bookingApiModel);
return await _apiClient.postBooking(bookingApiModel);
} on Exception catch (e) {
return Result.error(e);
}
@@ -121,7 +121,7 @@ class BookingRepositoryRemote implements BookingRepository {
@override
Future<Result<void>> delete(int id) async {
try {
return _apiClient.deleteBooking(id);
return await _apiClient.deleteBooking(id);
} on Exception catch (e) {
return Result.error(e);
}

View File

@@ -85,7 +85,6 @@ class BookingCreateUseCase {
switch (saveBookingResult) {
case Ok<void>():
_log.fine('Booking saved successfully');
break;
case Error<void>():
_log.warning('Failed to save booking', saveBookingResult.error);
return Result.error(saveBookingResult.error);

View File

@@ -46,9 +46,7 @@ GoRouter router(AuthRepository authRepository) => GoRouter(
authRepository: context.read(),
itineraryConfigRepository: context.read(),
);
return HomeScreenContainer(
logoutViewModel: logoutViewModel,
);
return HomeScreenContainer(logoutViewModel: logoutViewModel);
},
routes: [
GoRoute(

View File

@@ -7,7 +7,7 @@ import 'package:flutter/material.dart';
class AppLocalization {
static AppLocalization of(BuildContext context) {
return Localizations.of(context, AppLocalization);
return Localizations.of<AppLocalization>(context, AppLocalization)!;
}
static const _strings = <String, String>{

View File

@@ -8,10 +8,7 @@ import '../view_models/home_viewmodel.dart';
import 'home_screen.dart';
class HomeScreenContainer extends StatefulWidget {
const HomeScreenContainer({
super.key,
required this.logoutViewModel,
});
const HomeScreenContainer({super.key, required this.logoutViewModel});
final LogoutViewModel logoutViewModel;

View File

@@ -52,7 +52,7 @@ class SearchFormContinent extends StatelessWidget {
scrollDirection: Axis.horizontal,
itemCount: viewModel.continents.length,
padding: Dimens.of(context).edgeInsetsScreenHorizontal,
itemBuilder: (BuildContext context, int index) {
itemBuilder: (context, index) {
final Continent(:imageUrl, :name) = viewModel.continents[index];
return _CarouselItem(
key: ValueKey(name),
@@ -61,7 +61,7 @@ class SearchFormContinent extends StatelessWidget {
viewModel: viewModel,
);
},
separatorBuilder: (BuildContext context, int index) {
separatorBuilder: (context, index) {
return const SizedBox(width: 8);
},
);

View File

@@ -5,13 +5,11 @@
import FlutterMacOS
import Foundation
import path_provider_foundation
import share_plus
import shared_preferences_foundation
import sqflite_darwin
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin"))
SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin"))
SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin"))

View File

@@ -45,14 +45,14 @@ void main() {
);
}
testWidgets('should load screen', (WidgetTester tester) async {
testWidgets('should load screen', (tester) async {
await mockNetworkImages(() async {
await loadScreen(tester);
expect(find.byType(ActivitiesScreen), findsOneWidget);
});
});
testWidgets('should list activity', (WidgetTester tester) async {
testWidgets('should list activity', (tester) async {
await mockNetworkImages(() async {
await loadScreen(tester);
expect(find.byType(ActivityEntry), findsOneWidget);
@@ -60,9 +60,7 @@ void main() {
});
});
testWidgets('should select activity and confirm', (
WidgetTester tester,
) async {
testWidgets('should select activity and confirm', (tester) async {
await mockNetworkImages(() async {
await loadScreen(tester);
// Select one activity

View File

@@ -32,14 +32,14 @@ void main() {
);
}
testWidgets('should load screen', (WidgetTester tester) async {
testWidgets('should load screen', (tester) async {
await mockNetworkImages(() async {
await loadScreen(tester);
expect(find.byType(LoginScreen), findsOneWidget);
});
});
testWidgets('should perform login', (WidgetTester tester) async {
testWidgets('should perform login', (tester) async {
await mockNetworkImages(() async {
await loadScreen(tester);

View File

@@ -43,14 +43,14 @@ void main() {
);
}
testWidgets('should load widget', (WidgetTester tester) async {
testWidgets('should load widget', (tester) async {
await mockNetworkImages(() async {
await loadScreen(tester);
expect(find.byType(LogoutButton), findsOneWidget);
});
});
testWidgets('should perform logout', (WidgetTester tester) async {
testWidgets('should perform logout', (tester) async {
await mockNetworkImages(() async {
await loadScreen(tester);

View File

@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:compass_app/domain/models/itinerary_config/itinerary_config.dart';
import 'package:compass_app/domain/use_cases/booking/booking_create_use_case.dart';
import 'package:compass_app/domain/use_cases/booking/booking_share_use_case.dart';
@@ -62,20 +64,20 @@ void main() {
);
}
testWidgets('should load screen', (WidgetTester tester) async {
testWidgets('should load screen', (tester) async {
await loadScreen(tester);
expect(find.byType(BookingScreen), findsOneWidget);
});
testWidgets('should display booking from ID', (WidgetTester tester) async {
testWidgets('should display booking from ID', (tester) async {
// Add a booking to repository
bookingRepository.createBooking(kBooking);
unawaited(bookingRepository.createBooking(kBooking));
// Load screen
await loadScreen(tester);
// Load booking with ID 0
viewModel.loadBooking.execute(0);
unawaited(viewModel.loadBooking.execute(0));
// Wait for booking to load
await tester.pumpAndSettle();
@@ -84,13 +86,11 @@ void main() {
expect(find.text(kBooking.destination.tags.first), findsOneWidget);
});
testWidgets('should create booking from itinerary config', (
WidgetTester tester,
) async {
testWidgets('should create booking from itinerary config', (tester) async {
await loadScreen(tester);
// Create a new booking from stored itinerary config
viewModel.createBooking.execute();
unawaited(viewModel.createBooking.execute());
// Wait for booking to load
await tester.pumpAndSettle();
@@ -102,10 +102,10 @@ void main() {
expect(bookingRepository.bookings.length, 1);
});
testWidgets('should share booking', (WidgetTester tester) async {
bookingRepository.createBooking(kBooking);
testWidgets('should share booking', (tester) async {
unawaited(bookingRepository.createBooking(kBooking));
await loadScreen(tester);
viewModel.loadBooking.execute(0);
unawaited(viewModel.loadBooking.execute(0));
await tester.pumpAndSettle();
await tester.tap(find.byKey(const Key('share-button')));
expect(shared, true);

View File

@@ -43,10 +43,7 @@ void main() {
Future<void> loadWidget(WidgetTester tester) async {
await testApp(
tester,
HomeScreen(
viewModel: viewModel,
logoutViewModel: logoutViewModel,
),
HomeScreen(viewModel: viewModel, logoutViewModel: logoutViewModel),
goRouter: goRouter,
);
}

View File

@@ -42,14 +42,14 @@ void main() {
);
}
testWidgets('should load screen', (WidgetTester tester) async {
testWidgets('should load screen', (tester) async {
await mockNetworkImages(() async {
await loadScreen(tester);
expect(find.byType(ResultsScreen), findsOneWidget);
});
});
testWidgets('should display destination', (WidgetTester tester) async {
testWidgets('should display destination', (tester) async {
await mockNetworkImages(() async {
await loadScreen(tester);
@@ -62,9 +62,7 @@ void main() {
});
});
testWidgets('should tap and navigate to activities', (
WidgetTester tester,
) async {
testWidgets('should tap and navigate to activities', (tester) async {
await mockNetworkImages(() async {
await loadScreen(tester);

View File

@@ -25,9 +25,7 @@ void main() {
await testApp(tester, SearchFormContinent(viewModel: viewModel));
}
testWidgets('Should load and select continent', (
WidgetTester tester,
) async {
testWidgets('Should load and select continent', (tester) async {
await loadWidget(tester);
expect(find.byType(SearchFormContinent), findsOneWidget);

View File

@@ -26,9 +26,7 @@ void main() {
await testApp(tester, SearchFormDate(viewModel: viewModel));
}
testWidgets('should display date in different month', (
WidgetTester tester,
) async {
testWidgets('should display date in different month', (tester) async {
await loadWidget(tester);
expect(find.byType(SearchFormDate), findsOneWidget);
@@ -45,9 +43,7 @@ void main() {
expect(find.text('12 Jun - 23 Jul'), findsOneWidget);
});
testWidgets('should display date in same month', (
WidgetTester tester,
) async {
testWidgets('should display date in same month', (tester) async {
await loadWidget(tester);
expect(find.byType(SearchFormDate), findsOneWidget);

View File

@@ -26,7 +26,7 @@ void main() {
await testApp(tester, SearchFormGuests(viewModel: viewModel));
}
testWidgets('Increase number of guests', (WidgetTester tester) async {
testWidgets('Increase number of guests', (tester) async {
await loadWidget(tester);
expect(find.byType(SearchFormGuests), findsOneWidget);
@@ -39,7 +39,7 @@ void main() {
expect(find.text('1'), findsOneWidget);
});
testWidgets('Decrease number of guests', (WidgetTester tester) async {
testWidgets('Decrease number of guests', (tester) async {
await loadWidget(tester);
expect(find.byType(SearchFormGuests), findsOneWidget);

View File

@@ -46,9 +46,7 @@ void main() {
);
}
testWidgets('Should fill form and perform search', (
WidgetTester tester,
) async {
testWidgets('Should fill form and perform search', (tester) async {
await loadWidget(tester);
expect(find.byType(SearchFormScreen), findsOneWidget);

View File

@@ -34,7 +34,7 @@ void main() {
);
}
testWidgets('Should be enabled and allow tap', (WidgetTester tester) async {
testWidgets('Should be enabled and allow tap', (tester) async {
await loadWidget(tester);
expect(find.byType(SearchFormSubmit), findsOneWidget);

View File

@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'dart:async';
import 'package:compass_app/utils/command.dart';
import 'package:compass_app/utils/result.dart';
import 'package:flutter_test/flutter_test.dart';
@@ -53,10 +55,10 @@ void main() {
final future = command.execute();
// Run multiple times
command.execute();
command.execute();
command.execute();
command.execute();
unawaited(command.execute());
unawaited(command.execute());
unawaited(command.execute());
unawaited(command.execute());
// Await execution
await future;