Skip to content

Commit 57c3d71

Browse files
committed
fix: paint schedule sheet behind keyboard
1 parent 87d5d3e commit 57c3d71

4 files changed

Lines changed: 138 additions & 61 deletions

File tree

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import 'package:flutter/material.dart';
2+
3+
class KeyboardBackedBottomSheet extends StatelessWidget {
4+
const KeyboardBackedBottomSheet({
5+
super.key,
6+
required this.child,
7+
this.heightFactor = 0.85,
8+
this.backgroundColor = Colors.white,
9+
this.borderRadius = const BorderRadius.vertical(top: Radius.circular(24)),
10+
});
11+
12+
static const keyboardBackplateKey = Key('keyboard_backed_bottom_sheet_plate');
13+
14+
final Widget child;
15+
final double heightFactor;
16+
final Color backgroundColor;
17+
final BorderRadiusGeometry borderRadius;
18+
19+
@override
20+
Widget build(BuildContext context) {
21+
final bottomInset = MediaQuery.viewInsetsOf(context).bottom;
22+
final resolvedBorderRadius = borderRadius.resolve(
23+
Directionality.of(context),
24+
);
25+
final topRadius =
26+
resolvedBorderRadius.topLeft.y > resolvedBorderRadius.topRight.y
27+
? resolvedBorderRadius.topLeft.y
28+
: resolvedBorderRadius.topRight.y;
29+
30+
return Material(
31+
color: Colors.transparent,
32+
child: SafeArea(
33+
child: Stack(
34+
alignment: Alignment.bottomCenter,
35+
children: [
36+
if (bottomInset > 0)
37+
Positioned(
38+
left: 0,
39+
right: 0,
40+
bottom: 0,
41+
height: bottomInset + topRadius,
42+
child: ColoredBox(
43+
key: keyboardBackplateKey,
44+
color: backgroundColor,
45+
),
46+
),
47+
AnimatedPadding(
48+
padding: EdgeInsets.only(bottom: bottomInset),
49+
duration: const Duration(milliseconds: 150),
50+
curve: Curves.easeOut,
51+
child: FractionallySizedBox(
52+
heightFactor: heightFactor,
53+
child: Container(
54+
decoration: BoxDecoration(
55+
color: backgroundColor,
56+
borderRadius: borderRadius,
57+
),
58+
child: child,
59+
),
60+
),
61+
),
62+
],
63+
),
64+
),
65+
);
66+
}
67+
}

lib/presentation/schedule_create/screens/schedule_create_screen.dart

Lines changed: 13 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
33
import 'package:on_time_front/core/di/di_setup.dart';
44
import 'package:on_time_front/presentation/app/bloc/auth/auth_bloc.dart';
55
import 'package:on_time_front/presentation/schedule_create/bloc/schedule_form_bloc.dart';
6+
import 'package:on_time_front/presentation/schedule_create/components/keyboard_backed_bottom_sheet.dart';
67
import 'package:on_time_front/presentation/schedule_create/components/schedule_multi_page_form.dart';
78

