chore: استيراد أولي من سيرو (ecfe7568) — بلا أي تعديل

نسخة كاملة من مستودع سيرو عند ecfe7568 لتكون أساس تطبيق «انطلق».
نُسخ المتعقَّب في git فقط (12,509 ملفاً / 302 م.ب) بـ git archive، لا
`cp -r` — فاستُثنيت تلقائياً مخلفات البناء (build · node_modules ·
.dart_tool · .gradle · Pods ≈ 10.7 غ.ب) وكل ما يستثنيه .gitignore.

هذا الكوميت **بلا أي تعديل عمداً** حتى يكون كل ما يليه فرقاً مقروءاً
مقابل سيرو الأصلي. سيرو نفسه لم يُمسّ.

⚠️ لا يبني بعد: `.env` و`lib/env/env.g.dart` غير متعقَّبين في سيرو (وهذا
صحيح — أسرار لكل مستأجر). كل تطبيق فلاتر هنا يحتاج .env خاصاً بانطلق ثم
توليد env.g.dart عبر build_runner. لا تُنسخ أسرار سيرو.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Hamza-Ayed
2026-07-27 05:10:29 +03:00
co-authored by Claude Opus 5
commit 92dc6b3641
3654 changed files with 896478 additions and 0 deletions
@@ -0,0 +1,63 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
class MyCircleContainer extends StatelessWidget {
final Widget child;
final Color backgroundColor;
final Color borderColor;
MyCircleContainer({
super.key,
required this.child,
this.backgroundColor = AppColor.secondaryColor,
this.borderColor = AppColor.accentColor,
});
final controller = Get.put(CircleController());
@override
Widget build(BuildContext context) {
return GetBuilder<CircleController>(
builder: ((controller) => GestureDetector(
onTap: () {
controller.changeColor();
},
child: AnimatedContainer(
onEnd: () {
controller.onEnd();
},
duration: const Duration(milliseconds: 300),
width: controller.size,
height: controller.size,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: controller.backgroundColor,
border: Border.all(
color: borderColor,
width: 1,
),
),
child: Center(child: child),
),
)));
}
}
class CircleController extends GetxController {
Color backgroundColor = AppColor.secondaryColor;
double size = 40;
void changeColor() {
backgroundColor = backgroundColor == AppColor.secondaryColor
? AppColor.accentColor
: AppColor.secondaryColor;
size = 60;
update();
}
void onEnd() {
size = 40;
update();
}
}
@@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
class MyElevatedButton extends StatelessWidget {
final String title;
final VoidCallback onPressed;
final Color? kolor;
final IconData? icon;
const MyElevatedButton({
super.key,
required this.title,
required this.onPressed,
this.kolor,
this.icon,
});
@override
Widget build(BuildContext context) {
return Container(
width: double.infinity,
height: 56,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(16),
boxShadow: [
BoxShadow(
color: (kolor ?? AppColor.accent).withOpacity(0.3),
blurRadius: 12,
offset: const Offset(0, 4),
),
],
),
child: ElevatedButton(
style: ElevatedButton.styleFrom(
backgroundColor: kolor ?? AppColor.accent,
foregroundColor: Colors.white,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
),
elevation: 0,
),
onPressed: () {
HapticFeedback.lightImpact();
onPressed();
},
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
if (icon != null) ...[
Icon(icon, size: 20),
const SizedBox(width: 8),
],
Text(
title,
style: AppStyle.title.copyWith(color: Colors.white),
),
],
),
),
);
}
}
@@ -0,0 +1,94 @@
import 'dart:ui';
import 'package:flutter/material.dart';
class GlassContainer extends StatelessWidget {
final Widget child;
final double? width;
final double? height;
final EdgeInsetsGeometry? padding;
final EdgeInsetsGeometry? margin;
final double borderRadius;
final List<Color>? gradientColors;
final double blur;
final double opacity;
final bool showBorder;
final Color? borderColor;
const GlassContainer({
super.key,
required this.child,
this.width,
this.height,
this.padding,
this.margin,
this.borderRadius = 16.0,
this.gradientColors,
this.blur = 20.0,
this.opacity = 0.1,
this.showBorder = true,
this.borderColor,
});
@override
Widget build(BuildContext context) {
final isDark = Theme.of(context).brightness == Brightness.dark;
final cs = Theme.of(context).colorScheme;
final defaultGradient = isDark
? [
Colors.white.withValues(alpha: opacity),
Colors.white.withValues(alpha: opacity * 0.5),
]
: [
Colors.white.withValues(alpha: 0.7),
Colors.white.withValues(alpha: 0.4),
];
final effectiveBorderColor = borderColor ??
(isDark
? Colors.white.withValues(alpha: 0.15)
: Colors.white.withValues(alpha: 0.5));
final shadowColor = isDark
? Colors.black.withValues(alpha: 0.3)
: cs.shadow.withValues(alpha: 0.08);
return Container(
width: width,
height: height,
margin: margin,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius),
boxShadow: [
BoxShadow(
color: shadowColor,
blurRadius: 24,
spreadRadius: 0,
offset: const Offset(0, 8),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(borderRadius),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: blur, sigmaY: blur),
child: Container(
padding: padding,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(borderRadius),
border: showBorder
? Border.all(color: effectiveBorderColor, width: 1)
: null,
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: gradientColors ?? defaultGradient,
),
),
child: child,
),
),
),
);
}
}
@@ -0,0 +1,66 @@
import 'package:flutter/material.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
class IconWidgetMenu extends StatelessWidget {
const IconWidgetMenu({
super.key,
required this.onpressed,
required this.icon,
required this.title,
});
final VoidCallback onpressed;
final IconData icon;
final String title;
@override
Widget build(BuildContext context) {
return InkWell(
onTap: onpressed,
child: Padding(
padding: const EdgeInsets.only(top: 25),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
width: 50,
decoration: const BoxDecoration(
color: AppColor.secondaryColor,
shape: BoxShape.circle,
boxShadow: [
BoxShadow(
color: AppColor.secondaryColor,
offset: Offset(-2, -2),
blurRadius: 0,
spreadRadius: 0,
blurStyle: BlurStyle.outer,
),
BoxShadow(
color: AppColor.accentColor,
offset: Offset(3, 3),
blurRadius: 0,
spreadRadius: 0,
blurStyle: BlurStyle.outer,
),
],
),
child: Center(
child: Icon(
icon,
size: 30,
color: AppColor.primaryColor,
),
),
),
Text(
title,
style: AppStyle.subtitle,
)
],
),
),
);
}
}
@@ -0,0 +1,60 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
class MyScafolld extends StatelessWidget {
const MyScafolld({
super.key,
required this.title,
required this.body,
this.action,
required this.isleading,
});
final String title;
final List<Widget> body;
final Widget? action;
final bool isleading;
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: AppColor.bg,
appBar: AppBar(
backgroundColor: AppColor.bg,
elevation: 0,
leadingWidth: 70,
leading: isleading
? Center(
child: Container(
margin: const EdgeInsets.only(right: 16),
decoration: BoxDecoration(
color: AppColor.surfaceElevated,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: AppColor.divider),
),
child: IconButton(
onPressed: () => Get.back(),
icon: const Icon(
Icons.arrow_back_ios_new_rounded,
color: AppColor.textPrimary,
size: 18,
),
),
),
)
: null,
actions: [
if (action != null) action!,
const SizedBox(width: 16),
],
title: Text(
title,
style: AppStyle.headTitle,
),
),
body: SafeArea(child: Stack(children: body)));
}
}
@@ -0,0 +1,76 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
class MyTextForm extends StatelessWidget {
const MyTextForm({
super.key,
required this.controller,
required this.label,
required this.hint,
required this.type,
this.prefixIcon,
});
final TextEditingController controller;
final String label, hint;
final TextInputType type;
final IconData? prefixIcon;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 16),
child: TextFormField(
keyboardType: type,
style: AppStyle.body,
cursorColor: AppColor.accent,
controller: controller,
decoration: InputDecoration(
filled: true,
fillColor: AppColor.surface,
prefixIcon: prefixIcon != null
? Icon(prefixIcon, color: AppColor.textSecondary, size: 20)
: null,
contentPadding: const EdgeInsets.symmetric(horizontal: 20, vertical: 18),
enabledBorder: OutlineInputBorder(
borderSide: const BorderSide(color: AppColor.divider),
borderRadius: BorderRadius.circular(16),
),
focusedBorder: OutlineInputBorder(
borderSide: const BorderSide(color: AppColor.accent, width: 2),
borderRadius: BorderRadius.circular(16),
),
errorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: AppColor.danger),
borderRadius: BorderRadius.circular(16),
),
focusedErrorBorder: OutlineInputBorder(
borderSide: const BorderSide(color: AppColor.danger, width: 2),
borderRadius: BorderRadius.circular(16),
),
labelText: label.tr,
labelStyle: AppStyle.subtitle,
hintText: hint.tr,
hintStyle: AppStyle.caption,
),
validator: (value) {
if (value == null || value.isEmpty) {
return '${'Please enter'.tr} ${label.tr}';
}
if (type == TextInputType.emailAddress) {
if (!GetUtils.isEmail(value)) {
return 'Please enter a valid email.'.tr;
}
}
return null;
},
),
);
}
}
@@ -0,0 +1,37 @@
import 'package:flutter/material.dart';
class MyCircularProgressIndicator extends StatelessWidget {
final Color backgroundColor;
const MyCircularProgressIndicator({
super.key,
this.backgroundColor = Colors.transparent,
});
@override
Widget build(BuildContext context) {
return Center(
child: Container(
width: 110,
height: 110,
decoration: BoxDecoration(
color: backgroundColor,
shape: BoxShape.circle,
),
child: Stack(
children: [
const Center(child: CircularProgressIndicator()),
Column(
children: [
Align(
alignment: Alignment.center,
child: Image.asset('assets/images/logo.png'),
),
],
),
],
),
),
);
}
}
+182
View File
@@ -0,0 +1,182 @@
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
import '../../constant/colors.dart';
import '../../constant/style.dart';
class DialogConfig {
static const Duration animationDuration = Duration(milliseconds: 200);
static const double blurStrength = 8.0;
static const double cornerRadius = 14.0;
static final BoxDecoration decoration = BoxDecoration(
borderRadius: BorderRadius.circular(cornerRadius),
boxShadow: [
BoxShadow(
color: Colors.black.withAlpha(38), // 0.15 opacity
blurRadius: 16,
offset: const Offset(0, 8),
),
],
);
}
class MyDialog extends GetxController {
void getDialog(String title, String? midTitle, VoidCallback onPressed) {
HapticFeedback.mediumImpact();
Get.dialog(
TweenAnimationBuilder<double>(
duration: DialogConfig.animationDuration,
tween: Tween(begin: 0.0, end: 1.0),
builder: (context, value, child) {
return Transform.scale(
scale: 0.95 + (0.05 * value),
child: Opacity(opacity: value, child: child),
);
},
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: DialogConfig.blurStrength,
sigmaY: DialogConfig.blurStrength,
),
child: AlertDialog(
backgroundColor: AppColor.surfaceElevated,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
title: Text(
title,
textAlign: TextAlign.center,
style: AppStyle.headTitle,
),
content: midTitle != null
? Text(
midTitle,
textAlign: TextAlign.center,
style: AppStyle.subtitle,
)
: null,
actionsPadding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
actions: [
Row(
children: [
Expanded(
child: TextButton(
onPressed: () => Get.back(),
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: const BorderSide(color: AppColor.divider),
),
),
child: Text('Cancel'.tr, style: AppStyle.subtitle),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: () {
HapticFeedback.mediumImpact();
onPressed();
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColor.accent,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
),
child: Text('OK'.tr, style: AppStyle.title.copyWith(color: Colors.white)),
),
),
],
),
],
),
),
),
barrierColor: Colors.black54,
);
}
}
class MyDialogContent extends GetxController {
void getDialog(String title, Widget? content, VoidCallback onPressed) {
HapticFeedback.mediumImpact();
Get.dialog(
TweenAnimationBuilder<double>(
duration: DialogConfig.animationDuration,
tween: Tween(begin: 0.0, end: 1.0),
builder: (context, value, child) {
return Transform.scale(
scale: 0.95 + (0.05 * value),
child: Opacity(opacity: value, child: child),
);
},
child: BackdropFilter(
filter: ImageFilter.blur(
sigmaX: DialogConfig.blurStrength,
sigmaY: DialogConfig.blurStrength,
),
child: AlertDialog(
backgroundColor: AppColor.surfaceElevated,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(24)),
title: Text(
title,
textAlign: TextAlign.center,
style: AppStyle.headTitle,
),
content: content != null
? SingleChildScrollView(child: content)
: null,
actionsPadding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
actions: [
Row(
children: [
Expanded(
child: TextButton(
onPressed: () => Get.back(),
style: TextButton.styleFrom(
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: const BorderSide(color: AppColor.divider),
),
),
child: Text('Cancel'.tr, style: AppStyle.subtitle),
),
),
const SizedBox(width: 12),
Expanded(
child: ElevatedButton(
onPressed: () {
HapticFeedback.mediumImpact();
onPressed();
},
style: ElevatedButton.styleFrom(
backgroundColor: AppColor.accent,
foregroundColor: Colors.white,
padding: const EdgeInsets.symmetric(vertical: 16),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
elevation: 0,
),
child: Text('OK'.tr, style: AppStyle.title.copyWith(color: Colors.white)),
),
),
],
),
],
),
),
),
barrierColor: Colors.black54,
);
}
}
@@ -0,0 +1,33 @@
import 'package:flutter/material.dart';
class ResponsiveLayout extends StatelessWidget {
final Widget mobile;
final Widget desktop;
const ResponsiveLayout({
Key? key,
required this.mobile,
required this.desktop,
}) : super(key: key);
static bool isDesktop(BuildContext context) {
return MediaQuery.of(context).size.width >= 900; // standard desktop breakpoint
}
static bool isMobile(BuildContext context) {
return MediaQuery.of(context).size.width < 900;
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
builder: (context, constraints) {
if (constraints.maxWidth >= 900) {
return desktop;
} else {
return mobile;
}
},
);
}
}
+262
View File
@@ -0,0 +1,262 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get/get.dart';
enum _SnackVariant { success, error, info, warning }
extension _VariantProps on _SnackVariant {
Color get baseColor => switch (this) {
_SnackVariant.success => const Color(0xFF1A9E5C),
_SnackVariant.error => const Color(0xFFD93025),
_SnackVariant.info => const Color(0xFF1A73E8),
_SnackVariant.warning => const Color(0xFFF29900),
};
Color get surfaceColor => switch (this) {
_SnackVariant.success => const Color(0xFFF0FBF5),
_SnackVariant.error => const Color(0xFFFEF2F1),
_SnackVariant.info => const Color(0xFFF0F6FF),
_SnackVariant.warning => const Color(0xFFFFF8E6),
};
IconData get icon => switch (this) {
_SnackVariant.success => Icons.check_circle_rounded,
_SnackVariant.error => Icons.error_rounded,
_SnackVariant.info => Icons.info_rounded,
_SnackVariant.warning => Icons.warning_amber_rounded,
};
String get label => switch (this) {
_SnackVariant.success => 'Success',
_SnackVariant.error => 'Error',
_SnackVariant.info => 'Info',
_SnackVariant.warning => 'Warning',
};
}
class _SnackContent extends StatefulWidget {
final String message;
final _SnackVariant variant;
const _SnackContent({required this.message, required this.variant});
@override
State<_SnackContent> createState() => _SnackContentState();
}
class _SnackContentState extends State<_SnackContent>
with TickerProviderStateMixin {
late final AnimationController _ctrl;
late final AnimationController _scaleCtrl;
late final Animation<double> _scaleAnim;
late final Animation<double> _progressAnim;
static const Duration _displayDuration = Duration(seconds: 4);
@override
void initState() {
super.initState();
_ctrl = AnimationController(vsync: this, duration: _displayDuration);
_scaleCtrl = AnimationController(
vsync: this,
duration: const Duration(milliseconds: 500),
);
_scaleAnim = CurvedAnimation(
parent: _scaleCtrl,
curve: Curves.elasticOut,
);
_progressAnim = Tween<double>(begin: 1.0, end: 0.0).animate(
CurvedAnimation(parent: _ctrl, curve: Curves.linear),
);
_scaleCtrl.forward();
_ctrl.forward();
}
@override
void dispose() {
_ctrl.dispose();
_scaleCtrl.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final v = widget.variant;
final accent = v.baseColor;
final surface = v.surfaceColor;
return Container(
margin: const EdgeInsets.symmetric(horizontal: 14, vertical: 8),
decoration: BoxDecoration(
color: surface,
borderRadius: BorderRadius.circular(18),
border: Border.all(color: accent.withAlpha(46), width: 1.2),
boxShadow: [
BoxShadow(
color: accent.withAlpha(31),
blurRadius: 20,
spreadRadius: -2,
offset: const Offset(0, 6),
),
BoxShadow(
color: Colors.black.withAlpha(15),
blurRadius: 10,
offset: const Offset(0, 2),
),
],
),
child: ClipRRect(
borderRadius: BorderRadius.circular(18),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Padding(
padding: const EdgeInsets.fromLTRB(14, 14, 10, 12),
child: Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
ScaleTransition(
scale: _scaleAnim,
child: Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: accent.withAlpha(31),
shape: BoxShape.circle,
),
child: Icon(v.icon, color: accent, size: 22),
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
v.label.tr,
style: TextStyle(
color: accent,
fontSize: 13,
fontWeight: FontWeight.w700,
letterSpacing: 0.2,
),
),
const SizedBox(height: 3),
Text(
widget.message,
style: const TextStyle(
color: Color(0xFF424242),
fontSize: 13.5,
height: 1.4,
fontWeight: FontWeight.w400,
),
maxLines: 2,
overflow: TextOverflow.ellipsis,
),
],
),
),
GestureDetector(
onTap: () {
HapticFeedback.lightImpact();
_closeSnackbar(context);
},
child: Container(
width: 30,
height: 30,
margin: const EdgeInsets.only(left: 6),
decoration: BoxDecoration(
color: Colors.grey.withAlpha(25),
shape: BoxShape.circle,
),
child: Icon(
Icons.close_rounded,
size: 16,
color: Colors.grey[500],
),
),
),
],
),
),
AnimatedBuilder(
animation: _progressAnim,
builder: (_, __) => Stack(
children: [
Container(height: 3, color: accent.withAlpha(20)),
FractionallySizedBox(
widthFactor: _progressAnim.value,
child: Container(
height: 3,
decoration: BoxDecoration(
color: accent.withAlpha(115),
borderRadius: const BorderRadius.only(
topRight: Radius.circular(4),
bottomRight: Radius.circular(4),
),
),
),
),
],
),
),
],
),
),
);
}
void _closeSnackbar(BuildContext context) {
ScaffoldMessenger.maybeOf(context)?.hideCurrentSnackBar();
}
}
int _retryCount = 0;
void _show(_SnackVariant variant, String message) {
if (Get.context == null) {
if (_retryCount < 3) {
_retryCount++;
WidgetsBinding.instance.addPostFrameCallback((_) => _show(variant, message));
}
return;
}
_retryCount = 0;
final context = Get.context;
if (context == null) return;
final messenger = ScaffoldMessenger.maybeOf(context);
if (messenger == null) return;
messenger.clearSnackBars();
switch (variant) {
case _SnackVariant.error:
case _SnackVariant.warning:
HapticFeedback.mediumImpact();
case _SnackVariant.success:
HapticFeedback.lightImpact();
case _SnackVariant.info:
HapticFeedback.selectionClick();
}
messenger.showSnackBar(
SnackBar(
content: _SnackContent(message: message, variant: variant),
backgroundColor: Colors.transparent,
elevation: 0,
margin: EdgeInsets.zero,
padding: EdgeInsets.zero,
behavior: SnackBarBehavior.floating,
duration: const Duration(seconds: 4),
dismissDirection: DismissDirection.up,
),
);
}
void mySnackbarSuccess(String message) => _show(_SnackVariant.success, message);
void mySnackbarError(String message) => _show(_SnackVariant.error, message);
void mySnackbarInfo(String message) => _show(_SnackVariant.info, message);
void mySnackbarWarning(String message) => _show(_SnackVariant.warning, message);
@@ -0,0 +1,483 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
class UnifiedAppBar extends StatelessWidget implements PreferredSizeWidget {
final String title;
final Widget? leading;
final List<Widget>? actions;
final Color? backgroundColor;
final Color? foregroundColor;
final double elevation;
final bool centerTitle;
final PreferredSizeWidget? bottom;
final double toolbarHeight;
const UnifiedAppBar({
super.key,
required this.title,
this.leading,
this.actions,
this.backgroundColor,
this.foregroundColor,
this.elevation = 0,
this.centerTitle = false,
this.bottom,
this.toolbarHeight = kToolbarHeight + 34,
});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
final bgColor = backgroundColor ?? cs.surface;
return Container(
height: toolbarHeight,
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
decoration: BoxDecoration(
color: bgColor,
border: Border(bottom: BorderSide(color: cs.outline, width: 0.5)),
),
child: SafeArea(
bottom: false,
child: Row(
children: [
leading ??
GestureDetector(
onTap: () => Get.back(),
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: cs.surfaceContainerHighest,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: cs.outline),
),
child: Icon(
Icons.arrow_back_ios_new_rounded,
color: cs.onSurfaceVariant,
size: 16,
),
),
),
const SizedBox(width: 12),
Expanded(
child: Text(
title,
style: TextStyle(
color: foregroundColor ?? cs.onSurface,
fontSize: 18,
fontWeight: FontWeight.w700,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
if (actions != null) ...actions!,
],
),
),
);
}
@override
Size get preferredSize => Size.fromHeight(toolbarHeight);
}
class UnifiedAppBarWithTabs extends StatelessWidget implements PreferredSizeWidget {
final String title;
final List<Widget> tabs;
final TabController? tabController;
final Widget? leading;
final List<Widget>? actions;
final Color? backgroundColor;
final Color? foregroundColor;
final double elevation;
final EdgeInsetsGeometry? tabPadding;
const UnifiedAppBarWithTabs({
super.key,
required this.title,
required this.tabs,
this.tabController,
this.leading,
this.actions,
this.backgroundColor,
this.foregroundColor,
this.elevation = 0,
this.tabPadding,
});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
final bgColor = backgroundColor ?? cs.surface;
return Container(
height: kToolbarHeight + 34 + 48,
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
decoration: BoxDecoration(
color: bgColor,
border: Border(bottom: BorderSide(color: cs.outline, width: 0.5)),
),
child: SafeArea(
bottom: false,
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
leading ??
GestureDetector(
onTap: () => Get.back(),
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: cs.surfaceContainerHighest,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: cs.outline),
),
child: Icon(
Icons.arrow_back_ios_new_rounded,
color: cs.onSurfaceVariant,
size: 16,
),
),
),
const SizedBox(width: 12),
Expanded(
child: Text(
title,
style: TextStyle(
color: foregroundColor ?? cs.onSurface,
fontSize: 18,
fontWeight: FontWeight.w700,
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
),
),
if (actions != null) ...actions!,
],
),
const SizedBox(height: 8),
Container(
padding: tabPadding ?? const EdgeInsets.all(4),
decoration: BoxDecoration(
color: cs.surfaceContainerHighest,
borderRadius: BorderRadius.circular(12),
border: Border.all(color: cs.outline),
),
child: TabBar(
controller: tabController,
isScrollable: true,
indicator: BoxDecoration(
color: cs.primary.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(8),
border: Border.all(color: cs.primary.withValues(alpha: 0.3)),
),
indicatorSize: TabBarIndicatorSize.tab,
dividerColor: Colors.transparent,
labelColor: cs.primary,
unselectedLabelColor: cs.onSurfaceVariant,
labelStyle: const TextStyle(fontWeight: FontWeight.w700, fontSize: 13),
unselectedLabelStyle: const TextStyle(fontWeight: FontWeight.w500, fontSize: 13),
tabs: tabs,
),
),
],
),
),
);
}
@override
Size get preferredSize => const Size.fromHeight(kToolbarHeight + 34 + 48);
}
class UnifiedScaffold extends StatelessWidget {
final String title;
final Widget body;
final List<Widget>? actions;
final Widget? leading;
final Color? backgroundColor;
final bool extendBody;
final FloatingActionButton? floatingActionButton;
final FloatingActionButtonLocation? floatingActionButtonLocation;
final PreferredSizeWidget? bottomNavigationBar;
const UnifiedScaffold({
super.key,
required this.title,
required this.body,
this.actions,
this.leading,
this.backgroundColor,
this.extendBody = false,
this.floatingActionButton,
this.floatingActionButtonLocation,
this.bottomNavigationBar,
});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return Scaffold(
backgroundColor: backgroundColor ?? cs.surface,
extendBody: extendBody,
floatingActionButton: floatingActionButton,
floatingActionButtonLocation: floatingActionButtonLocation,
bottomNavigationBar: bottomNavigationBar,
appBar: UnifiedAppBar(
title: title,
actions: actions,
leading: leading,
backgroundColor: backgroundColor,
),
body: body,
);
}
}
class UnifiedLoadingState extends StatelessWidget {
final String? message;
final Color? color;
const UnifiedLoadingState({super.key, this.message, this.color});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
width: 40,
height: 40,
child: CircularProgressIndicator(
color: color ?? cs.primary,
strokeWidth: 2,
backgroundColor: (color ?? cs.primary).withValues(alpha: 0.1),
),
),
const SizedBox(height: 16),
Text(
message ?? 'جاري التحميل...',
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 13),
),
],
),
);
}
}
class UnifiedEmptyState extends StatelessWidget {
final IconData icon;
final String title;
final String? subtitle;
final Widget? action;
const UnifiedEmptyState({
super.key,
required this.icon,
required this.title,
this.subtitle,
this.action,
});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return Center(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: cs.surfaceContainerHighest,
shape: BoxShape.circle,
),
child: Icon(icon, size: 48, color: cs.onSurfaceVariant),
),
const SizedBox(height: 16),
Text(
title,
style: TextStyle(color: cs.onSurface, fontSize: 16, fontWeight: FontWeight.w600),
textAlign: TextAlign.center,
),
if (subtitle != null) ...[
const SizedBox(height: 8),
Text(
subtitle!,
style: TextStyle(color: cs.onSurfaceVariant, fontSize: 13),
textAlign: TextAlign.center,
),
],
if (action != null) ...[
const SizedBox(height: 20),
action!,
],
],
),
),
);
}
}
class UnifiedStatCard extends StatelessWidget {
final String label;
final String value;
final IconData icon;
final Color color;
final VoidCallback? onTap;
final String? subtitle;
const UnifiedStatCard({
super.key,
required this.label,
required this.value,
required this.icon,
required this.color,
this.onTap,
this.subtitle,
});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(16),
splashColor: color.withValues(alpha: 0.1),
highlightColor: color.withValues(alpha: 0.05),
child: Container(
width: 155,
padding: const EdgeInsets.all(16),
decoration: BoxDecoration(
color: cs.surfaceContainerHighest,
borderRadius: BorderRadius.circular(16),
border: Border.all(color: cs.outline),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Container(
padding: const EdgeInsets.all(7),
decoration: BoxDecoration(
color: color.withValues(alpha: 0.12),
borderRadius: BorderRadius.circular(9),
),
child: Icon(icon, color: color, size: 16),
),
Container(
width: 6,
height: 6,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: color.withValues(alpha: 0.6),
),
),
],
),
const Spacer(),
Text(
value,
style: TextStyle(
color: cs.onSurface,
fontSize: 20,
fontWeight: FontWeight.w700,
height: 1.1,
),
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 3),
Text(
label,
style: TextStyle(
color: cs.onSurfaceVariant,
fontSize: 10,
fontWeight: FontWeight.w500,
),
overflow: TextOverflow.ellipsis,
),
if (subtitle != null) ...[
const SizedBox(height: 2),
Text(
subtitle!,
style: TextStyle(
color: cs.onSurfaceVariant,
fontSize: 9,
fontWeight: FontWeight.w400,
),
overflow: TextOverflow.ellipsis,
),
],
],
),
),
),
);
}
}
class UnifiedSectionHeader extends StatelessWidget {
final String title;
final IconData? icon;
final Color? iconColor;
final Widget? trailing;
const UnifiedSectionHeader({
super.key,
required this.title,
this.icon,
this.iconColor,
this.trailing,
});
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return Padding(
padding: const EdgeInsets.fromLTRB(20, 8, 20, 10),
child: Row(
children: [
Container(
width: 3,
height: 14,
decoration: BoxDecoration(
color: iconColor ?? cs.primary,
borderRadius: BorderRadius.circular(2),
),
),
const SizedBox(width: 8),
if (icon != null) ...[
Icon(icon!, size: 16, color: iconColor ?? cs.primary),
const SizedBox(width: 6),
],
Text(
title,
style: TextStyle(
color: cs.onSurfaceVariant,
fontSize: 11,
fontWeight: FontWeight.w600,
letterSpacing: 1.2,
),
),
if (trailing != null) ...[
const Spacer(),
trailing!,
],
],
),
);
}
}
@@ -0,0 +1,530 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:siro_admin/main.dart';
import 'package:siro_admin/constant/box_name.dart';
import 'package:siro_admin/views/admin/captain/captain.dart';
import 'package:siro_admin/views/admin/passenger/passenger.dart';
import 'package:siro_admin/views/admin/drivers/driver_tracker_screen.dart';
import 'package:siro_admin/views/transit/org_list_page.dart';
import 'package:siro_admin/views/admin/static/static.dart';
import 'package:siro_admin/controller/admin/static_controller.dart';
import 'package:siro_admin/views/admin/drivers/monitor_ride.dart';
import 'package:siro_admin/views/admin/rides/ride_lookup_page.dart';
import 'package:siro_admin/views/admin/packages.dart';
import 'package:siro_admin/views/admin/wallet/wallet.dart';
import 'package:siro_admin/views/admin/captain/syrian_driver_not_active.dart';
import 'package:siro_admin/views/admin/drivers/driver_gift_check_page.dart';
import 'package:siro_admin/views/admin/quality/blacklist_page.dart';
import 'package:siro_admin/views/admin/employee/employee_page.dart';
import 'package:siro_admin/views/admin/server/monitor_server_page.dart';
import 'package:siro_admin/views/admin/error/error/error_page.dart';
import 'package:siro_admin/views/invoice/invoice_list_page.dart';
import 'package:siro_admin/views/admin/staff/add_staff_page.dart';
import 'package:siro_admin/views/admin/staff/pending_admins_page.dart';
import 'package:siro_admin/views/admin/static/advanced_analytics_page.dart';
import 'package:siro_admin/views/admin/financial/financial_v2_page.dart';
import 'package:siro_admin/views/admin/security/audit_logs_page.dart';
import 'package:siro_admin/views/admin/analytics/live_analytics_page.dart';
class WebSidebar extends StatelessWidget {
final int selectedIndex;
final Function(int)? onItemSelected;
const WebSidebar({
Key? key,
this.selectedIndex = 0,
this.onItemSelected,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
final String myPhone = box.read(BoxName.adminPhone)?.toString() ?? '';
final String role = box.read('admin_role')?.toString() ?? 'admin';
final bool isSuperAdmin = (role == 'super_admin') ||
(myPhone == '201023248456' ||
myPhone == '963992952235' ||
myPhone == '962798583052');
return Container(
width: 270,
color: cs.surface,
child: Column(
children: [
_buildLogo(context),
Divider(color: cs.outline, height: 1),
Expanded(
child: ListView(
padding: const EdgeInsets.symmetric(vertical: 12),
children: [
_buildNavItem(
context,
title: 'اللوحة الرئيسية',
icon: Icons.dashboard_rounded,
index: 0,
onTap: () {
if (onItemSelected != null) onItemSelected!(0);
},
),
_buildSectionHeader(context, 'التحليلات والإحصائيات'),
_buildNavItem(
context,
title: 'التحليلات الحية',
icon: Icons.ssid_chart_rounded,
index: 101,
onTap: () => Get.to(() => const LiveAnalyticsPage()),
),
_buildNavItem(
context,
title: 'التحليلات المتقدمة',
icon: Icons.analytics_rounded,
index: 102,
onTap: () => Get.to(() => const AdvancedAnalyticsPage()),
),
_buildNavItem(
context,
title: 'إحصائيات النظام',
icon: Icons.bar_chart_rounded,
index: 7,
onTap: () async {
await Get.put(StaticController()).getAll();
Get.to(() => const StaticDash());
},
),
_buildSectionHeader(context, 'الكباتن والركاب'),
_buildNavItem(
context,
title: 'إدارة الركاب',
icon: Icons.people_outline_rounded,
index: 1,
onTap: () => Get.to(() => Passengrs()),
),
_buildNavItem(
context,
title: 'قائمة الكباتن',
icon: Icons.drive_eta_rounded,
index: 2,
onTap: () => Get.to(() => CaptainsPage()),
),
_buildNavItem(
context,
title: 'طلبات الكباتن المعلقة',
icon: Icons.person_add_disabled_rounded,
index: 103,
onTap: () => Get.to(() => DriversPendingPage()),
),
_buildNavItem(
context,
title: 'مراجعة الوثائق',
icon: Icons.assignment_ind_rounded,
index: 104,
onTap: () => Get.toNamed('/driver-docs'),
),
_buildNavItem(
context,
title: 'هدايا وعروض الكباتن',
icon: Icons.card_giftcard_rounded,
index: 105,
onTap: () => Get.to(() => const DriverGiftCheckPage()),
),
_buildNavItem(
context,
title: 'القائمة السوداء',
icon: Icons.block_rounded,
index: 106,
onTap: () => Get.to(() => const BlacklistPage()),
),
_buildSectionHeader(context, 'الرحلات والتتبع'),
_buildNavItem(
context,
title: 'شاشة الرحلات',
icon: Icons.map_rounded,
index: 5,
onTap: () => Get.to(() => RidesDashboardScreen()),
),
if (isSuperAdmin)
_buildNavItem(
context,
title: 'مراقبة الرحلات الحية',
icon: Icons.remove_red_eye_rounded,
index: 6,
onTap: () => Get.to(() => RideMonitorScreen()),
),
_buildNavItem(
context,
title: 'تتبع الكباتن (المراقب)',
icon: Icons.track_changes_rounded,
index: 3,
onTap: () => Get.to(() => SiroTrackerScreen()),
),
_buildSectionHeader(context, 'نظام مواصلاتي'),
_buildNavItem(
context,
title: 'إدارة المؤسسات والشركات',
icon: Icons.directions_bus_filled_rounded,
index: 4,
onTap: () => Get.to(() => const TransitOrgListPage()),
),
_buildSectionHeader(context, 'المالية والأسعار'),
_buildNavItem(
context,
title: 'التقرير المالي (V2)',
icon: Icons.account_balance_wallet_rounded,
index: 108,
onTap: () => Get.to(() => const FinancialV2Page()),
),
_buildNavItem(
context,
title: 'المحافظ المالية',
icon: Icons.account_balance_rounded,
index: 109,
onTap: () => Get.to(() => Wallet()),
),
_buildNavItem(
context,
title: 'الباقات والاشتراكات',
icon: Icons.card_membership_rounded,
index: 110,
onTap: () => Get.to(() => PackageUpdateScreen()),
),
_buildNavItem(
context,
title: 'الفواتير',
icon: Icons.receipt_long_rounded,
index: 111,
onTap: () => Get.to(() => const InvoiceListPage()),
),
_buildNavItem(
context,
title: 'تسعير الكازان',
icon: Icons.price_change_rounded,
index: 9,
onTap: () => Get.toNamed('/kazan'),
),
_buildNavItem(
context,
title: 'أكواد الخصم (Promo)',
icon: Icons.confirmation_number_rounded,
index: 8,
onTap: () => Get.toNamed('/promo'),
),
_buildSectionHeader(context, 'التسويق والدعم'),
_buildNavItem(
context,
title: 'حركات التسويق والـ AI',
icon: Icons.campaign_rounded,
index: 112,
onTap: () => Get.toNamed('/marketing'),
),
_buildNavItem(
context,
title: 'الخريطة الحرارية (Heatmap)',
icon: Icons.local_fire_department_rounded,
index: 113,
onTap: () => Get.toNamed('/heatmap'),
),
_buildNavItem(
context,
title: 'الذكاء الاجتماعي',
icon: Icons.psychology_rounded,
index: 114,
onTap: () => Get.toNamed('/social-intelligence'),
),
_buildNavItem(
context,
title: 'إدارة الشكاوى',
icon: Icons.report_problem_rounded,
index: 115,
onTap: () => Get.toNamed('/complaints'),
),
if (isSuperAdmin) ...[
_buildSectionHeader(context, 'إدارة النظام والأمان'),
_buildNavItem(
context,
title: 'مراقبة السيرفرات',
icon: Icons.dns_rounded,
index: 116,
onTap: () => Get.to(() => ServerMonitorPage()),
),
_buildNavItem(
context,
title: 'سجلات الأمان والعمليات',
icon: Icons.admin_panel_settings_outlined,
index: 117,
onTap: () => Get.to(() => const AuditLogsPage()),
),
_buildNavItem(
context,
title: 'فريق العمل والموظفين',
icon: Icons.badge_rounded,
index: 118,
onTap: () => Get.to(() => EmployeePage()),
),
_buildNavItem(
context,
title: 'إضافة مشرف جديد',
icon: Icons.person_add_rounded,
index: 119,
onTap: () => Get.to(() => const AddStaffPage(role: 'admin')),
),
_buildNavItem(
context,
title: 'طلبات المشرفين المعلقة',
icon: Icons.hourglass_top_rounded,
index: 120,
onTap: () => Get.to(() => const PendingAdminsPage()),
),
_buildNavItem(
context,
title: 'أخطاء النظام',
icon: Icons.bug_report_rounded,
index: 121,
onTap: () => Get.to(() => const ErrorListPage()),
),
],
],
),
),
Divider(color: cs.outline, height: 1),
_buildThemeToggle(context),
_buildLogoutBtn(context),
],
),
);
}
Widget _buildLogo(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return Container(
padding: const EdgeInsets.symmetric(vertical: 20, horizontal: 20),
child: Row(
children: [
Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
color: cs.primary.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12),
border: Border.all(color: cs.primary.withValues(alpha: 0.3)),
),
child: Icon(Icons.admin_panel_settings_rounded,
color: cs.primary, size: 28),
),
const SizedBox(width: 12),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'SIRO ADMIN',
style: TextStyle(
color: cs.onSurface,
fontWeight: FontWeight.bold,
fontSize: 16,
letterSpacing: 1.1,
),
),
const SizedBox(height: 2),
Text(
'Web Dashboard',
style: TextStyle(
color: cs.onSurfaceVariant,
fontSize: 11,
),
),
],
)
],
),
);
}
Widget _buildSectionHeader(BuildContext context, String title) {
final cs = Theme.of(context).colorScheme;
return Padding(
padding: const EdgeInsets.only(right: 20, left: 20, top: 18, bottom: 6),
child: Text(
title,
style: TextStyle(
color: cs.primary.withValues(alpha: 0.85),
fontSize: 11,
fontWeight: FontWeight.bold,
letterSpacing: 0.5,
),
),
);
}
Widget _buildNavItem(
BuildContext context, {
required String title,
required IconData icon,
required int index,
required VoidCallback onTap,
}) {
final cs = Theme.of(context).colorScheme;
final bool isSelected = selectedIndex == index;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 2),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: onTap,
borderRadius: BorderRadius.circular(10),
hoverColor: cs.primary.withValues(alpha: 0.08),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: isSelected
? cs.primary.withValues(alpha: 0.15)
: Colors.transparent,
borderRadius: BorderRadius.circular(10),
border: isSelected
? Border.all(color: cs.primary.withValues(alpha: 0.4))
: null,
),
child: Row(
children: [
Icon(
icon,
size: 20,
color: isSelected ? cs.primary : cs.onSurfaceVariant,
),
const SizedBox(width: 14),
Expanded(
child: Text(
title,
style: TextStyle(
color: isSelected ? cs.primary : cs.onSurface,
fontSize: 13.5,
fontWeight:
isSelected ? FontWeight.bold : FontWeight.w500,
),
),
),
],
),
),
),
),
);
}
Widget _buildThemeToggle(BuildContext context) {
final cs = Theme.of(context).colorScheme;
final isDark = Theme.of(context).brightness == Brightness.dark;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
child: Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
final newMode = isDark ? ThemeMode.light : ThemeMode.dark;
Get.changeThemeMode(newMode);
},
borderRadius: BorderRadius.circular(10),
hoverColor: cs.primary.withValues(alpha: 0.08),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: cs.surfaceContainerHighest,
borderRadius: BorderRadius.circular(10),
border: Border.all(color: cs.outline),
),
child: Row(
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: Icon(
isDark ? Icons.light_mode_rounded : Icons.dark_mode_rounded,
key: ValueKey(isDark),
size: 20,
color: isDark ? const Color(0xFFFBBF24) : cs.primary,
),
),
const SizedBox(width: 14),
Expanded(
child: Text(
isDark ? 'الوضع الفاتح' : 'الوضع الداكن',
style: TextStyle(
color: cs.onSurface,
fontSize: 13.5,
fontWeight: FontWeight.w500,
),
),
),
AnimatedContainer(
duration: const Duration(milliseconds: 300),
width: 44,
height: 24,
decoration: BoxDecoration(
color: isDark
? cs.primary.withValues(alpha: 0.3)
: cs.outline,
borderRadius: BorderRadius.circular(12),
),
child: AnimatedAlign(
duration: const Duration(milliseconds: 300),
alignment: isDark ? Alignment.centerRight : Alignment.centerLeft,
child: Container(
width: 20,
height: 20,
margin: const EdgeInsets.symmetric(horizontal: 2),
decoration: BoxDecoration(
color: isDark ? cs.primary : cs.onSurface,
shape: BoxShape.circle,
),
),
),
),
],
),
),
),
),
);
}
Widget _buildLogoutBtn(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return Container(
padding: const EdgeInsets.all(16),
child: InkWell(
onTap: () {
box.erase();
Get.offAllNamed('/login');
},
borderRadius: BorderRadius.circular(10),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
decoration: BoxDecoration(
color: cs.error.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(10),
border: Border.all(color: cs.error.withValues(alpha: 0.2)),
),
child: Row(
children: [
Icon(Icons.logout_rounded, color: cs.error, size: 20),
const SizedBox(width: 14),
Text(
'تسجيل الخروج',
style: TextStyle(
color: cs.error,
fontSize: 13.5,
fontWeight: FontWeight.bold,
),
),
],
),
),
),
);
}
}