177 lines
6.0 KiB
Dart
177 lines
6.0 KiB
Dart
import 'package:flutter/material.dart';
|
|
import 'package:get/get.dart';
|
|
|
|
import '../../controller/auth/token_otp_change_controller.dart';
|
|
|
|
class OtpVerificationPage extends StatefulWidget {
|
|
final String phone;
|
|
final String deviceToken;
|
|
final String token;
|
|
final String ptoken;
|
|
|
|
const OtpVerificationPage({
|
|
super.key,
|
|
required this.phone,
|
|
required this.deviceToken,
|
|
required this.token,
|
|
required this.ptoken,
|
|
});
|
|
|
|
@override
|
|
State<OtpVerificationPage> createState() => _OtpVerificationPageState();
|
|
}
|
|
|
|
class _OtpVerificationPageState extends State<OtpVerificationPage> {
|
|
late final OtpVerificationController controller;
|
|
final List<FocusNode> _focusNodes = List.generate(6, (index) => FocusNode());
|
|
final List<TextEditingController> _textControllers =
|
|
List.generate(5, (index) => TextEditingController());
|
|
|
|
@override
|
|
void initState() {
|
|
super.initState();
|
|
controller = Get.put(OtpVerificationController(
|
|
phone: widget.phone,
|
|
deviceToken: widget.deviceToken,
|
|
token: widget.token,
|
|
));
|
|
}
|
|
|
|
@override
|
|
void dispose() {
|
|
for (var node in _focusNodes) {
|
|
node.dispose();
|
|
}
|
|
for (var controller in _textControllers) {
|
|
controller.dispose();
|
|
}
|
|
super.dispose();
|
|
}
|
|
|
|
void _onOtpChanged(String value, int index) {
|
|
if (value.isNotEmpty) {
|
|
if (index < 5) {
|
|
_focusNodes[index + 1].requestFocus();
|
|
} else {
|
|
_focusNodes[index].unfocus(); // إلغاء التركيز بعد آخر حقل
|
|
}
|
|
} else if (index > 0) {
|
|
_focusNodes[index - 1].requestFocus();
|
|
}
|
|
// تجميع نصوص كل الحقول لتكوين الرمز النهائي
|
|
controller.otpCode.value = _textControllers.map((c) => c.text).join();
|
|
}
|
|
|
|
Widget _buildOtpInputFields() {
|
|
return Directionality(
|
|
textDirection: TextDirection.ltr, // لضمان ترتيب الحقول من اليسار لليمين
|
|
child: Row(
|
|
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
|
|
children: List.generate(5, (index) {
|
|
return SizedBox(
|
|
width: 45,
|
|
height: 55,
|
|
child: TextFormField(
|
|
controller: _textControllers[index],
|
|
focusNode: _focusNodes[index],
|
|
textAlign: TextAlign.center,
|
|
keyboardType: TextInputType.number,
|
|
maxLength: 1,
|
|
style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold),
|
|
decoration: InputDecoration(
|
|
counterText: "",
|
|
border: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
),
|
|
enabledBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
borderSide: BorderSide(color: Colors.grey.shade300),
|
|
),
|
|
focusedBorder: OutlineInputBorder(
|
|
borderRadius: BorderRadius.circular(12),
|
|
borderSide: BorderSide(
|
|
color: Theme.of(context).primaryColor, width: 2),
|
|
),
|
|
),
|
|
onChanged: (value) => _onOtpChanged(value, index),
|
|
),
|
|
);
|
|
}),
|
|
),
|
|
);
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Scaffold(
|
|
appBar: AppBar(
|
|
title: Text('Verify OTP'.tr),
|
|
backgroundColor: Colors.transparent,
|
|
elevation: 0,
|
|
centerTitle: true,
|
|
),
|
|
backgroundColor: Colors.grey[50],
|
|
body: SingleChildScrollView(
|
|
child: Padding(
|
|
padding: const EdgeInsets.all(24.0),
|
|
child: Column(
|
|
crossAxisAlignment: CrossAxisAlignment.center,
|
|
children: [
|
|
const SizedBox(height: 20),
|
|
Icon(Icons.phonelink_lock_rounded,
|
|
size: 80, color: Theme.of(context).primaryColor),
|
|
const SizedBox(height: 24),
|
|
Text(
|
|
'Verification Code'.tr,
|
|
style:
|
|
const TextStyle(fontSize: 24, fontWeight: FontWeight.bold),
|
|
),
|
|
const SizedBox(height: 12),
|
|
Padding(
|
|
padding: const EdgeInsets.symmetric(horizontal: 20.0),
|
|
child: Text(
|
|
'${'We have sent a verification code to your mobile number:'.tr} ${widget.phone}',
|
|
textAlign: TextAlign.center,
|
|
style: TextStyle(
|
|
color: Colors.grey.shade600, fontSize: 16, height: 1.5),
|
|
),
|
|
),
|
|
const SizedBox(height: 40),
|
|
_buildOtpInputFields(),
|
|
const SizedBox(height: 40),
|
|
Obx(() => SizedBox(
|
|
width: double.infinity,
|
|
height: 50,
|
|
child: controller.isVerifying.value
|
|
? const Center(child: CircularProgressIndicator())
|
|
: ElevatedButton(
|
|
style: ElevatedButton.styleFrom(
|
|
shape: RoundedRectangleBorder(
|
|
borderRadius: BorderRadius.circular(12))),
|
|
onPressed: () =>
|
|
controller.verifyOtp(widget.ptoken),
|
|
child: Text('Verify'.tr,
|
|
style: const TextStyle(
|
|
fontSize: 18, fontWeight: FontWeight.w600)),
|
|
),
|
|
)),
|
|
const SizedBox(height: 24),
|
|
Obx(
|
|
() => controller.canResend.value
|
|
? TextButton(
|
|
onPressed: controller.sendOtp,
|
|
child: Text('Resend Code'.tr),
|
|
)
|
|
: Text(
|
|
'${'You can resend in'.tr} ${controller.countdown.value} ${'seconds'.tr}',
|
|
style: const TextStyle(color: Colors.grey),
|
|
),
|
|
)
|
|
],
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|