Skip to content

Commit 6c34bd0

Browse files
committed
feat(authentication): replace TextFormField with Pinput for OTP verification
- Remove TextFormField and related padding - Add Pinput widget for 6-digit OTP verification - Implement default and focused pin themes - Add length validation and error handling - Improve accessibility with onCompleted event
1 parent 18bb5bf commit 6c34bd0

File tree

1 file changed

+38
-27
lines changed

1 file changed

+38
-27
lines changed

lib/authentication/view/email_code_verification_page.dart

Lines changed: 38 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import 'package:flutter/material.dart';
2-
import 'package:flutter/services.dart';
32
import 'package:flutter_bloc/flutter_bloc.dart';
43
import 'package:flutter_news_app_mobile_client_full_source_code/app/bloc/app_bloc.dart';
54
import 'package:flutter_news_app_mobile_client_full_source_code/app/config/config.dart';
65
import 'package:flutter_news_app_mobile_client_full_source_code/authentication/bloc/authentication_bloc.dart';
76
import 'package:flutter_news_app_mobile_client_full_source_code/l10n/l10n.dart';
7+
import 'package:pinput/pinput.dart';
88
import 'package:ui_kit/ui_kit.dart';
99

1010
/// {@template email_code_verification_page}
@@ -130,10 +130,12 @@ class _EmailCodeVerificationFormState
130130
extends State<_EmailCodeVerificationForm> {
131131
final _formKey = GlobalKey<FormState>();
132132
final _codeController = TextEditingController();
133+
final _focusNode = FocusNode();
133134

134135
@override
135136
void dispose() {
136137
_codeController.dispose();
138+
_focusNode.dispose();
137139
super.dispose();
138140
}
139141

@@ -152,39 +154,48 @@ class _EmailCodeVerificationFormState
152154
Widget build(BuildContext context) {
153155
final l10n = AppLocalizationsX(context).l10n;
154156
final textTheme = Theme.of(context).textTheme;
157+
final colorScheme = Theme.of(context).colorScheme;
158+
159+
final defaultPinTheme = PinTheme(
160+
width: 56,
161+
height: 60,
162+
textStyle: textTheme.headlineSmall,
163+
decoration: BoxDecoration(
164+
color: colorScheme.surface,
165+
borderRadius: BorderRadius.circular(8),
166+
border: Border.all(color: colorScheme.onSurface.withOpacity(0.12)),
167+
),
168+
);
155169

156170
return Form(
157171
key: _formKey,
158172
child: Column(
159173
mainAxisSize: MainAxisSize.min,
160174
children: [
161-
Padding(
162-
// No horizontal padding needed if column is stretched
163-
// padding: const EdgeInsets.symmetric(horizontal: AppSpacing.md),
164-
padding: EdgeInsets.zero,
165-
child: TextFormField(
166-
controller: _codeController,
167-
decoration: InputDecoration(
168-
labelText: l10n.emailCodeVerificationHint,
169-
// border: const OutlineInputBorder(),
170-
counterText: '',
175+
Pinput(
176+
length: 6,
177+
controller: _codeController,
178+
focusNode: _focusNode,
179+
defaultPinTheme: defaultPinTheme,
180+
onCompleted: (pin) => _submitForm(),
181+
validator: (value) {
182+
if (value == null || value.isEmpty) {
183+
return l10n.emailCodeValidationEmptyError;
184+
}
185+
if (value.length != 6) {
186+
return l10n.emailCodeValidationLengthError;
187+
}
188+
return null;
189+
},
190+
focusedPinTheme: defaultPinTheme.copyWith(
191+
decoration: defaultPinTheme.decoration!.copyWith(
192+
border: Border.all(color: colorScheme.primary),
193+
),
194+
),
195+
errorPinTheme: defaultPinTheme.copyWith(
196+
decoration: defaultPinTheme.decoration!.copyWith(
197+
border: Border.all(color: colorScheme.error),
171198
),
172-
keyboardType: TextInputType.number,
173-
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
174-
maxLength: 6,
175-
textAlign: TextAlign.center,
176-
style: textTheme.headlineSmall,
177-
enabled: !widget.isLoading,
178-
validator: (value) {
179-
if (value == null || value.isEmpty) {
180-
return l10n.emailCodeValidationEmptyError;
181-
}
182-
if (value.length != 6) {
183-
return l10n.emailCodeValidationLengthError;
184-
}
185-
return null;
186-
},
187-
onFieldSubmitted: widget.isLoading ? null : (_) => _submitForm(),
188199
),
189200
),
190201
const SizedBox(height: AppSpacing.xxl),

0 commit comments

Comments
 (0)