import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:sefer_admin1/constant/links.dart'; import 'package:sefer_admin1/controller/functions/crud.dart'; import 'package:sefer_admin1/main.dart'; import '../../../constant/box_name.dart'; // ─── Custom Colors ──────────────────────────────────────────────────────────── class _AppColors { static const bg = Color(0xFF0A0D14); static const surface = Color(0xFF111622); static const card = Color(0xFF161D2E); static const border = Color(0xFF1F2D4A); static const accent = Color(0xFF00E5FF); static const accentDim = Color(0xFF0097A7); static const accentGlow = Color(0x2200E5FF); static const accentDecrypt = Color(0xFF7C4DFF); static const accentDecryptDim = Color(0xFF512DA8); static const accentDecryptGlow = Color(0x227C4DFF); static const textPrimary = Color(0xFFE8F0FE); static const textSec = Color(0xFF7A8BAA); static const success = Color(0xFF00E676); static const error = Color(0xFFFF5252); } class EncryptToolPage extends StatefulWidget { final String adminToken; const EncryptToolPage({Key? key, required this.adminToken}) : super(key: key); @override State createState() => _EncryptToolPageState(); } class _EncryptToolPageState extends State with SingleTickerProviderStateMixin { final TextEditingController _inputController = TextEditingController(); final TextEditingController _outputController = TextEditingController(); String _output = ''; bool _loading = false; String? _error; bool _isInputCopied = false; bool _isOutputCopied = false; late final AnimationController _glowController; late final Animation _glowAnimation; @override void initState() { super.initState(); _glowController = AnimationController( vsync: this, duration: const Duration(seconds: 3), )..repeat(reverse: true); _glowAnimation = Tween(begin: 0.4, end: 1.0).animate( CurvedAnimation(parent: _glowController, curve: Curves.easeInOut), ); } @override void dispose() { _inputController.dispose(); _outputController.dispose(); _glowController.dispose(); super.dispose(); } // ─── Logic (unchanged) ────────────────────────────────────────────────────── Future _callTool(String action) async { FocusScope.of(context).unfocus(); setState(() { _loading = true; _error = null; _output = ''; _outputController.clear(); _isInputCopied = false; _isOutputCopied = false; }); try { final response = await CRUD().post( link: '${AppLink.server}/ggg.php', payload: { 'action': action, 'text': _inputController.text, 'admin_phone': box.read(BoxName.adminPhone) ?? '', }, ); if (response == 'failure') { setState(() => _error = 'حدث خطأ في الاتصال بالخادم. حاول مرة أخرى.'); } else { if (response['status'] == 'success') { setState(() { _output = (response['result'] ?? '').toString(); _outputController.text = _output; }); } else { setState(() => _error = response['message']?.toString() ?? 'حدث خطأ غير معروف.'); } } } catch (e) { setState(() => _error = 'مشكلة في الشبكة: $e'); } finally { setState(() => _loading = false); } } void _showSnackBar(String message, {bool isError = false}) { ScaffoldMessenger.of(context).clearSnackBars(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Row( children: [ Icon(isError ? Icons.error_outline : Icons.check_circle, color: isError ? _AppColors.error : _AppColors.success), const SizedBox(width: 12), Text( message, style: const TextStyle( fontFamily: 'Cairo', fontWeight: FontWeight.bold, color: _AppColors.textPrimary, ), ), ], ), backgroundColor: isError ? const Color(0xFF1A0808) : const Color(0xFF081A0F), behavior: SnackBarBehavior.floating, shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(14), side: BorderSide( color: isError ? _AppColors.error : _AppColors.success, width: 1, ), ), margin: const EdgeInsets.all(16), duration: const Duration(seconds: 2), ), ); } Future _copyText(bool isInput) async { final textToCopy = isInput ? _inputController.text : _outputController.text; if (textToCopy.isEmpty) { _showSnackBar('لا يوجد نص لنسخه!', isError: true); return; } await Clipboard.setData(ClipboardData(text: textToCopy)); if (isInput) { setState(() => _isInputCopied = true); Future.delayed(const Duration(seconds: 2), () { if (mounted) setState(() => _isInputCopied = false); }); } else { setState(() => _isOutputCopied = true); Future.delayed(const Duration(seconds: 2), () { if (mounted) setState(() => _isOutputCopied = false); }); } _showSnackBar('تم النسخ بنجاح!'); } Future _pasteText(bool isInput) async { final clipboardData = await Clipboard.getData(Clipboard.kTextPlain); final textToPaste = clipboardData?.text ?? ''; if (textToPaste.isEmpty) { _showSnackBar('الحافظة فارغة!', isError: true); return; } setState(() { if (isInput) { _inputController.text = textToPaste; } else { _output = textToPaste; _outputController.text = textToPaste; } }); _showSnackBar('تم اللصق بنجاح!'); } // ─── UI Helpers ───────────────────────────────────────────────────────────── Widget _buildActionButtons({ required bool isInput, required bool isCopied, Color accentColor = _AppColors.accent, }) { return Row( mainAxisSize: MainAxisSize.min, children: [ _MiniIconButton( label: 'لصق', icon: Icons.content_paste_rounded, color: accentColor, onTap: () => _pasteText(isInput), ), const SizedBox(width: 6), _MiniIconButton( label: isCopied ? 'تم!' : 'نسخ', icon: isCopied ? Icons.check_circle_rounded : Icons.copy_rounded, color: isCopied ? _AppColors.success : accentColor, onTap: () => _copyText(isInput), ), ], ); } InputDecoration _buildInputDecoration(String hint) => InputDecoration( hintText: hint, hintStyle: const TextStyle(color: _AppColors.textSec, fontSize: 14), filled: true, fillColor: const Color(0xFF0C1120), border: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: BorderSide.none, ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: const BorderSide(color: _AppColors.border, width: 1), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(14), borderSide: const BorderSide(color: _AppColors.accent, width: 1.5), ), contentPadding: const EdgeInsets.all(16), ); // ─── Build ────────────────────────────────────────────────────────────────── @override Widget build(BuildContext context) { return Scaffold( backgroundColor: _AppColors.bg, body: Stack( children: [ // ── Ambient background glow ────────────────────────────────────────── Positioned( top: -120, left: -80, child: AnimatedBuilder( animation: _glowAnimation, builder: (_, __) => Opacity( opacity: _glowAnimation.value * 0.25, child: Container( width: 380, height: 380, decoration: const BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [Color(0xFF00E5FF), Colors.transparent], ), ), ), ), ), ), Positioned( bottom: -100, right: -60, child: AnimatedBuilder( animation: _glowAnimation, builder: (_, __) => Opacity( opacity: (1 - _glowAnimation.value) * 0.2, child: Container( width: 320, height: 320, decoration: const BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [Color(0xFF7C4DFF), Colors.transparent], ), ), ), ), ), ), // ── Content ────────────────────────────────────────────────────────── SafeArea( child: Column( children: [ // ── AppBar ───────────────────────────────────────────────────── Padding( padding: const EdgeInsets.fromLTRB(8, 8, 16, 0), child: Row( children: [ IconButton( icon: const Icon(Icons.arrow_back_ios_new_rounded, color: _AppColors.textSec, size: 20), onPressed: () => Navigator.pop(context), ), const Spacer(), Row( children: [ Container( width: 8, height: 8, decoration: const BoxDecoration( shape: BoxShape.circle, color: _AppColors.accent, boxShadow: [ BoxShadow( color: _AppColors.accentGlow, blurRadius: 8, spreadRadius: 2, ), ], ), ), const SizedBox(width: 10), const Text( 'أداة التشفير', style: TextStyle( fontSize: 18, fontWeight: FontWeight.w700, color: _AppColors.textPrimary, letterSpacing: 0.5, ), ), ], ), const Spacer(), Container( padding: const EdgeInsets.symmetric( horizontal: 12, vertical: 6), decoration: BoxDecoration( color: _AppColors.accentGlow, borderRadius: BorderRadius.circular(20), border: Border.all( color: _AppColors.accent.withOpacity(0.3)), ), child: const Text( 'AES-256', style: TextStyle( color: _AppColors.accent, fontSize: 11, fontWeight: FontWeight.bold, letterSpacing: 1.5, ), ), ), ], ), ), // ── Scrollable body ─────────────────────────────────────────── Expanded( child: SingleChildScrollView( padding: const EdgeInsets.fromLTRB(20, 24, 20, 32), physics: const BouncingScrollPhysics(), child: Center( child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 650), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // ─── Input Card ───────────────────────────────────── _GlassCard( borderColor: _AppColors.accent.withOpacity(0.2), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Header Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: _AppColors.accentGlow, borderRadius: BorderRadius.circular(10), ), child: const Icon( Icons.text_fields_rounded, color: _AppColors.accent, size: 18), ), const SizedBox(width: 12), const Text( 'النص الأصلي', style: TextStyle( color: _AppColors.textPrimary, fontSize: 15, fontWeight: FontWeight.w700, ), ), ], ), _buildActionButtons( isInput: true, isCopied: _isInputCopied, accentColor: _AppColors.accent, ), ], ), const SizedBox(height: 16), // Input field TextField( controller: _inputController, maxLines: 5, minLines: 3, textDirection: TextDirection.ltr, style: const TextStyle( color: _AppColors.textPrimary, fontSize: 15, height: 1.6, fontFamily: 'monospace', ), onTap: () { if (_inputController.text.isNotEmpty) { _inputController.selection = TextSelection( baseOffset: 0, extentOffset: _inputController.text.length, ); } }, decoration: _buildInputDecoration( 'اكتب أو الصق النص هنا...'), ), const SizedBox(height: 24), // Action buttons row Row( children: [ // Encrypt Expanded( child: _ActionButton( label: 'تشفير', icon: Icons.lock_rounded, isLoading: _loading, onPressed: _loading ? null : () => _callTool('encrypt'), gradient: const LinearGradient( colors: [ Color(0xFF00B4D8), Color(0xFF00E5FF) ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), glowColor: _AppColors.accentGlow, borderColor: _AppColors.accent, ), ), const SizedBox(width: 14), // Decrypt Expanded( child: _ActionButton( label: 'فك التشفير', icon: Icons.lock_open_rounded, isLoading: _loading, onPressed: _loading ? null : () => _callTool('decrypt'), gradient: const LinearGradient( colors: [ Color(0xFF5B2EA6), Color(0xFF7C4DFF) ], begin: Alignment.topLeft, end: Alignment.bottomRight, ), glowColor: _AppColors.accentDecryptGlow, borderColor: _AppColors.accentDecrypt, ), ), ], ), ], ), ), // ─── Error message ─────────────────────────────────── AnimatedSize( duration: const Duration(milliseconds: 300), child: _error != null ? Container( margin: const EdgeInsets.only(top: 16), padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF1A0808), borderRadius: BorderRadius.circular(14), border: Border.all( color: _AppColors.error .withOpacity(0.4)), ), child: Row( children: [ const Icon( Icons.error_outline_rounded, color: _AppColors.error, size: 20), const SizedBox(width: 12), Expanded( child: Text( _error!, style: const TextStyle( color: _AppColors.error, fontWeight: FontWeight.w600, fontSize: 14, ), ), ), ], ), ) : const SizedBox.shrink(), ), // ─── Output Card ───────────────────────────────────── const SizedBox(height: 20), _GlassCard( borderColor: _AppColors.accentDecrypt.withOpacity(0.25), headerWidget: Container( padding: const EdgeInsets.symmetric( horizontal: 20, vertical: 14), decoration: const BoxDecoration( color: Color(0xFF16102A), borderRadius: BorderRadius.vertical( top: Radius.circular(20)), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: _AppColors.accentDecryptGlow, borderRadius: BorderRadius.circular(10), ), child: const Icon( Icons.shield_rounded, color: _AppColors.accentDecrypt, size: 18), ), const SizedBox(width: 12), const Text( 'النتيجة', style: TextStyle( color: _AppColors.textPrimary, fontSize: 15, fontWeight: FontWeight.w700, ), ), ], ), _buildActionButtons( isInput: false, isCopied: _isOutputCopied, accentColor: _AppColors.accentDecrypt, ), ], ), ), child: Padding( padding: const EdgeInsets.all(20), child: TextField( controller: _outputController, readOnly: true, maxLines: 5, minLines: 3, textDirection: TextDirection.ltr, style: const TextStyle( color: _AppColors.textPrimary, fontSize: 15, height: 1.6, fontFamily: 'monospace', letterSpacing: 0.5, ), decoration: const InputDecoration( hintText: 'ستظهر النتيجة هنا...', hintStyle: TextStyle( color: _AppColors.textSec, fontSize: 14), border: InputBorder.none, isDense: true, contentPadding: EdgeInsets.zero, ), onTap: () { if (_outputController.text.isNotEmpty) { _outputController.selection = TextSelection( baseOffset: 0, extentOffset: _outputController.text.length, ); } }, ), ), ), // ─── Footer hint ───────────────────────────────────── const SizedBox(height: 24), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ const Icon(Icons.info_outline_rounded, color: _AppColors.textSec, size: 13), const SizedBox(width: 6), const Text( 'البيانات مشفرة بالكامل ولا تُخزَّن على الخادم', style: TextStyle( color: _AppColors.textSec, fontSize: 12, ), ), ], ), ], ), ), ), ), ), ], ), ), ], ), ); } } // ─── Reusable Widgets ────────────────────────────────────────────────────────── /// Glass card with optional custom header widget class _GlassCard extends StatelessWidget { final Widget child; final Widget? headerWidget; final Color borderColor; const _GlassCard({ required this.child, this.headerWidget, this.borderColor = _AppColors.border, }); @override Widget build(BuildContext context) { return Container( decoration: BoxDecoration( color: _AppColors.card, borderRadius: BorderRadius.circular(22), border: Border.all(color: borderColor, width: 1.2), boxShadow: [ BoxShadow( color: Colors.black.withOpacity(0.35), blurRadius: 24, offset: const Offset(0, 8), ), ], ), child: ClipRRect( borderRadius: BorderRadius.circular(22), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ if (headerWidget != null) headerWidget!, if (headerWidget == null) Padding( padding: const EdgeInsets.fromLTRB(20, 20, 20, 0), child: child, ) else child, if (headerWidget == null) const SizedBox(height: 20), ], ), ), ); } } /// Gradient action button with glow class _ActionButton extends StatefulWidget { final String label; final IconData icon; final bool isLoading; final VoidCallback? onPressed; final Gradient gradient; final Color glowColor; final Color borderColor; const _ActionButton({ required this.label, required this.icon, required this.isLoading, required this.onPressed, required this.gradient, required this.glowColor, required this.borderColor, }); @override State<_ActionButton> createState() => _ActionButtonState(); } class _ActionButtonState extends State<_ActionButton> with SingleTickerProviderStateMixin { late final AnimationController _ctrl; late final Animation _scale; @override void initState() { super.initState(); _ctrl = AnimationController( vsync: this, duration: const Duration(milliseconds: 120)); _scale = Tween(begin: 1.0, end: 0.95) .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: AnimatedOpacity( opacity: widget.onPressed == null ? 0.4 : 1.0, duration: const Duration(milliseconds: 200), child: Container( padding: const EdgeInsets.symmetric(vertical: 16), decoration: BoxDecoration( gradient: widget.gradient, borderRadius: BorderRadius.circular(14), boxShadow: [ BoxShadow( color: widget.glowColor, blurRadius: 16, spreadRadius: 1, offset: const Offset(0, 4), ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.center, children: widget.isLoading ? [ const SizedBox( width: 20, height: 20, child: CircularProgressIndicator( color: Colors.white, strokeWidth: 2), ), ] : [ Icon(widget.icon, color: Colors.white, size: 18), const SizedBox(width: 8), Text( widget.label, style: const TextStyle( color: Colors.white, fontSize: 15, fontWeight: FontWeight.w700, letterSpacing: 0.3, ), ), ], ), ), ), ), ); } } /// Small inline icon button (copy/paste) class _MiniIconButton extends StatelessWidget { final String label; final IconData icon; final Color color; final VoidCallback onTap; const _MiniIconButton({ required this.label, required this.icon, required this.color, required this.onTap, }); @override Widget build(BuildContext context) { return Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(8), onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6), decoration: BoxDecoration( color: color.withOpacity(0.1), borderRadius: BorderRadius.circular(8), border: Border.all(color: color.withOpacity(0.25)), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Icon(icon, color: color, size: 14), const SizedBox(width: 5), Text( label, style: TextStyle( color: color, fontWeight: FontWeight.bold, fontSize: 12, ), ), ], ), ), ), ); } }