import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter_svg/flutter_svg.dart'; import '../screens/request_leave_screen.dart'; import '../screens/request_advance_scrren.dart'; import '../models/leave_request.dart'; import '../models/advance_request.dart'; import '../services/request_service.dart'; class HolidayScreen extends StatefulWidget { const HolidayScreen({super.key}); @override State createState() => _HolidayScreenState(); } class _HolidayScreenState extends State { int activeTab = 0; // 0 = السلف | 1 = الأجازات final RequestService _requestService = RequestService(); late List _leaveRequests; late List _advanceRequests; /// ⭐ Telegram-style FAB animation final ScrollController _scrollController = ScrollController(); bool _showActions = true; @override void initState() { super.initState(); _initializeData(); // ⭐ Listen to scroll and animate the floating buttons (Telegram style) _scrollController.addListener(() { final direction = _scrollController.position.userScrollDirection; if (direction == ScrollDirection.reverse) { // scrolling DOWN → hide buttons if (_showActions) setState(() => _showActions = false); } else if (direction == ScrollDirection.forward) { // scrolling UP → show buttons if (!_showActions) setState(() => _showActions = true); } // If user reaches top → force visible if (_scrollController.position.pixels <= 10) { if (!_showActions) setState(() => _showActions = true); } }); } void _initializeData() async { _leaveRequests = await _requestService.getLeaveRequests(); _advanceRequests = await _requestService.getAdvanceRequests(); _requestService.leaveRequestsStream.listen((requests) { setState(() { _leaveRequests = requests; }); }); _requestService.advanceRequestsStream.listen((requests) { setState(() { _advanceRequests = requests; }); }); } Widget buildStatusCircle({ required bool active, required String label, required String? svgPath, required Color activeColor, required Color glowColor, }) { return Column( children: [ Container( width: 36, height: 36, decoration: BoxDecoration( shape: BoxShape.circle, color: active ? activeColor : const Color(0xFFD6D6D6), boxShadow: active ? [ BoxShadow( color: glowColor.withOpacity(0.6), blurRadius: 15, spreadRadius: 2, ), ] : [], ), child: active && svgPath != null ? Center( child: SvgPicture.asset( svgPath, width: 18, height: 18, color: const Color(0xFFFFFFFF), ), ) : null, ), const SizedBox(height: 4), Text(label, style: const TextStyle(fontSize: 10)), ], ); } @override Widget build(BuildContext context) { return Directionality( textDirection: TextDirection.rtl, child: Stack( children: [ // -------------------- TABS -------------------- Positioned( top: 0, left: 0, right: 0, bottom: 5, child: Row( mainAxisAlignment: MainAxisAlignment.center, children: [ // الأجازات GestureDetector( onTap: () => setState(() => activeTab = 1), child: Column( children: [ Text( "الأجازات", style: TextStyle( fontSize: 22, fontWeight: FontWeight.w600, color: activeTab == 1 ? const Color(0xFF8EFDC2) : const Color(0x9EFFFFFF), ), ), if (activeTab == 1) Container( width: 60, height: 2, margin: const EdgeInsets.only(top: 4), color: const Color(0xFF8EFDC2), ), ], ), ), const SizedBox(width: 70), // السلف GestureDetector( onTap: () => setState(() => activeTab = 0), child: Column( children: [ Text( "السلف", style: TextStyle( fontSize: 22, fontWeight: FontWeight.w600, color: activeTab == 0 ? const Color(0xFF8EFDC2) : const Color(0x9EFFFFFF), ), ), if (activeTab == 0) Container( width: 60, height: 2, margin: const EdgeInsets.only(top: 4), color: const Color(0xFF8EFDC2), ), ], ), ), ], ), ), // ------------- CONTENT AREA (LISTS) ------------- Positioned( top: 30, left: 0, right: 0, bottom: 0, child: activeTab == 1 ? _buildLeaveRequestsTab() : _buildAdvanceRequestsTab(), ), // ------------------------------------------------------------- // ⭐ TELEGRAM STYLE FLOATING ACTION BUTTONS (SLIDE + FADE) // ------------------------------------------------------------- Positioned( bottom: 30, right: 20, child: AnimatedSlide( offset: _showActions ? const Offset(0, 0) : const Offset(0, 1.4), duration: const Duration(milliseconds: 350), curve: Curves.easeOut, child: AnimatedOpacity( duration: const Duration(milliseconds: 250), opacity: _showActions ? 1 : 0, child: Column( children: [ _HolidayActionButton( label: "طلب سلفة", svgPath: "assets/images/money2.svg", iconWidth: 28, iconHeight: 20, onTap: () async { await Navigator.push( context, MaterialPageRoute( builder: (context) => const RequestAdvanceScreen(), ), ); }, ), const SizedBox(height: 18), _HolidayActionButton( label: "طلب إجازة", svgPath: "assets/images/plus.svg", iconWidth: 28, iconHeight: 20, onTap: () async { await Navigator.push( context, MaterialPageRoute( builder: (context) => const RequestLeaveScreen(), ), ); }, ), ], ), ), ), ), ], ), ); } // -------------------- LIST BUILDERS -------------------- Widget _buildLeaveRequestsTab() { if (_leaveRequests.isEmpty) { return const Center( child: Text( 'لا توجد طلبات أجازة', style: TextStyle(color: Colors.white, fontSize: 18), ), ); } return ListView.builder( controller: _scrollController, padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20), itemCount: _leaveRequests.length, itemBuilder: (context, index) { return _buildLeaveRequestCard(_leaveRequests[index]); }, ); } Widget _buildAdvanceRequestsTab() { if (_advanceRequests.isEmpty) { return const Center( child: Text( 'لا توجد طلبات سلف', style: TextStyle(color: Colors.white, fontSize: 18), ), ); } return ListView.builder( controller: _scrollController, padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20), itemCount: _advanceRequests.length, itemBuilder: (context, index) { return _buildAdvanceRequestCard(_advanceRequests[index]); }, ); } // -------------------- LEAVE REQUEST CARD -------------------- Widget _buildLeaveRequestCard(LeaveRequest request) { const bgColor = Color(0xFFEAF8F3); const lineColor = Color(0xFF22A685); final bool isWaiting = request.status == "waiting"; final bool isApproved = request.status == "approved"; final bool isDenied = request.status == "denied"; final String dateText = "${request.fromDate.year}.${request.fromDate.month}.${request.fromDate.day}"; return Directionality( textDirection: TextDirection.rtl, child: Container( width: MediaQuery.of(context).size.width * 0.8, margin: const EdgeInsets.only(bottom: 16), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), decoration: BoxDecoration( color: bgColor, borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ // Status circles Row( mainAxisAlignment: MainAxisAlignment.center, children: [ buildStatusCircle( active: isWaiting, label: "قيد الانتظار", svgPath: isWaiting ? "assets/images/waiting.svg" : null, activeColor: const Color(0xFFF9C8A01B), glowColor: const Color(0xB4FFDC69), ), const SizedBox(width: 12), buildStatusCircle( active: isApproved, label: "موافقة", svgPath: isApproved ? "assets/images/yes.svg" : null, activeColor: const Color(0xFF0A8A60), glowColor: const Color(0xFF00D7A3), ), const SizedBox(width: 12), buildStatusCircle( active: isDenied, label: "تم الرفض", svgPath: isDenied ? "assets/images/no.svg" : null, activeColor: const Color(0xFFE63946), glowColor: const Color(0xFFE63946), ), ], ), const SizedBox(height: 8), // Title + date row Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // icon + leave type Row( children: [ SizedBox( width: 32, height: 32, child: Center( child: SvgPicture.asset( "assets/images/holiday.svg", width: 32, height: 32, color: const Color(0xFF11663C), ), ), ), const SizedBox(width: 8), Text( request.leaveType, style: const TextStyle( fontSize: 12, color: Colors.black87, fontWeight: FontWeight.bold, ), ), ], ), // date Text( dateText, style: const TextStyle( fontSize: 14, color: Colors.black87, fontWeight: FontWeight.w500, ), ), ], ), const SizedBox(height: 10), // divider Container(width: double.infinity, height: 1.4, color: lineColor), const SizedBox(height: 10), // Reason row Padding( padding: const EdgeInsets.only(top: 8), child: Row( textDirection: TextDirection.ltr, children: [ Expanded( child: Text( request.reason, textAlign: TextAlign.right, style: const TextStyle( fontSize: 13, color: Colors.black87, ), ), ), const SizedBox(width: 6), const Text( "السبب :", textAlign: TextAlign.right, style: TextStyle( fontSize: 14, color: Colors.black87, fontWeight: FontWeight.bold, ), ), ], ), ), ], ), ), ); } // -------------------- ADVANCE REQUEST CARD -------------------- Widget _buildAdvanceRequestCard(AdvanceRequest request) { const bgColor = Color(0xFFEAF8F3); const lineColor = Color(0xFF22A685); final bool isWaiting = request.status == "waiting"; final bool isApproved = request.status == "approved"; final bool isDenied = request.status == "denied"; final String dateText = "${DateTime.now().year}.${DateTime.now().month}.${DateTime.now().day}"; return Directionality( textDirection: TextDirection.rtl, child: Container( width: MediaQuery.of(context).size.width * 0.8, margin: const EdgeInsets.only(bottom: 16), padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 14), decoration: BoxDecoration( color: bgColor, borderRadius: BorderRadius.circular(16), ), child: Column( crossAxisAlignment: CrossAxisAlignment.end, children: [ Row( mainAxisAlignment: MainAxisAlignment.center, children: [ buildStatusCircle( active: isWaiting, label: "قيد الانتظار", svgPath: isWaiting ? "assets/images/waiting.svg" : null, activeColor: const Color(0xFFF9C8A01B), glowColor: const Color(0xB4FFDC69), ), const SizedBox(width: 12), buildStatusCircle( active: isApproved, label: "موافقة", svgPath: isApproved ? "assets/images/yes.svg" : null, activeColor: const Color(0xFF0A8A60), glowColor: const Color(0xFF00D7A3), ), const SizedBox(width: 12), buildStatusCircle( active: isDenied, label: "تم الرفض", svgPath: isDenied ? "assets/images/no.svg" : null, activeColor: const Color(0xFFE63946), glowColor: const Color(0xFFE63946), ), ], ), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ SizedBox( width: 32, height: 32, child: Center( child: SvgPicture.asset( "assets/images/money.svg", width: 32, height: 32, color: const Color(0xFF11663C), ), ), ), const SizedBox(width: 8), Text( "سلفة: ${request.amount.toStringAsFixed(0)} دع", style: const TextStyle( fontSize: 12, color: Colors.black87, fontWeight: FontWeight.bold, ), ), ], ), Text( dateText, style: const TextStyle( fontSize: 14, color: Colors.black87, fontWeight: FontWeight.w500, ), ), ], ), const SizedBox(height: 10), Container(width: double.infinity, height: 1, color: lineColor), const SizedBox(height: 10), Padding( padding: const EdgeInsets.only(top: 8), child: Row( textDirection: TextDirection.ltr, children: [ Expanded( child: Text( request.reason, textAlign: TextAlign.right, style: const TextStyle( fontSize: 13, color: Colors.black87, ), ), ), const SizedBox(width: 6), const Text( "السبب :", textAlign: TextAlign.right, style: TextStyle( fontSize: 14, color: Colors.black87, fontWeight: FontWeight.bold, ), ), ], ), ), ], ), ), ); } } // -------------------- FLOATING ACTION BUTTON -------------------- class _HolidayActionButton extends StatelessWidget { final String label; final String svgPath; final VoidCallback onTap; final double iconWidth; final double iconHeight; const _HolidayActionButton({ required this.label, required this.svgPath, required this.onTap, required this.iconWidth, required this.iconHeight, }); @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Container( width: 80, height: 70, decoration: BoxDecoration( color: Colors.white, shape: BoxShape.circle, boxShadow: const [ BoxShadow( color: Color(0x4B00C68B), blurRadius: 20, offset: Offset(0, 6), ), ], ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ SizedBox( width: iconWidth, height: iconHeight, child: SvgPicture.asset(svgPath, fit: BoxFit.contain), ), const SizedBox(height: 6), Text( label, style: const TextStyle( fontSize: 14, fontWeight: FontWeight.w600, color: Colors.black, ), ), ], ), ), ); } }