Skip to content

Commit c36ea3c

Browse files
committed
Refactor: Introduce AppOtpInput widget and update dependencies
- Added `pinput` dependency to `app_ui/pubspec.yaml`. - Removed `pinput` dependency from `app_core/pubspec.yaml`. - Created `AppOtpInput` widget in `app_ui` to encapsulate OTP input logic. - Replaced direct usage of `Pinput` with `AppOtpInput` in `VerifyOTPScreen`. - Updated various dependency versions in `widgetbook/pubspec.lock`. - Updated Flutter SDK constraint in `widgetbook/pubspec.lock`.
1 parent f8dc4c3 commit c36ea3c

File tree

6 files changed

+126
-91
lines changed

6 files changed

+126
-91
lines changed

apps/app_core/lib/modules/verify_otp/screens/verify_otp_screen.dart

Lines changed: 73 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@ import 'package:app_translations/app_translations.dart';
88
import 'package:app_ui/app_ui.dart';
99
import 'package:auto_route/auto_route.dart';
1010
import 'package:flutter/material.dart';
11-
import 'package:flutter/services.dart';
1211
import 'package:flutter_bloc/flutter_bloc.dart';
13-
import 'package:pinput/pinput.dart';
1412

1513
@RoutePage()
1614
class VerifyOTPScreen extends StatefulWidget implements AutoRouteWrapper {
@@ -42,88 +40,84 @@ class _VerifyOTPScreenState extends State<VerifyOTPScreen> with TickerProviderSt
4240
automaticallyImplyLeading: true,
4341
title: context.t.verify_otp,
4442
),
45-
body: SafeArea(
46-
child: BlocConsumer<VerifyOTPBloc, VerifyOTPState>(
47-
listener: (context, state) {
48-
if (state.verifyOtpStatus == ApiStatus.loaded && state.otp.value == '222222') {
49-
showAppSnackbar(context, 'OTP verified successfully!');
50-
context.replaceRoute(const ChangePasswordRoute());
51-
} else if (state.verifyOtpStatus == ApiStatus.error) {
52-
showAppSnackbar(context, 'Invalid OTP', type: SnackbarType.failed);
53-
}
54-
},
55-
builder: (context, state) {
56-
return ListView(
57-
padding: const EdgeInsets.all(Insets.small12),
58-
children: [
59-
VSpace.large24(),
60-
SlideAndFadeAnimationWrapper(delay: 100, child: Center(child: Assets.images.logo.image(width: 100))),
61-
VSpace.large24(),
62-
SlideAndFadeAnimationWrapper(
63-
delay: 200,
64-
child: Center(child: AppText.xsSemiBold(text: context.t.welcome, fontSize: 16)),
43+
body: BlocConsumer<VerifyOTPBloc, VerifyOTPState>(
44+
listener: (context, state) {
45+
if (state.verifyOtpStatus == ApiStatus.loaded && state.otp.value == '222222') {
46+
showAppSnackbar(context, 'OTP verified successfully!');
47+
context.replaceRoute(const ChangePasswordRoute());
48+
} else if (state.verifyOtpStatus == ApiStatus.error) {
49+
showAppSnackbar(context, 'Invalid OTP', type: SnackbarType.failed);
50+
}
51+
},
52+
builder: (context, state) {
53+
return ListView(
54+
padding: const EdgeInsets.all(Insets.small12),
55+
children: [
56+
VSpace.large24(),
57+
SlideAndFadeAnimationWrapper(delay: 100, child: Center(child: Assets.images.logo.image(width: 100))),
58+
VSpace.large24(),
59+
SlideAndFadeAnimationWrapper(
60+
delay: 200,
61+
child: Center(child: AppText.xsSemiBold(text: context.t.welcome, fontSize: 16)),
62+
),
63+
VSpace.large24(),
64+
AppTextField(initialValue: widget.emailAddress, label: context.t.email, isReadOnly: true),
65+
VSpace.medium16(),
66+
Center(
67+
child: Padding(
68+
padding: const EdgeInsets.all(Insets.small12),
69+
child: AppText.sSemiBold(text: context.t.enter_otp),
6570
),
66-
VSpace.large24(),
67-
AppTextField(initialValue: widget.emailAddress, label: context.t.email, isReadOnly: true),
68-
VSpace.medium16(),
71+
),
72+
VSpace.small12(),
73+
AppOtpInput(
74+
errorText: state.otp.error != null ? context.t.pin_incorrect : null,
75+
onChanged: (value) {
76+
context.read<VerifyOTPBloc>().add(VerifyOTPChanged(value));
77+
},
78+
),
79+
80+
VSpace.xsmall8(),
81+
if (state.isTimerRunning)
6982
Center(
70-
child: Padding(
71-
padding: const EdgeInsets.all(Insets.small12),
72-
child: AppText.sSemiBold(text: context.t.enter_otp),
83+
child: AppTimer(
84+
seconds: 30,
85+
onFinished: () {
86+
context.read<VerifyOTPBloc>().add(const TimerFinishedEvent());
87+
},
7388
),
7489
),
75-
VSpace.small12(),
76-
Pinput(
77-
length: 6,
78-
separatorBuilder: (index) => HSpace.xxsmall4(),
79-
errorText: state.otp.error != null ? context.t.pin_incorrect : null,
80-
onChanged: (value) {
81-
context.read<VerifyOTPBloc>().add(VerifyOTPChanged(value));
82-
},
83-
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
84-
),
85-
VSpace.xsmall8(),
86-
if (state.isTimerRunning)
87-
Center(
88-
child: AppTimer(
89-
seconds: 30,
90-
onFinished: () {
91-
context.read<VerifyOTPBloc>().add(const TimerFinishedEvent());
92-
},
93-
),
90+
VSpace.small12(),
91+
Row(
92+
mainAxisAlignment: MainAxisAlignment.center,
93+
children: [
94+
AppText.xsRegular(color: context.colorScheme.black, text: context.t.did_not_receive_otp),
95+
AppButton(
96+
text: context.t.resend_otp,
97+
buttonType: ButtonType.text,
98+
textColor: context.colorScheme.primary400,
99+
onPressed:
100+
state.isTimerRunning
101+
? null
102+
: () {
103+
FocusScope.of(context).unfocus();
104+
context.read<VerifyOTPBloc>().add(const ResendEmailEvent());
105+
},
94106
),
95-
VSpace.small12(),
96-
Row(
97-
mainAxisAlignment: MainAxisAlignment.center,
98-
children: [
99-
AppText.xsRegular(color: context.colorScheme.black, text: context.t.did_not_receive_otp),
100-
AppButton(
101-
text: context.t.resend_otp,
102-
buttonType: ButtonType.text,
103-
textColor: context.colorScheme.primary400,
104-
onPressed:
105-
state.isTimerRunning
106-
? null
107-
: () {
108-
FocusScope.of(context).unfocus();
109-
context.read<VerifyOTPBloc>().add(const ResendEmailEvent());
110-
},
111-
),
112-
HSpace.xsmall8(),
113-
],
114-
),
115-
VSpace.large24(),
116-
AppButton(
117-
isExpanded: true,
118-
padding: const EdgeInsets.symmetric(horizontal: Insets.large24),
119-
text: context.t.verify_otp,
120-
isLoading: state.verifyOtpStatus == ApiStatus.loading,
121-
onPressed: () => context.read<VerifyOTPBloc>().add(const VerifyButtonPressed()),
122-
),
123-
],
124-
);
125-
},
126-
),
107+
HSpace.xsmall8(),
108+
],
109+
),
110+
VSpace.large24(),
111+
AppButton(
112+
isExpanded: true,
113+
padding: const EdgeInsets.symmetric(horizontal: Insets.large24),
114+
text: context.t.verify_otp,
115+
isLoading: state.verifyOtpStatus == ApiStatus.loading,
116+
onPressed: () => context.read<VerifyOTPBloc>().add(const VerifyButtonPressed()),
117+
),
118+
],
119+
);
120+
},
127121
),
128122
);
129123
}

apps/app_core/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ dependencies:
8989

9090
# Launch URL
9191
url_launcher: ^6.3.1
92-
pinput: ^5.0.1
92+
9393

9494
dependency_overrides:
9595
web: ^1.0.0
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import 'package:app_ui/app_ui.dart';
2+
import 'package:flutter/material.dart';
3+
import 'package:flutter/services.dart';
4+
import 'package:pinput/pinput.dart';
5+
6+
class AppOtpInput extends StatelessWidget {
7+
const AppOtpInput({required this.onChanged, this.length = 6, this.errorText, super.key});
8+
9+
final void Function(String) onChanged;
10+
final int length;
11+
final String? errorText;
12+
13+
@override
14+
Widget build(BuildContext context) {
15+
return Pinput(
16+
length: length,
17+
separatorBuilder: (index) => HSpace.xxsmall4(),
18+
errorText: errorText,
19+
onChanged: onChanged,
20+
inputFormatters: [FilteringTextInputFormatter.digitsOnly],
21+
);
22+
}
23+
}

packages/app_ui/lib/src/widgets/molecules/molecules.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export 'app_circular_progress_indicator.dart';
44
export 'app_dialog.dart';
55
export 'app_dropdown.dart';
66
export 'app_network_image.dart';
7+
export 'app_otp_input.dart';
78
export 'app_profile_image.dart';
89
export 'app_refresh_indicator.dart';
910
export 'app_textfield.dart';

packages/app_ui/pubspec.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies:
1919
timeago: ^3.7.0
2020
url_launcher: ^6.3.1
2121
flutter_svg: ^2.0.17
22+
pinput: ^5.0.1
2223

2324
dev_dependencies:
2425
flutter_test:

packages/widgetbook/pubspec.lock

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,10 @@ packages:
5252
dependency: transitive
5353
description:
5454
name: async
55-
sha256: d2872f9c19731c2e5f10444b14686eb7cc85c76274bd6c16e1816bff9a3bab63
55+
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
5656
url: "https://pub.dev"
5757
source: hosted
58-
version: "2.12.0"
58+
version: "2.13.0"
5959
boolean_selector:
6060
dependency: transitive
6161
description:
@@ -236,10 +236,10 @@ packages:
236236
dependency: transitive
237237
description:
238238
name: fake_async
239-
sha256: "6a95e56b2449df2273fd8c45a662d6947ce1ebb7aafe80e550a3f68297f3cacc"
239+
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
240240
url: "https://pub.dev"
241241
source: hosted
242-
version: "1.3.2"
242+
version: "1.3.3"
243243
ffi:
244244
dependency: transitive
245245
description:
@@ -419,10 +419,10 @@ packages:
419419
dependency: transitive
420420
description:
421421
name: leak_tracker
422-
sha256: c35baad643ba394b40aac41080300150a4f08fd0fd6a10378f8f7c6bc161acec
422+
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
423423
url: "https://pub.dev"
424424
source: hosted
425-
version: "10.0.8"
425+
version: "10.0.9"
426426
leak_tracker_flutter_testing:
427427
dependency: transitive
428428
description:
@@ -583,6 +583,14 @@ packages:
583583
url: "https://pub.dev"
584584
source: hosted
585585
version: "6.1.0"
586+
pinput:
587+
dependency: transitive
588+
description:
589+
name: pinput
590+
sha256: "8a73be426a91fefec90a7f130763ca39772d547e92f19a827cf4aa02e323d35a"
591+
url: "https://pub.dev"
592+
source: hosted
593+
version: "5.0.1"
586594
platform:
587595
dependency: transitive
588596
description:
@@ -659,10 +667,10 @@ packages:
659667
dependency: transitive
660668
description:
661669
name: skeletonizer
662-
sha256: "0dcacc51c144af4edaf37672072156f49e47036becbc394d7c51850c5c1e884b"
670+
sha256: a9ddf63900947f4c0648372b6e9987bc2b028db9db843376db6767224d166c31
663671
url: "https://pub.dev"
664672
source: hosted
665-
version: "1.4.3"
673+
version: "2.0.1"
666674
sky_engine:
667675
dependency: transitive
668676
description: flutter
@@ -812,6 +820,14 @@ packages:
812820
url: "https://pub.dev"
813821
source: hosted
814822
version: "1.4.0"
823+
universal_platform:
824+
dependency: transitive
825+
description:
826+
name: universal_platform
827+
sha256: "64e16458a0ea9b99260ceb5467a214c1f298d647c659af1bff6d3bf82536b1ec"
828+
url: "https://pub.dev"
829+
source: hosted
830+
version: "1.1.0"
815831
url_launcher:
816832
dependency: transitive
817833
description:
@@ -920,10 +936,10 @@ packages:
920936
dependency: transitive
921937
description:
922938
name: vm_service
923-
sha256: "0968250880a6c5fe7edc067ed0a13d4bae1577fe2771dcf3010d52c4a9d3ca14"
939+
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
924940
url: "https://pub.dev"
925941
source: hosted
926-
version: "14.3.1"
942+
version: "15.0.0"
927943
watcher:
928944
dependency: transitive
929945
description:
@@ -1006,4 +1022,4 @@ packages:
10061022
version: "3.1.3"
10071023
sdks:
10081024
dart: ">=3.7.0 <4.0.0"
1009-
flutter: ">=3.29.0"
1025+
flutter: ">=3.31.0-0.0.pre"

0 commit comments

Comments
 (0)