import 'package:flutter/material.dart'; import 'package:get/get.dart'; import 'package:sefer_admin1/env/env.dart'; import '../../controller/auth/login_controller.dart'; import '../../controller/auth/otp_helper.dart'; import '../../controller/functions/crud.dart'; import '../../print.dart'; // ─── Colors (نفس نظام الألوان المستخدم في التطبيق) ────────────────────────── class _C { static const bg = Color(0xFF0A0D14); static const card = Color(0xFF161D2E); static const border = Color(0xFF1F2D4A); static const accent = Color(0xFF00E5FF); static const accentGlow = Color(0x2200E5FF); static const accentDim = Color(0xFF0097A7); static const textPrimary = Color(0xFFE8F0FE); static const textSec = Color(0xFF7A8BAA); static const error = Color(0xFFFF5252); static const inputBg = Color(0xFF0C1120); } class AdminLoginPage extends StatefulWidget { const AdminLoginPage({super.key}); @override State createState() => _AdminLoginPageState(); } class _AdminLoginPageState extends State with SingleTickerProviderStateMixin { final _phoneController = TextEditingController(); final _formKey = GlobalKey(); bool _isLoading = false; late final AnimationController _glowCtrl; late final Animation _glowAnim; // ─── Logic (بدون تغيير) ──────────────────────────────────────────────────── Future _submit() async { final allowedPhones = Env.ALLOWED_ADMIN_PHONES; Log.print('allowedPhones: ${allowedPhones}'); allowedPhones.toString().split(','); final phone = _phoneController.text.trim(); if (!allowedPhones.contains(phone)) { Get.snackbar('رفض الدخول', 'رقم الهاتف غير مخوّل بالدخول إلى الإدارة'); return; } setState(() => _isLoading = true); final otpSent = await OtpHelper.sendOtp(phone); if (otpSent) { Get.to(() => OtpVerificationAdmin(phone: phone)); } setState(() => _isLoading = false); } @override void initState() { super.initState(); _initializeToken(); _glowCtrl = AnimationController( vsync: this, duration: const Duration(seconds: 4), )..repeat(reverse: true); _glowAnim = Tween(begin: 0.3, end: 1.0).animate( CurvedAnimation(parent: _glowCtrl, curve: Curves.easeInOut), ); } void _initializeToken() async { await CRUD().getJWT(); } @override void dispose() { _phoneController.dispose(); _glowCtrl.dispose(); super.dispose(); } // ─── Build ───────────────────────────────────────────────────────────────── @override Widget build(BuildContext context) { Get.put(OtpHelper()); return Scaffold( backgroundColor: _C.bg, body: Stack( children: [ // ── Ambient glow top-right ────────────────────────────────────────── Positioned( top: -150, right: -100, child: AnimatedBuilder( animation: _glowAnim, builder: (_, __) => Opacity( opacity: _glowAnim.value * 0.18, child: Container( width: 400, height: 400, decoration: const BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [Color(0xFF00E5FF), Colors.transparent], ), ), ), ), ), ), // ── Ambient glow bottom-left ──────────────────────────────────────── Positioned( bottom: -120, left: -80, child: AnimatedBuilder( animation: _glowAnim, builder: (_, __) => Opacity( opacity: (1 - _glowAnim.value) * 0.15, child: Container( width: 340, height: 340, decoration: const BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [Color(0xFF7C4DFF), Colors.transparent], ), ), ), ), ), ), // ── Main content ─────────────────────────────────────────────────── SafeArea( child: Center( child: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 28), physics: const BouncingScrollPhysics(), child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 440), child: Form( key: _formKey, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const SizedBox(height: 24), // ── Logo / Icon ───────────────────────────────────── _buildLogo(), const SizedBox(height: 32), // ── Title ─────────────────────────────────────────── const Text( 'لوحة الإدارة', style: TextStyle( color: _C.textPrimary, fontSize: 26, fontWeight: FontWeight.w800, letterSpacing: 0.5, ), ), const SizedBox(height: 8), const Text( 'أدخل رقم هاتفك للمتابعة', style: TextStyle( color: _C.textSec, fontSize: 14, ), ), const SizedBox(height: 40), // ── Card ──────────────────────────────────────────── Container( padding: const EdgeInsets.all(28), decoration: BoxDecoration( color: _C.card, borderRadius: BorderRadius.circular(24), border: Border.all( color: _C.accent.withOpacity(0.18), width: 1.2), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.4), blurRadius: 32, offset: const Offset(0, 12), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // ── Field label ───────────────────────────── const Row( children: [ Icon(Icons.phone_android_rounded, color: _C.accent, size: 16), SizedBox(width: 8), Text( 'رقم الهاتف', style: TextStyle( color: _C.textSec, fontSize: 13, fontWeight: FontWeight.w600, letterSpacing: 0.3, ), ), ], ), const SizedBox(height: 10), // ── Phone field ───────────────────────────── TextFormField( controller: _phoneController, keyboardType: TextInputType.phone, textDirection: TextDirection.ltr, style: const TextStyle( color: _C.textPrimary, fontSize: 16, fontFamily: 'monospace', letterSpacing: 1.2, ), decoration: InputDecoration( hintText: '+963 XXX XXX XXX', hintStyle: const TextStyle( color: _C.textSec, fontSize: 14, letterSpacing: 0.5), filled: true, fillColor: _C.inputBg, prefixIcon: const Icon(Icons.dialpad_rounded, color: _C.accentDim, size: 20), border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: const BorderSide( color: _C.border, width: 1), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: const BorderSide( color: _C.accent, width: 1.5), ), errorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: const BorderSide( color: _C.error, width: 1), ), focusedErrorBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: const BorderSide( color: _C.error, width: 1.5), ), contentPadding: const EdgeInsets.symmetric( horizontal: 16, vertical: 16), errorStyle: const TextStyle( color: _C.error, fontSize: 12), ), validator: (value) { if (value == null || value.isEmpty) { return 'الرجاء إدخال رقم الهاتف'; } return null; }, ), const SizedBox(height: 28), // ── Submit button ──────────────────────────── _isLoading ? const Center( child: SizedBox( width: 32, height: 32, child: CircularProgressIndicator( color: _C.accent, strokeWidth: 2.5, ), ), ) : _SubmitButton(onPressed: () { if (_formKey.currentState!.validate()) { _submit(); } }), ], ), ), const SizedBox(height: 32), // ── Footer ────────────────────────────────────────── Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 6, height: 6, decoration: BoxDecoration( shape: BoxShape.circle, color: _C.accent, boxShadow: [ BoxShadow( color: _C.accentGlow, blurRadius: 6, spreadRadius: 1, ), ], ), ), const SizedBox(width: 8), const Text( 'وصول مقيّد للمشرفين فقط', style: TextStyle( color: _C.textSec, fontSize: 12, ), ), ], ), const SizedBox(height: 24), ], ), ), ), ), ), ), ], ), ); } // ─── Logo Widget ───────────────────────────────────────────────────────── Widget _buildLogo() { return AnimatedBuilder( animation: _glowAnim, builder: (_, child) => Container( width: 90, height: 90, decoration: BoxDecoration( shape: BoxShape.circle, color: _C.card, border: Border.all( color: _C.accent.withOpacity(0.3 + _glowAnim.value * 0.3), width: 1.5, ), boxShadow: [ BoxShadow( color: _C.accentGlow.withOpacity(_glowAnim.value * 0.6), blurRadius: 30, spreadRadius: 4, ), ], ), child: child, ), child: const Icon( Icons.admin_panel_settings_rounded, color: _C.accent, size: 42, ), ); } } // ─── Submit Button ───────────────────────────────────────────────────────────── class _SubmitButton extends StatefulWidget { final VoidCallback onPressed; const _SubmitButton({required this.onPressed}); @override State<_SubmitButton> createState() => _SubmitButtonState(); } class _SubmitButtonState extends State<_SubmitButton> with SingleTickerProviderStateMixin { late final AnimationController _ctrl; late final Animation _scale; @override void initState() { super.initState(); _ctrl = AnimationController( vsync: this, duration: const Duration(milliseconds: 100)); _scale = Tween(begin: 1.0, end: 0.96) .animate(CurvedAnimation(parent: _ctrl, curve: Curves.easeOut)); } @override void dispose() { _ctrl.dispose(); super.dispose(); } @override Widget build(BuildContext context) { return GestureDetector( onTapDown: (_) => _ctrl.forward(), onTapUp: (_) => _ctrl.reverse(), onTapCancel: () => _ctrl.reverse(), onTap: widget.onPressed, child: AnimatedBuilder( animation: _scale, builder: (_, child) => Transform.scale(scale: _scale.value, child: child), child: Container( padding: const EdgeInsets.symmetric(vertical: 17), decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFF00B4D8), Color(0xFF00E5FF)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(14), boxShadow: [ BoxShadow( color: const Color(0x3300E5FF), blurRadius: 20, spreadRadius: 1, offset: const Offset(0, 6), ), ], ), child: const Row( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon(Icons.send_rounded, color: Colors.white, size: 18), SizedBox(width: 10), Text( 'إرسال رمز التحقق', style: TextStyle( color: Colors.white, fontSize: 16, fontWeight: FontWeight.w700, letterSpacing: 0.3, ), ), ], ), ), ), ); } }