snapshot of https://github.com/flutter/samples.git (main, 2026-09-16; blobs > 131072B omitted)
Some checks failed
Main Branch CI / Test Flutter beta on ubuntu-latest (push) Has been skipped
Main Branch CI / Test Flutter stable on ubuntu-latest (push) Has been skipped
Main Branch CI / Test Flutter beta on macos-latest (push) Has been cancelled
Main Branch CI / Test Flutter stable on macos-latest (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-16 01:43:26 +05:00
commit 9ed6a80afa
2886 changed files with 140184 additions and 0 deletions

View File

@@ -0,0 +1,210 @@
// 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/material.dart';
import 'package:go_router/go_router.dart';
import '../../../domain/models/booking/booking_summary.dart';
import '../../../routing/routes.dart';
import '../../auth/logout/view_models/logout_viewmodel.dart';
import '../../core/localization/applocalization.dart';
import '../../core/themes/colors.dart';
import '../../core/themes/dimens.dart';
import '../../core/ui/date_format_start_end.dart';
import '../../core/ui/error_indicator.dart';
import '../view_models/home_viewmodel.dart';
import 'home_title.dart';
const String bookingButtonKey = 'booking-button';
class HomeScreen extends StatefulWidget {
const HomeScreen({
super.key,
required this.viewModel,
required this.logoutViewModel,
});
final HomeViewModel viewModel;
final LogoutViewModel logoutViewModel;
@override
State<HomeScreen> createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
@override
void initState() {
super.initState();
widget.viewModel.deleteBooking.addListener(_onResult);
}
@override
void didUpdateWidget(covariant HomeScreen oldWidget) {
super.didUpdateWidget(oldWidget);
oldWidget.viewModel.deleteBooking.removeListener(_onResult);
widget.viewModel.deleteBooking.addListener(_onResult);
}
@override
void dispose() {
widget.viewModel.deleteBooking.removeListener(_onResult);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
floatingActionButton: FloatingActionButton.extended(
// Workaround for https://github.com/flutter/flutter/issues/115358#issuecomment-2117157419
heroTag: null,
key: const ValueKey(bookingButtonKey),
onPressed: () => context.go(Routes.search),
label: Text(AppLocalization.of(context).bookNewTrip),
icon: const Icon(Icons.add_location_outlined),
),
body: SafeArea(
top: true,
bottom: true,
child: ListenableBuilder(
listenable: widget.viewModel.load,
builder: (context, child) {
if (widget.viewModel.load.running) {
return const Center(child: CircularProgressIndicator());
}
if (widget.viewModel.load.error) {
return ErrorIndicator(
title: AppLocalization.of(context).errorWhileLoadingHome,
label: AppLocalization.of(context).tryAgain,
onPressed: widget.viewModel.load.execute,
);
}
return child!;
},
child: ListenableBuilder(
listenable: widget.viewModel,
builder: (context, _) {
return CustomScrollView(
slivers: [
SliverToBoxAdapter(
child: Padding(
padding: EdgeInsets.symmetric(
vertical: Dimens.of(context).paddingScreenVertical,
horizontal: Dimens.of(context).paddingScreenHorizontal,
),
child: HomeHeader(
viewModel: widget.viewModel,
logoutViewModel: widget.logoutViewModel,
),
),
),
SliverList.builder(
itemCount: widget.viewModel.bookings.length,
itemBuilder: (_, index) => _Booking(
key: ValueKey(widget.viewModel.bookings[index].id),
booking: widget.viewModel.bookings[index],
onTap: () => context.push(
Routes.bookingWithId(
widget.viewModel.bookings[index].id,
),
),
confirmDismiss: (_) async {
// wait for command to complete
await widget.viewModel.deleteBooking.execute(
widget.viewModel.bookings[index].id,
);
// if command completed successfully, return true
if (widget.viewModel.deleteBooking.completed) {
// removes the dismissable from the list
return true;
} else {
// the dismissable stays in the list
return false;
}
},
),
),
],
);
},
),
),
),
);
}
void _onResult() {
if (widget.viewModel.deleteBooking.completed) {
widget.viewModel.deleteBooking.clearResult();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(AppLocalization.of(context).bookingDeleted)),
);
}
if (widget.viewModel.deleteBooking.error) {
widget.viewModel.deleteBooking.clearResult();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(AppLocalization.of(context).errorWhileDeletingBooking),
),
);
}
}
}
class _Booking extends StatelessWidget {
const _Booking({
super.key,
required this.booking,
required this.onTap,
required this.confirmDismiss,
});
final BookingSummary booking;
final GestureTapCallback onTap;
final ConfirmDismissCallback confirmDismiss;
@override
Widget build(BuildContext context) {
return Dismissible(
key: ValueKey(booking.id),
direction: DismissDirection.endToStart,
confirmDismiss: confirmDismiss,
background: Container(
color: AppColors.grey1,
child: const Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
Padding(
padding: EdgeInsets.only(right: Dimens.paddingHorizontal),
child: Icon(Icons.delete),
),
],
),
),
child: InkWell(
onTap: onTap,
child: Padding(
padding: EdgeInsets.symmetric(
horizontal: Dimens.of(context).paddingScreenHorizontal,
vertical: Dimens.paddingVertical,
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(booking.name, style: Theme.of(context).textTheme.titleLarge),
Text(
dateFormatStartEnd(
DateTimeRange(start: booking.startDate, end: booking.endDate),
),
style: Theme.of(context).textTheme.bodyLarge,
),
],
),
),
),
);
}
}