89
class ScheduleCreateScreen extends StatelessWidget {
@@ -12,38 +13,19 @@ class ScheduleCreateScreen extends StatelessWidget {
1213

1314
@override
1415
Widget build(BuildContext context) {
15-
final bottomInset = MediaQuery.of(context).viewInsets.bottom;
16-
17-
return Material(
18-
color: Colors.transparent,
19-
child: SafeArea(
20-
child: AnimatedPadding(
21-
padding: EdgeInsets.only(bottom: bottomInset),
22-
duration: const Duration(milliseconds: 150),
23-
curve: Curves.easeOut,
24-
child: FractionallySizedBox(
25-
heightFactor: 0.85,
26-
child: Container(
27-
decoration: const BoxDecoration(
28-
color: Colors.white,
29-
borderRadius: BorderRadius.vertical(top: Radius.circular(24)),
30-
),
31-
child: BlocProvider<ScheduleFormBloc>(
32-
create: (context) => getIt.get<ScheduleFormBloc>(
33-
param1: context.read<AuthBloc>(),
34-
)..add(ScheduleFormCreateRequested(initialDate: initialDate)),
35-
child: BlocBuilder<ScheduleFormBloc, ScheduleFormState>(
36-
builder: (context, state) {
37-
return ScheduleMultiPageForm(
38-
onSaved: () => context.read<ScheduleFormBloc>().add(
39-
const ScheduleFormCreated(),
40-
),
41-
);
42-
},
43-
),
16+
return KeyboardBackedBottomSheet(
17+
child: BlocProvider<ScheduleFormBloc>(
18+
create: (context) =>
19+
getIt.get<ScheduleFormBloc>(param1: context.read<AuthBloc>())
20+
..add(ScheduleFormCreateRequested(initialDate: initialDate)),
21+
child: BlocBuilder<ScheduleFormBloc, ScheduleFormState>(
22+
builder: (context, state) {
23+
return ScheduleMultiPageForm(
24+
onSaved: () => context.read<ScheduleFormBloc>().add(
25+
const ScheduleFormCreated(),
4426
),
45-
),
46-
),
27+
);
28+
},
4729
),
4830
),
4931
);

lib/presentation/schedule_create/screens/schedule_edit_screen.dart

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
33
import 'package:on_time_front/core/di/di_setup.dart';
44
import 'package:on_time_front/presentation/app/bloc/auth/auth_bloc.dart';
55
import 'package:on_time_front/presentation/schedule_create/bloc/schedule_form_bloc.dart';
6+
import 'package:on_time_front/presentation/schedule_create/components/keyboard_backed_bottom_sheet.dart';
67
import 'package:on_time_front/presentation/schedule_create/components/schedule_multi_page_form.dart';
78

89
class ScheduleEditScreen extends StatelessWidget {
@@ -12,37 +13,19 @@ class ScheduleEditScreen extends StatelessWidget {
1213

1314
@override
1415
Widget build(BuildContext context) {
15-
final bottomInset = MediaQuery.of(context).viewInsets.bottom;
16-
return Material(
17-
color: Colors.transparent,
18-
child: SafeArea(
19-
child: AnimatedPadding(
20-
padding: EdgeInsets.only(bottom: bottomInset),
21-
duration: const Duration(milliseconds: 150),
22-
curve: Curves.easeOut,
23-
child: FractionallySizedBox(
24-
heightFactor: 0.85,
25-
child: Container(
26-
decoration: BoxDecoration(
27-
color: Colors.white,
28-
borderRadius:
29-
const BorderRadius.vertical(top: Radius.circular(24)),
16+
return KeyboardBackedBottomSheet(
17+
child: BlocProvider<ScheduleFormBloc>(
18+
create: (context) =>
19+
getIt.get<ScheduleFormBloc>(param1: context.read<AuthBloc>())
20+
..add(ScheduleFormEditRequested(scheduleId: scheduleId)),
21+
child: BlocBuilder<ScheduleFormBloc, ScheduleFormState>(
22+
builder: (context, state) {
23+
return ScheduleMultiPageForm(
24+
onSaved: () => context.read<ScheduleFormBloc>().add(
25+
const ScheduleFormUpdated(),
3026
),
31-
child: BlocProvider<ScheduleFormBloc>(
32-
create: (context) => getIt.get<ScheduleFormBloc>(
33-
param1: context.read<AuthBloc>(),
34-
)..add(ScheduleFormEditRequested(scheduleId: scheduleId)),
35-
child: BlocBuilder<ScheduleFormBloc, ScheduleFormState>(
36-
builder: (context, state) {
37-
return ScheduleMultiPageForm(
38-
onSaved: () => context.read<ScheduleFormBloc>().add(
39-
const ScheduleFormUpdated(),
40-
));
41-
},
42-
),
43-
),
44-
),
45-
),
27+
);
28+
},
4629
),
4730
),
4831
);
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_test/flutter_test.dart';
3+
import 'package:on_time_front/presentation/schedule_create/components/keyboard_backed_bottom_sheet.dart';
4+
5+
void main() {
6+
testWidgets('paints a white backplate behind the iOS keyboard inset', (
7+
tester,
8+
) async {
9+
tester.view.devicePixelRatio = 1;
10+
tester.view.physicalSize = const Size(390, 844);
11+
tester.view.viewInsets = FakeViewPadding(bottom: 320);
12+
addTearDown(tester.view.resetDevicePixelRatio);
13+
addTearDown(tester.view.resetPhysicalSize);
14+
addTearDown(tester.view.resetViewInsets);
15+
16+
await tester.pumpWidget(
17+
const MaterialApp(
18+
home: KeyboardBackedBottomSheet(child: SizedBox.expand()),
19+
),
20+
);
21+
22+
final backplate = find.byKey(
23+
KeyboardBackedBottomSheet.keyboardBackplateKey,
24+
);
25+
26+
expect(backplate, findsOneWidget);
27+
expect(tester.widget<ColoredBox>(backplate).color, Colors.white);
28+
expect(tester.getSize(backplate).height, 344);
29+
});
30+
31+
testWidgets('does not add keyboard backplate while keyboard is hidden', (
32+
tester,
33+
) async {
34+
await tester.pumpWidget(
35+
const MaterialApp(
36+
home: KeyboardBackedBottomSheet(child: SizedBox.expand()),
37+
),
38+
);
39+
40+
expect(
41+
find.byKey(KeyboardBackedBottomSheet.keyboardBackplateKey),
42+
findsNothing,
43+
);
44+
});
45+
}

0 commit comments

Comments
 (0)