6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit 558cee23

AuthorNKL<nikolaj.king@gmail.com>
Date2025-12-08 08:42:04 +0100
added a click when scroll starting

Changed files

.../lib/booking_details/booking_details_page.dart  | 145 ++++++++++++++-------
 .../components/booking_details_bottom_sheet.dart   |   9 +-
 2 files changed, 102 insertions(+), 52 deletions(-)

Diff

diff --git a/comwell_key_app/lib/booking_details/booking_details_page.dart b/comwell_key_app/lib/booking_details/booking_details_page.dart
index c3bc603d..71bcb4d3 100644
--- a/comwell_key_app/lib/booking_details/booking_details_page.dart
+++ b/comwell_key_app/lib/booking_details/booking_details_page.dart
@@ -11,6 +11,7 @@ import 'package:comwell_key_app/routing/app_routes.dart';
import 'package:comwell_key_app/services/mappers/booking_mapper.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
import 'package:flutter/material.dart';
+import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
@@ -92,53 +93,14 @@ class BookingDetailsPage extends StatelessWidget {
? ShareButton(guests: state.guests)
: const SizedBox(),
),
- // Scrollable content
- SingleChildScrollView(
- child: Column(
- children: [
- // Top section with room info - leaves 60px for sheet peek
- SizedBox(
- height: screenHeight - 100,
- child: SafeArea(
- bottom: false,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.center,
- mainAxisAlignment: MainAxisAlignment.end,
- children: [
- if (cubit.booking.roomNumber != '')
- RoomNumberContainer(cubit: cubit),
- _buildBookingDetailsInformation(
- context, state, cubit, theme),
- const Padding(
- padding: EdgeInsets.symmetric(horizontal: 16.0),
- child: Divider(color: colorDivider),
- ),
- const SizedBox(height: 10),
- if (state.keys.isNotEmpty &&
- cubit.booking.roomNumber != '' &&
- state.keys
- .any((key) => key.label == cubit.booking.roomNumber))
- UnlockRoomButton(roomNumber: cubit.booking.roomNumber)
- else if (cubit.booking.reservationStatus ==
- ReservationStatus.checkedin)
- const GetKeysButton()
- else if (cubit.booking.reservationStatus ==
- ReservationStatus.preregistered)
- const CheckInButtonTimer()
- else if (cubit.booking.reservationStatus ==
- ReservationStatus.newreservation)
- const PreregisterButton()
- else
- const SizedBox(),
- const SizedBox(height: 24),
- ],
- ),
- ),
- ),
- // Bottom sheet content (scrollable, styled like a sheet)
- BookingDetailsBottomSheet(cubit: cubit, state: state),
- ],
- ),
+ // Scrollable content with haptic feedback
+ _ScrollableBookingContent(
+ screenHeight: screenHeight,
+ cubit: cubit,
+ state: state,
+ theme: theme,
+ buildBookingDetailsInformation: () =>
+ _buildBookingDetailsInformation(context, state, cubit, theme),
),
],
);
@@ -203,3 +165,92 @@ class BookingDetailsPage extends StatelessWidget {
);
}
}
+
+class _ScrollableBookingContent extends StatefulWidget {
+ final double screenHeight;
+ final BookingDetailsBloc cubit;
+ final BookingDetailsState state;
+ final ThemeData theme;
+ final Widget Function() buildBookingDetailsInformation;
+
+ const _ScrollableBookingContent({
+ required this.screenHeight,
+ required this.cubit,
+ required this.state,
+ required this.theme,
+ required this.buildBookingDetailsInformation,
+ });
+
+ @override
+ State<_ScrollableBookingContent> createState() =>
+ _ScrollableBookingContentState();
+}
+
+class _ScrollableBookingContentState extends State<_ScrollableBookingContent> {
+ bool _hasTriggeredHaptic = false;
+
+ void _onScroll(double offset) {
+ if (offset > 0 && !_hasTriggeredHaptic) {
+ HapticFeedback.lightImpact();
+ _hasTriggeredHaptic = true;
+ } else if (offset == 0) {
+ _hasTriggeredHaptic = false;
+ }
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ return NotificationListener<ScrollNotification>(
+ onNotification: (notification) {
+ _onScroll(notification.metrics.pixels);
+ return false;
+ },
+ child: SingleChildScrollView(
+ child: Column(
+ children: [
+ // Top section with room info - leaves 100px for sheet peek
+ SizedBox(
+ height: widget.screenHeight - 100,
+ child: SafeArea(
+ bottom: false,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.center,
+ mainAxisAlignment: MainAxisAlignment.end,
+ children: [
+ if (widget.cubit.booking.roomNumber != '')
+ RoomNumberContainer(cubit: widget.cubit),
+ widget.buildBookingDetailsInformation(),
+ const Padding(
+ padding: EdgeInsets.symmetric(horizontal: 16.0),
+ child: Divider(color: colorDivider),
+ ),
+ const SizedBox(height: 10),
+ if (widget.state.keys.isNotEmpty &&
+ widget.cubit.booking.roomNumber != '' &&
+ widget.state.keys.any(
+ (key) => key.label == widget.cubit.booking.roomNumber))
+ UnlockRoomButton(roomNumber: widget.cubit.booking.roomNumber)
+ else if (widget.cubit.booking.reservationStatus ==
+ ReservationStatus.checkedin)
+ const GetKeysButton()
+ else if (widget.cubit.booking.reservationStatus ==
+ ReservationStatus.preregistered)
+ const CheckInButtonTimer()
+ else if (widget.cubit.booking.reservationStatus ==
+ ReservationStatus.newreservation)
+ const PreregisterButton()
+ else
+ const SizedBox(),
+ const SizedBox(height: 24),
+ ],
+ ),
+ ),
+ ),
+ // Bottom sheet content (scrollable, styled like a sheet)
+ BookingDetailsBottomSheet(cubit: widget.cubit, state: widget.state),
+ ],
+ ),
+ ),
+ );
+ }
+}
diff --git a/comwell_key_app/lib/booking_details/components/booking_details_bottom_sheet.dart b/comwell_key_app/lib/booking_details/components/booking_details_bottom_sheet.dart
index bd33cfdd..da00f389 100644
--- a/comwell_key_app/lib/booking_details/components/booking_details_bottom_sheet.dart
+++ b/comwell_key_app/lib/booking_details/components/booking_details_bottom_sheet.dart
@@ -24,11 +24,10 @@ class BookingDetailsBottomSheet extends StatelessWidget {
final theme = Theme.of(context);
final isActive = cubit.user?.isClubMember ?? false;
- return Container(
- decoration: const BoxDecoration(
- color: Colors.white,
- borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
- ),
+ return Material(
+ elevation: 8,
+ color: Colors.white,
+ borderRadius: const BorderRadius.vertical(top: Radius.circular(40)),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,