View File

@@ -0,0 +1,45 @@
import 'package:flutter/widgets.dart';
import 'package:provider/provider.dart';
import '../../../data/repositories/booking/booking_repository.dart';
import '../../../data/repositories/user/user_repository.dart';
import '../../auth/logout/view_models/logout_viewmodel.dart';
import '../view_models/home_viewmodel.dart';
import 'home_screen.dart';
class HomeScreenContainer extends StatefulWidget {
const HomeScreenContainer({super.key, required this.logoutViewModel});
final LogoutViewModel logoutViewModel;
@override
State<HomeScreenContainer> createState() => _HomeScreenContainerState();
}
class _HomeScreenContainerState extends State<HomeScreenContainer> {
late final HomeViewModel _viewModel;
@override
void initState() {
super.initState();
_viewModel = HomeViewModel(
bookingRepository: context.read<BookingRepository>(),
userRepository: context.read<UserRepository>(),
);
}
@override
Widget build(BuildContext context) {
return HomeScreen(
viewModel: _viewModel,
logoutViewModel: widget.logoutViewModel,
);
}
@override
void dispose() {
_viewModel.dispose();
super.dispose();
}
}

View File

@@ -0,0 +1,76 @@
// 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/material.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../auth/logout/view_models/logout_viewmodel.dart';
import '../../auth/logout/widgets/logout_button.dart';
import '../../core/localization/applocalization.dart';
import '../../core/themes/dimens.dart';
import '../view_models/home_viewmodel.dart';
class HomeHeader extends StatelessWidget {
const HomeHeader({
super.key,
required this.viewModel,
required this.logoutViewModel,
});
final HomeViewModel viewModel;
final LogoutViewModel logoutViewModel;
@override
Widget build(BuildContext context) {
final user = viewModel.user;
if (user == null) {
return const SizedBox();
}
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
ClipOval(
child: Image.asset(
user.picture,
width: Dimens.of(context).profilePictureSize,
height: Dimens.of(context).profilePictureSize,
),
),
LogoutButton(viewModel: logoutViewModel),
],
),
const SizedBox(height: Dimens.paddingVertical),
_Title(text: AppLocalization.of(context).nameTrips(user.name)),
],
);
}
}
class _Title extends StatelessWidget {
const _Title({required this.text});
final String text;
@override
Widget build(BuildContext context) {
return ShaderMask(
blendMode: BlendMode.srcIn,
shaderCallback: (bounds) => RadialGradient(
center: Alignment.bottomLeft,
radius: 2,
colors: [Colors.purple.shade700, Colors.purple.shade400],
).createShader(Rect.fromLTWH(0, 0, bounds.width, bounds.height)),
child: Text(
text,
style: GoogleFonts.rubik(
textStyle: Theme.of(context).textTheme.headlineLarge,
),
),
);
}
}