Files
intaleq/siro_driver/lib/views/auth/captin/otp_token_page.dart
T
Hamza-AyedandClaude Opus 5 92dc6b3641 chore: استيراد أولي من سيرو (ecfe7568) — بلا أي تعديل
نسخة كاملة من مستودع سيرو عند ecfe7568 لتكون أساس تطبيق «انطلق».
نُسخ المتعقَّب في git فقط (12,509 ملفاً / 302 م.ب) بـ git archive، لا
`cp -r` — فاستُثنيت تلقائياً مخلفات البناء (build · node_modules ·
.dart_tool · .gradle · Pods ≈ 10.7 غ.ب) وكل ما يستثنيه .gitignore.

هذا الكوميت **بلا أي تعديل عمداً** حتى يكون كل ما يليه فرقاً مقروءاً
مقابل سيرو الأصلي. سيرو نفسه لم يُمسّ.

⚠️ لا يبني بعد: `.env` و`lib/env/env.g.dart` غير متعقَّبين في سيرو (وهذا
صحيح — أسرار لكل مستأجر). كل تطبيق فلاتر هنا يحتاج .env خاصاً بانطلق ثم
توليد env.g.dart عبر build_runner. لا تُنسخ أسرار سيرو.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 05:10:29 +03:00

177 lines
6.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../../controller/auth/captin/opt_token_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(3, (index) => FocusNode());
final List<TextEditingController> _textControllers =
List.generate(3, (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 < 2) {
_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(3, (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),
),
)
],
),
),
),
);
}
}