Files
finger_print_app/lib/screens/request_leave_screen.dart
Daniah Ayad Al-sultani 88f70bcd25 last chnages
2025-12-14 16:05:30 +03:00

643 lines
26 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../widgets/app_background.dart';
import '../widgets/settings_bar.dart';
import '../widgets/onboarding_button.dart';
import '../models/leave_request.dart';
import '../services/request_service.dart';
class RequestLeaveScreen extends StatefulWidget {
const RequestLeaveScreen({super.key});
@override
State<RequestLeaveScreen> createState() => _RequestLeaveScreenState();
}
class _RequestLeaveScreenState extends State<RequestLeaveScreen> {
// Dropdown value - initialize with default
String leaveType = "إجازة مرضية ";
// Toggle switch
bool isTimedLeave = false;
// Date & time selectors
DateTime? fromDate = DateTime.now();
DateTime? toDate = DateTime.now();
TimeOfDay? fromTime = const TimeOfDay(hour: 12, minute: 00);
TimeOfDay? toTime = const TimeOfDay(hour: 12, minute: 00);
// Text controller for reason
final TextEditingController reasonController = TextEditingController();
// Use the singleton instance
final RequestService _requestService = RequestService();
/// PICK DATE
Future<void> pickDate(bool isFrom) async {
DateTime initial = isFrom ? fromDate! : toDate!;
DateTime? newDate = await showDatePicker(
context: context,
initialDate: initial,
firstDate: DateTime(2020),
lastDate: DateTime(2035),
builder: (context, child) {
return Theme(data: ThemeData.dark(), child: child!);
},
);
if (newDate != null) {
setState(() {
if (isFrom) {
fromDate = newDate;
} else {
toDate = newDate;
}
});
}
}
/// PICK TIME
Future<void> pickTime(bool isFrom) async {
TimeOfDay initial = isFrom ? fromTime! : toTime!;
TimeOfDay? newTime = await showTimePicker(
context: context,
initialTime: initial,
builder: (context, child) {
return Theme(data: ThemeData.dark(), child: child!);
},
);
if (newTime != null) {
setState(() {
if (isFrom) {
fromTime = newTime;
} else {
toTime = newTime;
}
});
}
}
// Method to save the leave request
Future<void> _saveLeaveRequest() async {
if (reasonController.text.isEmpty) {
// Show an error message if reason is empty
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('الرجاء إدخال السبب'),
backgroundColor: Colors.red,
),
);
return;
}
// Create a new leave request with default status "waiting"
final leaveRequest = LeaveRequest(
id: DateTime.now().millisecondsSinceEpoch.toString(),
leaveType: leaveType, // Use the current leaveType value
isTimedLeave: isTimedLeave,
fromDate: fromDate!,
toDate: toDate!,
fromTime: fromTime!,
toTime: toTime!,
reason: reasonController.text,
requestDate: DateTime.now(),
status: "waiting", // Default status
);
try {
// Save the leave request
await _requestService.addLeaveRequest(leaveRequest);
// Show a success message
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(
content: Text('تم إرسال طلب الأجازة بنجاح'),
backgroundColor: Colors.green,
),
);
// Navigate back to the previous screen
Navigator.pop(context);
} catch (e) {
// Show an error message if something went wrong
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('حدث خطأ: $e'), backgroundColor: Colors.red),
);
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
resizeToAvoidBottomInset: true, // ✅ IMPORTANT
body: AppBackground(
child: SafeArea(
child: Column(
children: [
// In your RequestLeaveScreen's build method, replace the SettingsBar with this:
SettingsBar(
selectedIndex: -1,
onTap: (_) {},
showBackButton: true,
onBackTap: () => Navigator.pop(context),
iconPaths: const [
"assets/images/user.svg",
"assets/images/bell.svg",
],
),
// Title
// const SizedBox(height: 30),
Flexible(
child: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 25),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
// Fixed alignment for "طلب أجازة"
const Align(
alignment: Alignment.topRight,
child: Text(
"طلب أجازة ",
style: TextStyle(
color: Colors.white,
fontSize: 28,
fontWeight: FontWeight.bold,
),
),
),
const SizedBox(height: 10),
//=============================
// DROPDOWN: نوع الإجازة
//=============================
Align(
alignment: Alignment.centerRight,
child: const Text(
"نوع الإجازة",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
const SizedBox(height: 5),
// Modified dropdown with disabled state
Directionality(
textDirection: TextDirection.rtl,
child: Opacity(
opacity: isTimedLeave ? 0.45 : 1.0,
child: IgnorePointer(
ignoring: isTimedLeave,
child: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(
horizontal: 20,
),
height: 58,
decoration: BoxDecoration(
color:
isTimedLeave
? Colors.grey[300]
: Colors.white,
borderRadius: BorderRadius.circular(14),
boxShadow: const [
BoxShadow(
color: Color(0x22000000),
blurRadius: 8,
offset: Offset(0, 3),
),
],
),
child: DropdownButtonHideUnderline(
child: DropdownButton<String>(
value: leaveType,
icon: const Icon(
Icons.keyboard_arrow_down_rounded,
color: Colors.black,
size: 28,
),
style: const TextStyle(
color: Colors.black,
fontSize: 17,
),
isExpanded: true,
onChanged: (value) {
setState(() {
leaveType = value!;
// Set toggle based on selected value
isTimedLeave = value == "أجازة زمنية";
});
},
items: [
DropdownMenuItem(
value: "إجازة مرضية ",
child: Directionality(
textDirection: TextDirection.rtl,
child: Align(
alignment: Alignment.centerRight,
child: Text("إجازة مرضية "),
),
),
),
DropdownMenuItem(
value: "إجازة مدفوعة",
child: Directionality(
textDirection: TextDirection.rtl,
child: Align(
alignment: Alignment.centerRight,
child: Text("إجازة مدفوعة"),
),
),
),
DropdownMenuItem(
value: "إجازة غير مدفوعة",
child: Directionality(
textDirection: TextDirection.rtl,
child: Align(
alignment: Alignment.centerRight,
child: Text("إجازة غير مدفوعة"),
),
),
),
DropdownMenuItem(
value: "أجازة زمنية",
child: Directionality(
textDirection: TextDirection.rtl,
child: Align(
alignment: Alignment.centerRight,
child: Text("أجازة زمنية"),
),
),
),
],
),
),
),
),
),
),
const SizedBox(height: 25),
//=============================
// PERFECT CUSTOM TOGGLE (NEW)
//=============================
GestureDetector(
onTap: () {
setState(() {
isTimedLeave = !isTimedLeave;
// Set leave type to "أجازة زمنية" when toggle is ON
if (isTimedLeave) {
leaveType = "أجازة زمنية";
}
});
},
child: Row(
children: [
// ---------- TOGGLE ----------
AnimatedContainer(
duration: const Duration(milliseconds: 250),
width: 75,
height: 30,
padding: const EdgeInsets.symmetric(
horizontal: 4,
),
decoration: BoxDecoration(
color:
isTimedLeave
? const Color(
0xFF0A6B4A,
) // ON green track
: const Color(
0xFF9E9E9E,
), // OFF grey track
borderRadius: BorderRadius.circular(40),
),
child: Align(
alignment:
isTimedLeave
? Alignment.centerRight
: Alignment.centerLeft,
child: AnimatedContainer(
duration: const Duration(milliseconds: 250),
width: 30,
height: 30,
decoration: BoxDecoration(
color:
isTimedLeave
? const Color(0xFF12BE85) // ON knob
: Colors.white, // OFF knob
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: const Color(0x2D000000),
blurRadius: 6,
offset: const Offset(0, 2),
),
],
),
),
),
),
const SizedBox(width: 14),
// ---------- Dot (ALWAYS visible) ----------
Container(
width: 10,
height: 10,
decoration: const BoxDecoration(
color: Color(0xFF32C59A),
shape: BoxShape.circle,
),
),
const SizedBox(width: 6),
// ---------- Line (ALWAYS visible) ----------
Expanded(
child: Container(
height: 2,
color: const Color(0xFF32C59A),
),
),
const SizedBox(width: 12),
// ---------- Label ----------
const Text(
"إجازة زمنية",
style: TextStyle(
color: Colors.white,
fontSize: 19,
fontWeight: FontWeight.w600,
),
),
],
),
),
const SizedBox(height: 20),
// =============================
// DATE PICKER BOX
// =============================
Container(
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: const Color(0xFFF4F4F4),
borderRadius: BorderRadius.circular(16),
boxShadow: const [
BoxShadow(
color: Color(0x33000000),
blurRadius: 10,
offset: Offset(0, 4),
),
],
),
child: Column(
children: [
Row(
mainAxisAlignment:
MainAxisAlignment.end, // ALIGN RIGHT
children: [
// TEXT aligned right
const Text(
"فترة الإجازة",
style: TextStyle(
color: Colors.black,
fontSize: 18,
fontWeight: FontWeight.bold,
),
),
const SizedBox(width: 8),
// 🟢 YOUR CUSTOM SVG ICON
SvgPicture.asset(
"assets/images/calendar.svg", // <-- replace with your icon filename
width: 24,
height: 24,
color: Color(
0xFF007C46,
), // Optional: match your green
),
],
),
const SizedBox(height: 15),
// From date row
_dateRow(
label: "من",
date: fromDate!,
time: fromTime!,
onDateTap:
isTimedLeave ? null : () => pickDate(true),
onTimeTap: () => pickTime(true),
),
const SizedBox(height: 15),
// To date row
_dateRow(
label: "الى",
date: toDate!,
time: toTime!,
onDateTap:
isTimedLeave ? null : () => pickDate(false),
onTimeTap: () => pickTime(false),
),
],
),
),
const SizedBox(height: 10),
// =============================
// REASON TEXTFIELD (Two Containers)
// =============================
Align(
alignment: Alignment.centerRight,
child: Directionality(
textDirection: TextDirection.rtl,
child: const Text(
"السبب",
style: TextStyle(
color: Colors.white,
fontSize: 18,
fontWeight: FontWeight.w600,
),
),
),
),
// OUTER BORDER CONTAINER
Container(
padding: const EdgeInsets.all(
12,
), // border thickness space
decoration: BoxDecoration(
border: Border.all(
color: Color(0xFF00FFAA), // green border
width: 0.5,
),
borderRadius: BorderRadius.circular(14),
),
// INNER TEXTFIELD CONTAINER
child: Container(
height: 70,
padding: const EdgeInsets.symmetric(
horizontal: 14,
vertical: 10,
),
decoration: BoxDecoration(
color: const Color(0xFFEAEAEA),
borderRadius: BorderRadius.circular(12),
),
// Added Directionality to fix text direction
child: Directionality(
textDirection: TextDirection.rtl,
child: TextField(
controller: reasonController,
maxLines: 5,
textAlign:
TextAlign
.right, // Added this to align text to the right
decoration: const InputDecoration(
border: InputBorder.none,
hintText:
"اكتب السبب", // Added placeholder text
hintStyle: TextStyle(color: Colors.grey),
),
),
),
),
),
const SizedBox(height: 20),
// CONFIRM BUTTON
Center(
child: OnboardingButton(
text: "تأكيد الطلب",
backgroundColor: const Color(0xFFD1FEF0),
textColor: Colors.black, // Changed to black
onPressed: _saveLeaveRequest, // Call the save method
),
),
],
),
),
),
),
],
),
),
),
);
}
// ===============================================================
// CUSTOM DATE ROW WIDGET
// ===============================================================
Widget _dateRow({
required String label,
required DateTime date,
required TimeOfDay time,
required VoidCallback? onDateTap,
required VoidCallback onTimeTap,
}) {
bool dateDisabled = onDateTap == null;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 12),
height: 55,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(12),
),
child: Row(
children: [
// -----------------------
// DATE PART (can be disabled)
// -----------------------
Opacity(
opacity: dateDisabled ? 0.45 : 1,
child: IgnorePointer(
ignoring: dateDisabled,
child: GestureDetector(
onTap: onDateTap,
child: Row(
children: [
const Icon(Icons.arrow_drop_down),
const SizedBox(width: 4),
Text(
"${date.year}-${date.month}-${date.day}",
style: const TextStyle(fontSize: 16),
),
const SizedBox(width: 10),
Text(
_weekday(date.weekday),
style: const TextStyle(fontSize: 16),
),
],
),
),
),
),
const Spacer(),
// -----------------------
// TIME PART (always active)
// -----------------------
GestureDetector(
onTap: onTimeTap,
child: Text(
"${time.hour}:${time.minute.toString().padLeft(2, '0')}",
style: const TextStyle(fontSize: 16, fontWeight: FontWeight.w600),
),
),
const SizedBox(width: 10),
Text(
label,
style: const TextStyle(color: Colors.black, fontSize: 15),
),
],
),
);
}
String _weekday(int day) {
switch (day) {
case 1:
return "الإثنين";
case 2:
return "الثلاثاء";
case 3:
return "الأربعاء";
case 4:
return "الخميس";
case 5:
return "الجمعة";
case 6:
return "السبت";
case 7:
return "الأحد";
default:
return "";
}
}
}