UI changes was made to the hoilday screen

This commit is contained in:
Daniah Ayad Al-sultani
2025-12-07 17:41:57 +03:00
parent db044cb039
commit f73d3fbb75
2 changed files with 331 additions and 287 deletions

View File

@@ -45,38 +45,53 @@ class _HolidayScreenState extends State<HolidayScreen> {
}); });
} }
Color _getStatusColor(String status) { Widget buildStatusCircle({
switch (status) { required bool active,
case 'approved': required String label,
return Colors.green; required String? svgPath,
case 'denied': required Color activeColor,
return Colors.red; required Color glowColor,
default: }) {
return Colors.orange; return Column(
} children: [
Container(
width: 36, // Smaller circle
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, // Smaller icon
height: 18,
color: Colors.white,
),
)
: null,
),
const SizedBox(height: 4), // Space between circles
Text(label, style: const TextStyle(fontSize: 10)), // Smaller text
],
);
} }
String _getStatusText(String status) {
switch (status) {
case 'approved':
return 'موافق عليه';
case 'denied':
return 'مرفوض';
default:
return 'قيد الانتظار';
}
}
String _getStatusIconPath(String status) {
switch (status) {
case 'approved':
return "assets/images/yes.svg";
case 'denied':
return "assets/images/no.svg";
default:
return "assets/images/waiting.svg";
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -86,7 +101,7 @@ class _HolidayScreenState extends State<HolidayScreen> {
children: [ children: [
// Tabs // Tabs
Positioned( Positioned(
top: 40, top: 5,
left: 0, left: 0,
right: 0, right: 0,
child: Row( child: Row(
@@ -153,10 +168,10 @@ class _HolidayScreenState extends State<HolidayScreen> {
// Content area for requests // Content area for requests
Positioned( Positioned(
top: 100, // Position below the tabs top: 30, // Position below the tabs
left: 0, left: 0,
right: 0, right: 0,
bottom: 120, // Leave space for action buttons bottom: 0, // Leave space for action buttons
child: activeTab == 1 ? _buildLeaveRequestsTab() : _buildAdvanceRequestsTab(), child: activeTab == 1 ? _buildLeaveRequestsTab() : _buildAdvanceRequestsTab(),
), ),
@@ -170,8 +185,8 @@ class _HolidayScreenState extends State<HolidayScreen> {
_HolidayActionButton( _HolidayActionButton(
label: "طلب سلفة", label: "طلب سلفة",
svgPath: "assets/images/money2.svg", svgPath: "assets/images/money2.svg",
iconWidth: 38, iconWidth: 28,
iconHeight: 30, iconHeight: 20,
onTap: () async { onTap: () async {
// Navigate to RequestAdvanceScreen // Navigate to RequestAdvanceScreen
await Navigator.push( await Navigator.push(
@@ -189,8 +204,8 @@ class _HolidayScreenState extends State<HolidayScreen> {
_HolidayActionButton( _HolidayActionButton(
label: "طلب إجازة", label: "طلب إجازة",
svgPath: "assets/images/plus.svg", svgPath: "assets/images/plus.svg",
iconWidth: 30, iconWidth: 28,
iconHeight: 30, iconHeight: 20,
onTap: () async { onTap: () async {
await Navigator.push( await Navigator.push(
context, context,
@@ -222,19 +237,13 @@ class _HolidayScreenState extends State<HolidayScreen> {
); );
} }
return RefreshIndicator( return ListView.builder(
onRefresh: () async { padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20),
_initializeData(); itemCount: _leaveRequests.length,
itemBuilder: (context, index) {
final request = _leaveRequests[index];
return _buildLeaveRequestCard(request);
}, },
color: Colors.white,
child: ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20),
itemCount: _leaveRequests.length,
itemBuilder: (context, index) {
final request = _leaveRequests[index];
return _buildLeaveRequestCard(request);
},
),
); );
} }
@@ -251,285 +260,320 @@ class _HolidayScreenState extends State<HolidayScreen> {
); );
} }
return RefreshIndicator( return ListView.builder(
onRefresh: () async { padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20),
_initializeData(); itemCount: _advanceRequests.length,
itemBuilder: (context, index) {
final request = _advanceRequests[index];
return _buildAdvanceRequestCard(request);
}, },
color: Colors.white,
child: ListView.builder(
padding: const EdgeInsets.symmetric(horizontal: 25, vertical: 20),
itemCount: _advanceRequests.length,
itemBuilder: (context, index) {
final request = _advanceRequests[index];
return _buildAdvanceRequestCard(request);
},
),
); );
} }
Widget _buildLeaveRequestCard(LeaveRequest request) { Widget _buildLeaveRequestCard(LeaveRequest request) {
return Container( // Base colors from the design
margin: const EdgeInsets.only(bottom: 16), const bgColor = Color(0xFFEAF8F3);
padding: const EdgeInsets.all(16), // const activeColor = Color(0xFFFFC940); // yellow active state
decoration: BoxDecoration( // const inactiveColor = Color(0xFFD6D6D6); // grey inactive circles
color: Colors.white, const lineColor = Color(0xFF22A685); // green divider
borderRadius: BorderRadius.circular(16),
boxShadow: const [
BoxShadow(
color: Color(0x33000000),
blurRadius: 10,
offset: Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
// Header with type and status
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Status icon instead of text
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: _getStatusColor(request.status),
shape: BoxShape.circle,
),
child: SvgPicture.asset(
_getStatusIconPath(request.status),
width: 24,
height: 24,
color: Colors.white,
),
),
Text(
request.isTimedLeave ? "أجازة زمنية" : request.leaveType,
style: const TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 12), // Status flags
final bool isWaiting = request.status == "waiting";
final bool isApproved = request.status == "approved";
final bool isDenied = request.status == "denied";
// Date range final String dateText =
Directionality( "${request.fromDate.year}.${request.fromDate.month}.${request.fromDate.day}";
textDirection: TextDirection.rtl,
child: Row( return Directionality(
mainAxisAlignment: MainAxisAlignment.end, textDirection: TextDirection.rtl,
child: Container(
width: MediaQuery.of(context).size.width * 0.8, // 80% of screen width
margin: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), // Reduced padding
decoration: BoxDecoration(
color: bgColor,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
// ───────────────── STATUS ROW (centered) ─────────────────
Row(
mainAxisAlignment: MainAxisAlignment.center, // Center the status circles
children: [ children: [
Text( buildStatusCircle(
'من: ${request.fromDate.day}/${request.fromDate.month}/${request.fromDate.year}', active: isWaiting,
style: const TextStyle( label: "قيد الانتظار",
color: Colors.black87, svgPath: isWaiting ? "assets/images/waiting.svg" : null,
fontSize: 16, activeColor: const Color(0xFFF9C8A01B),
), glowColor: const Color(0xB4FFDC69),
), ),
const SizedBox(width: 20),
const SizedBox(width: 12), // Space between circles
buildStatusCircle(
active: isApproved,
label: "موافقة",
svgPath: isApproved ? "assets/images/yes.svg" : null,
activeColor: const Color(0xFF0A8A60),
glowColor: const Color(0xFF00D7A3),
),
const SizedBox(width: 12), // Space between circles
buildStatusCircle(
active: isDenied,
label: "تم الرفض",
svgPath: isDenied ? "assets/images/no.svg" : null,
activeColor: const Color(0xFFE63946),
glowColor: const Color(0xFFE63946),
),
],
),
const SizedBox(height: 8), // Reduced height
// ───────────── DATE (LEFT) + TYPE + TREE ICON (RIGHT) ─────────────
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Right cluster: tree icon + leave type
Row(
children: [
// Tree SVG in rounded square
SizedBox(
width: 32, // Smaller icon
height: 32,
child: Center(
child: SvgPicture.asset(
"assets/images/holiday.svg",
width: 32, // Smaller icon
height: 32,
color: const Color(0xFF11663C),
),
),
),
const SizedBox(width: 8),
Text(
request.leaveType,
style: const TextStyle(
fontSize: 12, // Smaller text
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
],
),
// Left: date
Text( Text(
'إلى: ${request.toDate.day}/${request.toDate.month}/${request.toDate.year}', dateText,
style: const TextStyle( style: const TextStyle(
fontSize: 14, // Smaller text
color: Colors.black87, color: Colors.black87,
fontSize: 16, fontWeight: FontWeight.w500,
), ),
), ),
], ],
), ),
),
if (request.isTimedLeave) ...[ const SizedBox(height: 10), // Reduced height
const SizedBox(height: 8),
Directionality( // Divider line
textDirection: TextDirection.rtl, Container(width: double.infinity, height: 1.4, color: lineColor),
const SizedBox(height: 10), // Reduced height
// Reason label
// ───────────── Reason Row (inline with label) ─────────────
Padding(
padding: const EdgeInsets.only(top: 8), // Reduced padding
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.end, textDirection: TextDirection.ltr,
children: [ children: [
Text( // Reason text (LEFT)
'من: ${request.fromTime.hour}:${request.fromTime.minute.toString().padLeft(2, '0')}', Expanded(
style: const TextStyle( child: Text(
color: Colors.black87, request.reason,
fontSize: 16, textAlign: TextAlign.right,
style: const TextStyle(
fontSize: 13, // Smaller text
color: Colors.black87,
),
), ),
), ),
const SizedBox(width: 20),
Text( const SizedBox(width: 6),
'إلى: ${request.toTime.hour}:${request.toTime.minute.toString().padLeft(2, '0')}',
style: const TextStyle( // Label (RIGHT)
const Text(
"السبب :",
textAlign: TextAlign.right,
style: TextStyle(
fontSize: 14, // Smaller text
color: Colors.black87, color: Colors.black87,
fontSize: 16, fontWeight: FontWeight.bold,
), ),
), ),
], ],
), ),
), ),
], ],
),
const SizedBox(height: 12),
// Reason
Directionality(
textDirection: TextDirection.rtl,
child: Container(
width: double.infinity,
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: const Color(0xFFF5F5F5),
borderRadius: BorderRadius.circular(8),
),
child: Text(
request.reason,
style: const TextStyle(
color: Colors.black87,
fontSize: 16,
),
),
),
),
const SizedBox(height: 12),
// Request date
Directionality(
textDirection: TextDirection.rtl,
child: Text(
'تاريخ الطلب: ${request.requestDate.day}/${request.requestDate.month}/${request.requestDate.year}',
style: const TextStyle(
color: Colors.grey,
fontSize: 14,
),
),
),
// Status text below the card
const SizedBox(height: 8),
Directionality(
textDirection: TextDirection.rtl,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
_getStatusText(request.status),
style: TextStyle(
color: _getStatusColor(request.status),
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
), ),
); );
} }
Widget _buildAdvanceRequestCard(AdvanceRequest request) { Widget _buildAdvanceRequestCard(AdvanceRequest request) {
return Container( // Base colors
margin: const EdgeInsets.only(bottom: 16), const bgColor = Color(0xFFEAF8F3);
padding: const EdgeInsets.all(16), const lineColor = Color(0xFF22A685);
decoration: BoxDecoration( // const inactiveColor = Color(0xFFD6D6D6);
color: Colors.white,
borderRadius: BorderRadius.circular(16),
boxShadow: const [
BoxShadow(
color: Color(0x33000000),
blurRadius: 10,
offset: Offset(0, 4),
),
],
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
// Header with status icon
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Status icon instead of text
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: _getStatusColor(request.status),
shape: BoxShape.circle,
),
child: SvgPicture.asset(
_getStatusIconPath(request.status),
width: 24,
height: 24,
color: Colors.white,
),
),
Text(
'طلب سلفة',
style: const TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
],
),
const SizedBox(height: 12), // Status flags
final bool isWaiting = request.status == "waiting";
final bool isApproved = request.status == "approved";
final bool isDenied = request.status == "denied";
// Amount // You can format a date if needed
Directionality( final String dateText =
textDirection: TextDirection.rtl, "${DateTime.now().year}.${DateTime.now().month}.${DateTime.now().day}";
child: Text(
'المبلغ: ${request.amount.toStringAsFixed(2)} دع',
style: const TextStyle(
color: Colors.black87,
fontSize: 16,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 12), return Directionality(
textDirection: TextDirection.rtl,
// Reason child: Container(
Directionality( width: MediaQuery.of(context).size.width * 0.8, // 80% of screen width
textDirection: TextDirection.rtl, margin: const EdgeInsets.only(bottom: 16),
child: Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 14), // Reduced padding
width: double.infinity, decoration: BoxDecoration(
padding: const EdgeInsets.all(12), color: bgColor,
decoration: BoxDecoration( borderRadius: BorderRadius.circular(16),
color: const Color(0xFFF5F5F5), ),
borderRadius: BorderRadius.circular(8), child: Column(
), crossAxisAlignment: CrossAxisAlignment.end,
child: Text( children: [
request.reason, // ───────────────── STATUS ROW (centered) ─────────────────
style: const TextStyle( Row(
color: Colors.black87, mainAxisAlignment: MainAxisAlignment.center, // Center the status circles
fontSize: 16,
),
),
),
),
// Status text below the card
const SizedBox(height: 8),
Directionality(
textDirection: TextDirection.rtl,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
buildStatusCircle(
active: isWaiting,
label: "قيد الانتظار",
svgPath: isWaiting ? "assets/images/waiting.svg" : null,
activeColor: const Color(0xFFF9C8A01B),
glowColor: const Color(0xB4FFDC69),
),
const SizedBox(width: 12), // Space between circles
buildStatusCircle(
active: isApproved,
label: "موافقة",
svgPath: isApproved ? "assets/images/yes.svg" : null,
activeColor: const Color(0xFF0A8A60),
glowColor: const Color(0xFF00D7A3),
),
const SizedBox(width: 12), // Space between circles
buildStatusCircle(
active: isDenied,
label: "تم الرفض",
svgPath: isDenied ? "assets/images/no.svg" : null,
activeColor: const Color(0xFFE63946),
glowColor: const Color(0xFFE63946),
),
],
),
const SizedBox(height: 8), // Reduced height
// ───────────────── TYPE + ICON + AMOUNT (same layout as leave card) ─────────────────
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// Right: money icon + amount label
Row(
children: [
SizedBox(
width: 32, // Smaller icon
height: 32,
child: Center(
child: SvgPicture.asset(
"assets/images/money.svg",
width: 32, // Smaller icon
height: 32,
color: const Color(0xFF11663C),
),
),
),
const SizedBox(width: 8),
Text(
"سلفة: ${request.amount.toStringAsFixed(0)} دع",
style: const TextStyle(
fontSize: 12, // Smaller text
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
],
),
// Left: dummy date (or request.requestDate)
Text( Text(
_getStatusText(request.status), dateText,
style: TextStyle( style: const TextStyle(
color: _getStatusColor(request.status), fontSize: 14, // Smaller text
fontSize: 14, color: Colors.black87,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w500,
), ),
), ),
], ],
), ),
),
], const SizedBox(height: 10), // Reduced height
// Divider line
Container(width: double.infinity, height: 1, color: lineColor),
const SizedBox(height: 10), // Reduced height
// ───────────────── REASON ROW (identical to leave card) ─────────────────
Padding(
padding: const EdgeInsets.only(top: 8), // Reduced padding
child: Row(
textDirection: TextDirection.ltr,
children: [
// Reason text (LEFT)
Expanded(
child: Text(
request.reason,
textAlign: TextAlign.right,
style: const TextStyle(
fontSize: 13, // Smaller text
color: Colors.black87,
),
),
),
const SizedBox(width: 6),
// Label (RIGHT)
const Text(
"السبب :",
textAlign: TextAlign.right,
style: TextStyle(
fontSize: 14, // Smaller text
color: Colors.black87,
fontWeight: FontWeight.bold,
),
),
],
),
),
],
),
), ),
); );
} }
@@ -556,7 +600,7 @@ class _HolidayActionButton extends StatelessWidget {
onTap: onTap, onTap: onTap,
child: Container( child: Container(
width: 80, width: 80,
height: 80, height: 70,
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
shape: BoxShape.circle, shape: BoxShape.circle,

View File

@@ -58,7 +58,7 @@ class _MainPageState extends State<MainPage> {
child: IndexedStack(index: _currentIndex, children: _screens), child: IndexedStack(index: _currentIndex, children: _screens),
), ),
const SizedBox(height: 20), // const SizedBox(height: 20),
Floatingnavbar( Floatingnavbar(
items: _navItems, items: _navItems,