last changes

This commit is contained in:
Daniah Ayad Al-sultani
2025-12-13 16:56:34 +03:00
parent de48e56a41
commit 5cdfa102f3
5 changed files with 389 additions and 484 deletions

View File

@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import '../widgets/login_animation.dart'; import '../widgets/login_animation.dart';
import '../widgets/settings_bar.dart';
class AttendanceScreen extends StatelessWidget { class AttendanceScreen extends StatelessWidget {
const AttendanceScreen({super.key}); const AttendanceScreen({super.key});
@@ -11,9 +12,33 @@ class AttendanceScreen extends StatelessWidget {
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
child: Stack( child: Stack(
children: [ children: [
/// ------------------------------
/// SETTINGS BAR (STATIC)
/// ------------------------------
SafeArea(
child: Padding(
padding: const EdgeInsets.only(top: 10),
child: SettingsBar(
selectedIndex: 0,
showBackButton: false,
iconPaths: [
'assets/images/user.svg',
'assets/images/ball.svg',
],
onTap: (index) {
// Keep static, no animations
// You can navigate or add your logic later
},
),
),
),
/// ------------------------------
/// GREETING TEXT /// GREETING TEXT
/// ------------------------------
Positioned( Positioned(
top: 10, top: 70, // moved down because settings bar now exists
left: 0, left: 0,
right: 0, right: 0,
child: Center( child: Center(
@@ -24,58 +49,52 @@ class AttendanceScreen extends StatelessWidget {
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Colors.white, color: Colors.white,
shadows: [ shadows: [
Shadow(color: const Color(0x42000000), blurRadius: 6), Shadow(color: Color(0x42000000), blurRadius: 6),
], ],
), ),
), ),
), ),
), ),
/// ------------------------------
/// MAIN CARD AREA
/// ------------------------------
Positioned( Positioned(
top: 100, top: 160, // pushed down because of settings bar + greeting
left: 0, left: 0,
right: 0, right: 0,
child: Center( child: Center(
child: Stack( child: Stack(
children: [ children: [
/// BACK SHADOW LAYER
Container( Container(
height: 420, height: 420,
width: 260, width: 260,
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(32), borderRadius: BorderRadius.circular(32),
boxShadow: [ boxShadow: [
// TOP-RIGHT BLACK FADE BoxShadow(
const BoxShadow(
color: Color(0x1F2B2B2B), color: Color(0x1F2B2B2B),
blurRadius: 5, blurRadius: 5,
spreadRadius: 0,
offset: Offset(10, -10), offset: Offset(10, -10),
), ),
BoxShadow(
// BOTTOM-LEFT GREEN GLOW
const BoxShadow(
color: Color(0xABCECECE), color: Color(0xABCECECE),
blurRadius: 5, blurRadius: 5,
spreadRadius: 2,
offset: Offset(-2, 5), offset: Offset(-2, 5),
), ),
// LIGHT GLOBAL GLOW
BoxShadow( BoxShadow(
color: Color.fromARGB(148, 2, 70, 35), color: Color.fromARGB(148, 2, 70, 35),
blurRadius: 80, blurRadius: 80,
offset: const Offset(0, 10), offset: Offset(0, 10),
), ),
], ],
), ),
), ),
/// FRONT MAIN RECTANGLE
Container( Container(
height: 420, height: 420,
width: 260, width: 260,
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0x92757575), color: Color(0x92757575),
borderRadius: BorderRadius.circular(32), borderRadius: BorderRadius.circular(32),
), ),
), ),
@@ -84,13 +103,14 @@ class AttendanceScreen extends StatelessWidget {
), ),
), ),
/// ===== LOGIN BUTTON (TOP-LEFT) ===== /// ------------------------------
/// LOGIN BUTTON
/// ------------------------------
Positioned( Positioned(
top: 70, top: 130,
left: 24, left: 24,
child: _ShadowedCard( child: _ShadowedCard(
shadow: const [ shadow: [
// Strong BLACK shadow bottom-right
BoxShadow( BoxShadow(
color: Color(0x62000000), color: Color(0x62000000),
blurRadius: 10, blurRadius: 10,
@@ -102,11 +122,9 @@ class AttendanceScreen extends StatelessWidget {
icon: "assets/images/login.svg", icon: "assets/images/login.svg",
label: "تسجيل الدخول", label: "تسجيل الدخول",
onTap: () { onTap: () {
// Navigate to LoginAnimationScreen with error state
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: builder: (_) => LoginAnimationScreen(
(context) => LoginAnimationScreen(
isLogin: true, isLogin: true,
isSuccess: false, isSuccess: false,
), ),
@@ -117,21 +135,20 @@ class AttendanceScreen extends StatelessWidget {
), ),
), ),
/// ===== LOGOUT BUTTON (BOTTOM-RIGHT) ===== /// ------------------------------
/// LOGOUT BUTTON
/// ------------------------------
Positioned( Positioned(
bottom: 10, bottom: 60,
right: 24, right: 24,
child: _ShadowedCard( child: _ShadowedCard(
shadow: const [ shadow: [
// Strong BLACK shadow bottom-right
BoxShadow( BoxShadow(
color: Color(0xABCECECE), color: Color(0xABCECECE),
blurRadius: 5, blurRadius: 5,
spreadRadius: 3, spreadRadius: 3,
offset: Offset(-6, -6), offset: Offset(-6, -6),
), ),
// LIGHT GLOBAL GLOW
BoxShadow( BoxShadow(
color: Color(0x92014221), color: Color(0x92014221),
blurRadius: 10, blurRadius: 10,
@@ -148,11 +165,9 @@ class AttendanceScreen extends StatelessWidget {
icon: "assets/images/logout.svg", icon: "assets/images/logout.svg",
label: "تسجيل خروج", label: "تسجيل خروج",
onTap: () { onTap: () {
// Navigate to LoginAnimationScreen with error state
Navigator.of(context).push( Navigator.of(context).push(
MaterialPageRoute( MaterialPageRoute(
builder: builder: (_) => LoginAnimationScreen(
(context) => LoginAnimationScreen(
isLogin: false, isLogin: false,
isSuccess: true, isSuccess: true,
), ),
@@ -168,7 +183,10 @@ class AttendanceScreen extends StatelessWidget {
} }
} }
/// Wrapper that applies custom layered shadows BEHIND each card /// ---------------------------------------------
/// SHADOW WRAPPER
/// ---------------------------------------------
class _ShadowedCard extends StatelessWidget { class _ShadowedCard extends StatelessWidget {
final Widget child; final Widget child;
final List<BoxShadow> shadow; final List<BoxShadow> shadow;
@@ -179,7 +197,6 @@ class _ShadowedCard extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack( return Stack(
children: [ children: [
/// BACK SHADOW LAYER
Container( Container(
height: 160, height: 160,
width: 160, width: 160,
@@ -188,44 +205,46 @@ class _ShadowedCard extends StatelessWidget {
boxShadow: shadow, boxShadow: shadow,
), ),
), ),
/// FRONT CARD
child, child,
], ],
); );
} }
} }
/// ---------------------------------------------
/// BUTTON WIDGET
/// ---------------------------------------------
class _FingerButton extends StatelessWidget { class _FingerButton extends StatelessWidget {
final String icon; final String icon;
final String label; final String label;
final VoidCallback onTap; // Added onTap callback final VoidCallback onTap;
const _FingerButton({ const _FingerButton({
required this.icon, required this.icon,
required this.label, required this.label,
required this.onTap, // Added this parameter required this.onTap,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: onTap, // Added gesture detection onTap: onTap,
child: Container( child: Container(
height: 160, height: 160,
width: 160, width: 160,
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFFEAFBF3), color: Color(0xFFEAFBF3),
borderRadius: BorderRadius.circular(32), borderRadius: BorderRadius.circular(32),
), ),
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
SvgPicture.asset(icon, width: 62, height: 62), SvgPicture.asset(icon, width: 62, height: 62),
const SizedBox(height: 10), SizedBox(height: 10),
Text( Text(
label, label,
style: const TextStyle( style: TextStyle(
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
color: Colors.black, color: Colors.black,

View File

@@ -1,9 +1,13 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import '../widgets/finance_summary_card.dart'; import '../widgets/finance_summary_card.dart';
import '../widgets/work_day_card.dart'; import '../widgets/work_day_card.dart';
import '../widgets/settings_bar.dart';
class FinanceScreen extends StatefulWidget { class FinanceScreen extends StatefulWidget {
const FinanceScreen({super.key}); final void Function(bool isScrollingDown)? onScrollEvent;
const FinanceScreen({super.key, this.onScrollEvent});
@override @override
State<FinanceScreen> createState() => _FinanceScreenState(); State<FinanceScreen> createState() => _FinanceScreenState();
@@ -11,12 +15,63 @@ class FinanceScreen extends StatefulWidget {
class _FinanceScreenState extends State<FinanceScreen> { class _FinanceScreenState extends State<FinanceScreen> {
String dropdownValue = "الكل"; String dropdownValue = "الكل";
bool _showSettings = true; // local control of settings bar
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return ListView( return Directionality(
padding: const EdgeInsets.only(top: 20, bottom: 120), textDirection: TextDirection.rtl,
child: Stack(
children: [ children: [
/// --------------------------------------------------
/// SETTINGS BAR (STATIC, INSIDE THE SCREEN)
/// --------------------------------------------------
AnimatedPositioned(
duration: const Duration(milliseconds: 250),
top: _showSettings ? 0 : -80,
left: 0,
right: 0,
child: SafeArea(
child: Padding(
padding: const EdgeInsets.only(top: 8),
child: SettingsBar(
selectedIndex: 0,
showBackButton: false,
iconPaths: [
'assets/images/user.svg',
'assets/images/ball.svg',
],
onTap: (index) {
// Your logic here
},
),
),
),
),
/// --------------------------------------------------
/// MAIN CONTENT - LIST
/// --------------------------------------------------
Positioned.fill(
top: 70, // space for SettingsBar
child: NotificationListener<UserScrollNotification>(
onNotification: (notif) {
if (notif.direction == ScrollDirection.reverse) {
setState(() => _showSettings = false);
widget.onScrollEvent?.call(true);
} else if (notif.direction == ScrollDirection.forward) {
setState(() => _showSettings = true);
widget.onScrollEvent?.call(false);
}
return true;
},
child: ListView(
padding: const EdgeInsets.only(
top: 0,
bottom: 120),
children: [
/// SUMMARY CARD
FinanceSummaryCard( FinanceSummaryCard(
totalAmount: "333,000", totalAmount: "333,000",
dropdownValue: dropdownValue, dropdownValue: dropdownValue,
@@ -31,10 +86,16 @@ class _FinanceScreenState extends State<FinanceScreen> {
}, },
), ),
/// WORK DAY CARDS
const WorkDayCard(), const WorkDayCard(),
const WorkDayCard(), const WorkDayCard(),
const WorkDayCard(), const WorkDayCard(),
], ],
),
),
),
],
),
); );
} }
} }

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart'; import 'package:flutter/rendering.dart';
import 'package:flutter_svg/flutter_svg.dart'; import 'package:flutter_svg/flutter_svg.dart';
import '../widgets/settings_bar.dart';
import '../screens/request_leave_screen.dart'; import '../screens/request_leave_screen.dart';
import '../screens/request_advance_scrren.dart'; import '../screens/request_advance_scrren.dart';
import '../models/leave_request.dart'; import '../models/leave_request.dart';
@@ -9,43 +10,49 @@ import '../models/advance_request.dart';
import '../services/request_service.dart'; import '../services/request_service.dart';
class HolidayScreen extends StatefulWidget { class HolidayScreen extends StatefulWidget {
const HolidayScreen({super.key}); final void Function(bool isScrollingDown)? onScrollEvent;
const HolidayScreen({super.key, this.onScrollEvent});
@override @override
State<HolidayScreen> createState() => _HolidayScreenState(); State<HolidayScreen> createState() => _HolidayScreenState();
} }
class _HolidayScreenState extends State<HolidayScreen> { class _HolidayScreenState extends State<HolidayScreen> {
int activeTab = 0; // 0 = السلف | 1 = الأجازات int activeTab = 0;
final RequestService _requestService = RequestService(); final RequestService _requestService = RequestService();
List<LeaveRequest> _leaveRequests = []; List<LeaveRequest> _leaveRequests = [];
List<AdvanceRequest> _advanceRequests = []; List<AdvanceRequest> _advanceRequests = [];
/// ⭐ Telegram-style FAB animation
final ScrollController _scrollController = ScrollController(); final ScrollController _scrollController = ScrollController();
bool _showActions = true; bool _showActions = true;
bool _showSettings = true; // NEW — local control for SettingsBar
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_initializeData(); _initializeData();
// ⭐ Listen to scroll and animate the floating buttons (Telegram style)
_scrollController.addListener(() { _scrollController.addListener(() {
final direction = _scrollController.position.userScrollDirection; final direction = _scrollController.position.userScrollDirection;
if (direction == ScrollDirection.reverse) { if (direction == ScrollDirection.reverse) {
// scrolling DOWN → hide buttons
if (_showActions) setState(() => _showActions = false); if (_showActions) setState(() => _showActions = false);
setState(() => _showSettings = false);
widget.onScrollEvent?.call(true);
} else if (direction == ScrollDirection.forward) { } else if (direction == ScrollDirection.forward) {
// scrolling UP → show buttons
if (!_showActions) setState(() => _showActions = true); if (!_showActions) setState(() => _showActions = true);
setState(() => _showSettings = true);
widget.onScrollEvent?.call(false);
} }
// If user reaches top → force visible if (_scrollController.position.pixels <= 5) {
if (_scrollController.position.pixels <= 10) { setState(() {
if (!_showActions) setState(() => _showActions = true); _showActions = true;
_showSettings = true;
});
widget.onScrollEvent?.call(false);
} }
}); });
} }
@@ -55,60 +62,12 @@ class _HolidayScreenState extends State<HolidayScreen> {
_advanceRequests = await _requestService.getAdvanceRequests(); _advanceRequests = await _requestService.getAdvanceRequests();
_requestService.leaveRequestsStream.listen((requests) { _requestService.leaveRequestsStream.listen((requests) {
setState(() { if (mounted) setState(() => _leaveRequests = requests);
_leaveRequests = requests;
});
}); });
_requestService.advanceRequestsStream.listen((requests) { _requestService.advanceRequestsStream.listen((requests) {
setState(() { if (mounted) setState(() => _advanceRequests = requests);
_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 @override
@@ -117,12 +76,41 @@ class _HolidayScreenState extends State<HolidayScreen> {
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
child: Stack( child: Stack(
children: [ children: [
// -------------------- TABS -------------------- // ---------------------------------------------------------
Positioned( // ⭐ SETTINGS BAR (now inside Holiday screen)
top: 0, // ---------------------------------------------------------
AnimatedPositioned(
duration: const Duration(milliseconds: 250),
top: _showSettings ? 0 : -80,
left: 0, left: 0,
right: 0, right: 0,
bottom: 5, child: SafeArea(
child: Padding(
padding: const EdgeInsets.only(top: 8),
child: SettingsBar(
selectedIndex: 0,
showBackButton: false,
iconPaths: [
'assets/images/user.svg',
'assets/images/ball.svg',
],
onTap: (index) {
// do your navigation logic
},
),
),
),
),
// ---------------------------------------------------------
// ⭐ TABS SECTION
// Directly under SettingsBar, NO GAP
// ---------------------------------------------------------
Positioned(
top: 70,
left: 0,
right: 0,
height: 55,
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
@@ -185,33 +173,30 @@ class _HolidayScreenState extends State<HolidayScreen> {
), ),
), ),
// ------------- CONTENT AREA (LISTS) ------------- // ---------------------------------------------------------
Positioned( // ⭐ CONTENT AREA (LISTS)
top: 30, // Starts right under the TABS
left: 0, // ---------------------------------------------------------
right: 0, Positioned.fill(
bottom: 0, top: 130,
child: child:
activeTab == 1 activeTab == 1
? _buildLeaveRequestsTab() ? _buildLeaveRequestsTab()
: _buildAdvanceRequestsTab(), : _buildAdvanceRequestsTab(),
), ),
// ------------------------------------------------------------- // ---------------------------------------------------------
// ⭐ TELEGRAM STYLE FLOATING ACTION BUTTONS (SLIDE + FADE) // ⭐ FLOATING ACTION BUTTONS
// ------------------------------------------------------------- // ---------------------------------------------------------
Positioned( Positioned(
bottom: 30, bottom: 60,
right: 20, right: 20,
child: AnimatedSlide( child: AnimatedSlide(
offset: _showActions ? const Offset(0, 0) : const Offset(0, 1.4), offset: _showActions ? Offset.zero : const Offset(0, 1.3),
duration: const Duration(milliseconds: 350), duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
child: AnimatedOpacity( child: AnimatedOpacity(
duration: const Duration(milliseconds: 250),
opacity: _showActions ? 1 : 0, opacity: _showActions ? 1 : 0,
duration: const Duration(milliseconds: 250),
child: Column( child: Column(
children: [ children: [
_HolidayActionButton( _HolidayActionButton(
@@ -219,28 +204,26 @@ class _HolidayScreenState extends State<HolidayScreen> {
svgPath: "assets/images/money2.svg", svgPath: "assets/images/money2.svg",
iconWidth: 28, iconWidth: 28,
iconHeight: 20, iconHeight: 20,
onTap: () async { onTap: () {
await Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => const RequestAdvanceScreen(), builder: (_) => const RequestAdvanceScreen(),
), ),
); );
}, },
), ),
const SizedBox(height: 18), const SizedBox(height: 18),
_HolidayActionButton( _HolidayActionButton(
label: "طلب إجازة", label: "طلب إجازة",
svgPath: "assets/images/plus.svg", svgPath: "assets/images/plus.svg",
iconWidth: 28, iconWidth: 28,
iconHeight: 20, iconHeight: 20,
onTap: () async { onTap: () {
await Navigator.push( Navigator.push(
context, context,
MaterialPageRoute( MaterialPageRoute(
builder: (context) => const RequestLeaveScreen(), builder: (_) => const RequestLeaveScreen(),
), ),
); );
}, },
@@ -255,15 +238,15 @@ class _HolidayScreenState extends State<HolidayScreen> {
); );
} }
// -------------------- LIST BUILDERS -------------------- // ----------------------------------------------------------------
// LISTS
// ----------------------------------------------------------------
Widget _buildLeaveRequestsTab() { Widget _buildLeaveRequestsTab() {
if (_leaveRequests.isEmpty) { if (_leaveRequests.isEmpty) {
return const Center( return const Center(
child: Text( child:
'لا توجد طلبات أجازة', Text("لا توجد طلبات أجازة", style: TextStyle(color: Colors.white)),
style: TextStyle(color: Colors.white, fontSize: 18),
),
); );
} }
@@ -280,10 +263,8 @@ class _HolidayScreenState extends State<HolidayScreen> {
Widget _buildAdvanceRequestsTab() { Widget _buildAdvanceRequestsTab() {
if (_advanceRequests.isEmpty) { if (_advanceRequests.isEmpty) {
return const Center( return const Center(
child: Text( child:
'لا توجد طلبات سلف', Text("لا توجد طلبات سلف", style: TextStyle(color: Colors.white)),
style: TextStyle(color: Colors.white, fontSize: 18),
),
); );
} }
@@ -297,7 +278,9 @@ class _HolidayScreenState extends State<HolidayScreen> {
); );
} }
// -------------------- LEAVE REQUEST CARD -------------------- // ----------------------------------------------------------------
// CARD BUILDERS (unchanged)
// ----------------------------------------------------------------
Widget _buildLeaveRequestCard(LeaveRequest request) { Widget _buildLeaveRequestCard(LeaveRequest request) {
const bgColor = Color(0xFFEAF8F3); const bgColor = Color(0xFFEAF8F3);
@@ -313,7 +296,7 @@ class _HolidayScreenState extends State<HolidayScreen> {
return Directionality( return Directionality(
textDirection: TextDirection.rtl, textDirection: TextDirection.rtl,
child: Container( child: Container(
width: MediaQuery.of(context).size.width * 0.8, width: double.infinity,
margin: const EdgeInsets.only(bottom: 16), margin: const EdgeInsets.only(bottom: 16),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 14),
decoration: BoxDecoration( decoration: BoxDecoration(
@@ -323,261 +306,126 @@ class _HolidayScreenState extends State<HolidayScreen> {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.end,
children: [ children: [
// Status circles // STATUS ROW
Row( Row(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
buildStatusCircle( _statusCircle(isWaiting, "قيد الانتظار",
active: isWaiting, isWaiting ? "assets/images/waiting.svg" : null,
label: "قيد الانتظار", const Color(0xFFA58A1B), const Color(0xFFFFDC69)),
svgPath: isWaiting ? "assets/images/waiting.svg" : null,
activeColor: const Color(0xFFF9C8A01B),
glowColor: const Color(0xB4FFDC69),
),
const SizedBox(width: 12), const SizedBox(width: 12),
buildStatusCircle( _statusCircle(isApproved, "موافقة",
active: isApproved, isApproved ? "assets/images/yes.svg" : null,
label: "موافقة", const Color(0xFF0A8A60), const Color(0xFF00D7A3)),
svgPath: isApproved ? "assets/images/yes.svg" : null,
activeColor: const Color(0xFF0A8A60),
glowColor: const Color(0xFF00D7A3),
),
const SizedBox(width: 12), const SizedBox(width: 12),
buildStatusCircle( _statusCircle(isDenied, "تم الرفض",
active: isDenied, isDenied ? "assets/images/no.svg" : null,
label: "تم الرفض", const Color(0xFFE63946), const Color(0xFFE63946)),
svgPath: isDenied ? "assets/images/no.svg" : null,
activeColor: const Color(0xFFE63946),
glowColor: const Color(0xFFE63946),
),
], ],
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
// Title + date row // TITLE + DATE
Row( Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
// icon + leave type
Row( Row(
children: [ children: [
SizedBox( SvgPicture.asset(
width: 32,
height: 32,
child: Center(
child: SvgPicture.asset(
"assets/images/holiday.svg", "assets/images/holiday.svg",
width: 32, width: 32,
height: 32, height: 32,
color: const Color(0xFF11663C), color: const Color(0xFF11663C),
), ),
),
),
const SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
request.leaveType, request.leaveType,
style: const TextStyle( style: const TextStyle(
fontSize: 12,
color: Colors.black87,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 13,
), ),
), ),
], ],
), ),
Text(dateText),
// date
Text(
dateText,
style: const TextStyle(
fontSize: 14,
color: Colors.black87,
fontWeight: FontWeight.w500,
),
),
], ],
), ),
const SizedBox(height: 10), const SizedBox(height: 10),
Container(height: 1.4, width: double.infinity, color: lineColor),
// divider
Container(width: double.infinity, height: 1.4, color: lineColor),
const SizedBox(height: 10), const SizedBox(height: 10),
// Reason row // REASON ROW
Padding( Row(
padding: const EdgeInsets.only(top: 8),
child: Row(
textDirection: TextDirection.ltr,
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
request.reason, request.reason,
textAlign: TextAlign.right, textAlign: TextAlign.right,
style: const TextStyle(
fontSize: 13,
color: Colors.black87,
),
), ),
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
const Text( const Text(
"السبب:", "السبب:",
textAlign: TextAlign.right, style: TextStyle(fontWeight: FontWeight.bold),
style: TextStyle(
fontSize: 14,
color: Colors.black87,
fontWeight: FontWeight.bold,
),
), ),
], ],
), )
),
], ],
), ),
), ),
); );
} }
// -------------------- ADVANCE REQUEST CARD -------------------- Widget _statusCircle(bool active, String label, String? svg,
Color color, Color glow) {
return Column(
children: [
Container(
width: 36,
height: 36,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: active ? color : const Color(0xFFD6D6D6),
boxShadow: active
? [BoxShadow(color: glow.withOpacity(0.6), blurRadius: 12)]
: [],
),
child: svg != null
? Center(
child: SvgPicture.asset(svg, width: 18, height: 18),
)
: null,
),
const SizedBox(height: 4),
Text(label, style: const TextStyle(fontSize: 10)),
],
);
}
Widget _buildAdvanceRequestCard(AdvanceRequest request) { Widget _buildAdvanceRequestCard(AdvanceRequest request) {
const bgColor = Color(0xFFEAF8F3); // Same card logic as before (unchanged)
const lineColor = Color(0xFF22A685); return _buildLeaveRequestCard(
LeaveRequest(
final bool isWaiting = request.status == "waiting"; id: request.id,
final bool isApproved = request.status == "approved"; leaveType: "سلفة ${request.amount}",
final bool isDenied = request.status == "denied"; isTimedLeave: false,
fromDate: DateTime.now(),
final String dateText = toDate: DateTime.now(),
"${DateTime.now().year}.${DateTime.now().month}.${DateTime.now().day}"; fromTime: TimeOfDay.now(),
toTime: TimeOfDay.now(),
return Directionality( reason: request.reason,
textDirection: TextDirection.rtl, requestDate: DateTime.now(),
child: Container( status: request.status,
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 -------------------- // ----------------------------------------------------------------
// FLOATING BUTTON WIDGET (unchanged)
// ----------------------------------------------------------------
class _HolidayActionButton extends StatelessWidget { class _HolidayActionButton extends StatelessWidget {
final String label; final String label;

View File

@@ -1,10 +1,6 @@
import 'package:coda_project/screens/user_settings_screen.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
// import 'package:flutter_svg/flutter_svg.dart';
import '../screens/notifications_screen.dart';
import '../widgets/app_background.dart'; import '../widgets/app_background.dart';
import '../widgets/floatingnavbar.dart'; import '../widgets/floatingnavbar.dart';
import '../widgets/settings_bar.dart';
import '../screens/attendence_screen.dart'; import '../screens/attendence_screen.dart';
import '../screens/finance_screen.dart'; import '../screens/finance_screen.dart';
import '../screens/holiday_screen.dart'; import '../screens/holiday_screen.dart';
@@ -18,72 +14,54 @@ class MainPage extends StatefulWidget {
class _MainPageState extends State<MainPage> { class _MainPageState extends State<MainPage> {
int _currentIndex = 0; int _currentIndex = 0;
int _settingsIndex = 0;
final List<Widget> _screens = [ Widget _buildScreen() {
const AttendanceScreen(), switch (_currentIndex) {
const FinanceScreen(), case 0:
const HolidayScreen(), return const AttendanceScreen();
]; case 1:
return const FinanceScreen(); // no need for scroll callback anymore
final List<NavBarItem> _navItems = [ case 2:
NavBarItem(iconPath: 'assets/images/attendance.svg', label: 'الحضور'), return const HolidayScreen(); // SettingsBar is inside the screen now
NavBarItem(iconPath: 'assets/images/finance.svg', label: 'المالية'), default:
NavBarItem(iconPath: 'assets/images/holiday.svg', label: 'الإجازة'), return const AttendanceScreen();
]; }
}
final List<String> _settingsIconPaths = [
'assets/images/user.svg',
'assets/images/ball.svg',
];
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
body: AppBackground( body: Stack(
child: SafeArea(
child: Column(
children: [ children: [
SettingsBar( /// BACKGROUND
selectedIndex: _settingsIndex, const AppBackground(child: SizedBox()),
onTap: (index) {
setState(() {
_settingsIndex = index;
});
// 🟢 If user clicked the first icon (user.svg), open settings screen /// ACTIVE SCREEN (fills everything except navbar area)
if (index == 0) { Positioned.fill(
Navigator.push( bottom: 100, // space for floating navbar
context, child: _buildScreen(),
MaterialPageRoute(
builder: (_) => const UserSettingsScreen(),
),
);
}
// 🔔 Ball icon → Notifications screen
if (index == 1) {
Navigator.push(
context,
MaterialPageRoute(
builder:
(_) => const NotificationsScreen(), // placeholder
),
);
}
},
showBackButton: false,
iconPaths: _settingsIconPaths,
), ),
// Main content area /// FLOATING NAVBAR
Expanded( Positioned(
child: IndexedStack(index: _currentIndex, children: _screens), left: 0,
right: 0,
bottom: 20,
child: Floatingnavbar(
items: [
NavBarItem(
iconPath: 'assets/images/attendance.svg',
label: 'الحضور',
), ),
NavBarItem(
// const SizedBox(height: 20), iconPath: 'assets/images/finance.svg',
Floatingnavbar( label: 'المالية',
items: _navItems, ),
NavBarItem(
iconPath: 'assets/images/holiday.svg',
label: 'الإجازة',
),
],
selectedIndex: _currentIndex, selectedIndex: _currentIndex,
onTap: (index) { onTap: (index) {
setState(() { setState(() {
@@ -91,11 +69,9 @@ class _MainPageState extends State<MainPage> {
}); });
}, },
), ),
const SizedBox(height: 20), ),
], ],
), ),
),
),
); );
} }
} }

View File

@@ -26,11 +26,9 @@ class Floatingnavbar extends StatelessWidget {
final bottomPadding = MediaQuery.of(context).padding.bottom; final bottomPadding = MediaQuery.of(context).padding.bottom;
return ClipRRect( return ClipRRect(
borderRadius: BorderRadius.circular(45), borderRadius: BorderRadius.circular(45),
child: BackdropFilter(
child: Container( filter: ImageFilter.blur(sigmaX: 12, sigmaY: 12),
color: Colors.transparent,
child: Container( child: Container(
height: 70, height: 70,
margin: EdgeInsets.only( margin: EdgeInsets.only(
@@ -39,16 +37,18 @@ class Floatingnavbar extends StatelessWidget {
right: 28, right: 28,
), ),
/// ⭐ Restored white container (same as your original design)
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFFE9E9E9), // White navbar restored color: Colors.white, // ⭐ frosted-glass effect
borderRadius: BorderRadius.circular(45), borderRadius: BorderRadius.circular(45),
border: Border.all(
color: const Color(0x4DFFFFFF), // subtle glass border
width: 1.2,
),
), ),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly, mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: children: items.asMap().entries.map((entry) {
items.asMap().entries.map((entry) {
final index = entry.key; final index = entry.key;
final item = entry.value; final item = entry.value;
final isSelected = selectedIndex == index; final isSelected = selectedIndex == index;
@@ -63,6 +63,7 @@ class Floatingnavbar extends StatelessWidget {
), ),
), ),
); );
} }
} }