Skip to content

Commit ed39e56

Browse files
committed
refactor(authentication): convert AccountLinkingPage to full-screen view
- Remove modal bottom sheet presentation - Replace with full-screen scaffold - Add AppBar for navigation - Simplify layout structure - Remove unnecessary gestures and animations
1 parent ceaae82 commit ed39e56

File tree

1 file changed

+69
-174
lines changed

1 file changed

+69
-174
lines changed

lib/authentication/view/account_linking_page.dart

Lines changed: 69 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,6 @@ import 'package:ui_kit/ui_kit.dart';
99
/// {@template account_linking_page}
1010
/// Displays options for an anonymous user to link their account to an email.
1111
///
12-
/// This page is presented as a modal bottom sheet, allowing the previous
13-
/// page to remain visible underneath and providing a dismissible experience.
1412
/// {@endtemplate}
1513
class AccountLinkingPage extends StatelessWidget {
1614
/// {@macro account_linking_page}
@@ -22,188 +20,85 @@ class AccountLinkingPage extends StatelessWidget {
2220
final textTheme = Theme.of(context).textTheme;
2321
final colorScheme = Theme.of(context).colorScheme;
2422

25-
// GestureDetector allows dismissing the modal by tapping the scrim.
26-
return GestureDetector(
27-
onTap: () => context.pop(),
28-
child: Scaffold(
29-
// A transparent background is crucial for the modal effect.
30-
backgroundColor: Colors.transparent,
31-
// The DraggableScrollableSheet provides the bottom sheet behavior.
32-
body: DraggableScrollableSheet(
33-
// The initial height of the bottom sheet (approx 2/3 of the screen).
34-
initialChildSize: 0.66,
35-
// The minimum height the sheet can be dragged down to before dismissing.
36-
minChildSize: 0.4,
37-
// The maximum height the sheet can be dragged up to.
38-
maxChildSize: 0.9,
39-
expand: false, // Do not expand to full screen by default
40-
builder: (BuildContext context, ScrollController scrollController) {
41-
// A second GestureDetector prevents the inner content taps from
42-
// bubbling up and closing the modal.
43-
return GestureDetector(
44-
onTap: () {}, // Absorb taps within the sheet
45-
child: Container(
46-
// Apply styling for the bottom sheet container.
47-
decoration: BoxDecoration(
48-
color: colorScheme.surface,
49-
borderRadius:
50-
const BorderRadius.vertical(top: Radius.circular(16)),
23+
return Scaffold(
24+
appBar: AppBar(title: Text(l10n.accountLinkingHeadline)),
25+
body: BlocConsumer<AuthenticationBloc, AuthenticationState>(
26+
listener: (context, state) {
27+
if (state.status == AuthenticationStatus.failure) {
28+
ScaffoldMessenger.of(context)
29+
..hideCurrentSnackBar()
30+
..showSnackBar(
31+
SnackBar(
32+
content: Text(state.exception!.toFriendlyMessage(context)),
33+
backgroundColor: colorScheme.error,
5134
),
52-
child: Stack(
53-
children: [
54-
Column(
55-
children: [
56-
// --- Drag Handle ---
57-
Padding(
58-
padding:
59-
const EdgeInsets.symmetric(vertical: AppSpacing.md),
60-
child: Center(
61-
child: Container(
62-
height: 4,
63-
width: 40,
64-
decoration: BoxDecoration(
65-
color: colorScheme.onSurface.withOpacity(0.4),
66-
borderRadius: BorderRadius.circular(8),
67-
),
68-
),
69-
),
70-
),
71-
// --- Main Content ---
72-
Expanded(
73-
child: BlocConsumer<AuthenticationBloc,
74-
AuthenticationState>(
75-
listener: (context, state) {
76-
if (state.status ==
77-
AuthenticationStatus.failure) {
78-
ScaffoldMessenger.of(context)
79-
..hideCurrentSnackBar()
80-
..showSnackBar(
81-
SnackBar(
82-
content: Text(
83-
state.exception!
84-
.toFriendlyMessage(context),
85-
),
86-
backgroundColor: colorScheme.error,
87-
),
88-
);
89-
}
90-
},
91-
builder: (context, state) {
92-
final isLoading =
93-
state.status == AuthenticationStatus.loading;
94-
95-
return Padding(
96-
padding: const EdgeInsets.all(
97-
AppSpacing.paddingLarge,
98-
),
99-
child: Center(
100-
child: SingleChildScrollView(
101-
// Link the scroll controller to enable dragging the sheet.
102-
controller: scrollController,
103-
child: Column(
104-
mainAxisAlignment:
105-
MainAxisAlignment.center,
106-
crossAxisAlignment:
107-
CrossAxisAlignment.stretch,
108-
children: [
109-
// --- Icon ---
110-
Padding(
111-
padding: const EdgeInsets.only(
112-
bottom: AppSpacing.xl,
113-
),
114-
child: Icon(
115-
Icons.sync,
116-
size: AppSpacing.xxl * 2,
117-
color: colorScheme.primary,
118-
),
119-
),
120-
// --- Headline and Subheadline ---
121-
Text(
122-
l10n.accountLinkingHeadline,
123-
style: textTheme.headlineMedium
124-
?.copyWith(
125-
fontWeight: FontWeight.bold,
126-
),
127-
textAlign: TextAlign.center,
128-
),
129-
const SizedBox(height: AppSpacing.md),
130-
Text(
131-
l10n.accountLinkingBody,
132-
style: textTheme.bodyLarge?.copyWith(
133-
color:
134-
colorScheme.onSurfaceVariant,
135-
),
136-
textAlign: TextAlign.center,
137-
),
138-
const SizedBox(height: AppSpacing.xxl),
35+
);
36+
}
37+
},
38+
builder: (context, state) {
39+
final isLoading = state.status == AuthenticationStatus.loading;
13940

140-
// --- Email Linking Button ---
141-
ElevatedButton.icon(
142-
icon:
143-
const Icon(Icons.email_outlined),
144-
onPressed: isLoading
145-
? null
146-
: () {
147-
// Navigate to the request code page for linking.
148-
context.goNamed(
149-
Routes
150-
.accountLinkingRequestCodeName,
151-
);
152-
},
153-
label: Text(
154-
l10n.accountLinkingSendLinkButton,
155-
),
156-
style: ElevatedButton.styleFrom(
157-
padding:
158-
const EdgeInsets.symmetric(
159-
vertical: AppSpacing.md,
160-
),
161-
textStyle: textTheme.labelLarge,
162-
),
163-
),
164-
165-
// --- Loading Indicator ---
166-
if (isLoading) ...[
167-
const Padding(
168-
padding: EdgeInsets.only(
169-
top: AppSpacing.xl,
170-
),
171-
child: Center(
172-
child:
173-
CircularProgressIndicator(),
174-
),
175-
),
176-
],
177-
],
178-
),
179-
),
180-
),
41+
return Padding(
42+
padding: const EdgeInsets.all(AppSpacing.paddingLarge),
43+
child: Center(
44+
child: SingleChildScrollView(
45+
child: Column(
46+
mainAxisAlignment: MainAxisAlignment.center,
47+
crossAxisAlignment: CrossAxisAlignment.stretch,
48+
children: [
49+
Padding(
50+
padding: const EdgeInsets.only(bottom: AppSpacing.xl),
51+
child: Icon(
52+
Icons.sync,
53+
size: AppSpacing.xxl * 2,
54+
color: colorScheme.primary,
55+
),
56+
),
57+
Text(
58+
l10n.accountLinkingHeadline,
59+
style: textTheme.headlineMedium?.copyWith(
60+
fontWeight: FontWeight.bold,
61+
),
62+
textAlign: TextAlign.center,
63+
),
64+
const SizedBox(height: AppSpacing.md),
65+
Text(
66+
l10n.accountLinkingBody,
67+
style: textTheme.bodyLarge?.copyWith(
68+
color: colorScheme.onSurfaceVariant,
69+
),
70+
textAlign: TextAlign.center,
71+
),
72+
const SizedBox(height: AppSpacing.xxl),
73+
ElevatedButton.icon(
74+
icon: const Icon(Icons.email_outlined),
75+
onPressed: isLoading
76+
? null
77+
: () {
78+
context.goNamed(
79+
Routes.accountLinkingRequestCodeName,
18180
);
18281
},
183-
),
82+
label: Text(l10n.accountLinkingSendLinkButton),
83+
style: ElevatedButton.styleFrom(
84+
padding: const EdgeInsets.symmetric(
85+
vertical: AppSpacing.md,
18486
),
185-
],
186-
),
187-
// --- Close Button ---
188-
Positioned(
189-
top: AppSpacing.sm,
190-
right: AppSpacing.sm,
191-
child: IconButton(
192-
icon: const Icon(Icons.close),
193-
tooltip: MaterialLocalizations.of(context)
194-
.closeButtonTooltip,
195-
onPressed: () {
196-
// Dismiss the modal bottom sheet.
197-
context.pop();
198-
},
87+
textStyle: textTheme.labelLarge,
19988
),
20089
),
90+
if (isLoading) ...[
91+
const Padding(
92+
padding: EdgeInsets.only(top: AppSpacing.xl),
93+
child: Center(child: CircularProgressIndicator()),
94+
),
95+
],
20196
],
20297
),
20398
),
204-
);
205-
},
206-
),
99+
),
100+
);
101+
},
207102
),
208103
);
209104
}

0 commit comments

Comments
 (0)