إصلاح أخطاء شاشة الكباتن من تحديث الذكاء الاصطناعي

This commit is contained in:
Hamza-Ayed
2026-07-26 13:15:45 +03:00
parent 4b5235c35c
commit 330dfc6dba
9 changed files with 1025 additions and 61 deletions
+1 -1
View File
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"6c0baaebf70e0148f485f27d5616b3d3382da7
_flutter.loader.load({ _flutter.loader.load({
serviceWorkerSettings: { serviceWorkerSettings: {
serviceWorkerVersion: "578408601" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */ serviceWorkerVersion: "4149845318" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
} }
}); });
+466
View File
@@ -0,0 +1,466 @@
{
"pages": [
{
"route": "/admin/home",
"file": "lib/views/admin/admin_home_page.dart",
"title": "Admin Home Page (Dashboard)",
"appBarPattern": "SliverAppBar",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "charts|grid|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Custom AppBar with FlexibleSpaceBar; complex chart implementations; uses DashboardV2Widget"
},
{
"route": "/admin/analytics/live",
"file": "lib/views/admin/analytics/live_analytics_page.dart",
"title": "Live Analytics Page",
"appBarPattern": "AppBar",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "charts|map|tables",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Standard AppBar with TabBar; flutter_map integration; shared widget classes for charts"
},
{
"route": "/admin/analytics/advanced",
"file": "lib/views/admin/static/advanced_analytics_page.dart",
"title": "Advanced Analytics Page",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "charts|lists|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Custom Container header; Column+SingleChildScrollView instead of CustomScrollView; inline _LegendDot"
},
{
"route": "/admin/static",
"file": "lib/views/admin/static/static.dart",
"title": "System Statistics (StaticDash)",
"appBarPattern": "SliverAppBar",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "charts|lists",
"hasLoadingState": true,
"hasEmptyState": false,
"issues": "Complex SliverAppBar; extensive custom chart widgets; many inline helper classes"
},
{
"route": "/admin/passenger",
"file": "lib/views/admin/passenger/passenger.dart",
"title": "Passenger Management",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Custom Container header; Column+Expanded+GetBuilder pattern; consistent cs usage"
},
{
"route": "/admin/captain",
"file": "lib/views/admin/captain/captain.dart",
"title": "Captain List",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Custom Container header; search section separate; ListView.separated with cards"
},
{
"route": "/admin/drivers/pending",
"file": "lib/views/admin/captain/syrian_driver_not_active.dart",
"title": "Pending Captain Requests",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Misleading filename; Custom Container header; RefreshIndicator; status chips"
},
{
"route": "/driver-docs",
"file": "lib/views/admin/drivers/driver_documents_review_page.dart",
"title": "Driver Documents Review",
"appBarPattern": "AppBar",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards|images",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Standard AppBar; pagination with loadMore; ExpansionTile for doc details with images"
},
{
"route": "/admin/drivers/gifts",
"file": "lib/views/admin/drivers/driver_gift_check_page.dart",
"title": "Driver Gifts & Offers",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": true,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "form|log",
"hasLoadingState": true,
"hasEmptyState": false,
"issues": "Custom Container header; hardcoded Color(0xFFF59E0B); terminal log with hardcoded green Color(0xFF4ADE80)"
},
{
"route": "/admin/quality/blacklist",
"file": "lib/views/admin/quality/blacklist_page.dart",
"title": "Blacklist Page",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "tabs|lists",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Custom Container header with TabBar; TabBar in Container not AppBar.bottom; Dialog for unblock"
},
{
"route": "/admin/rides/dashboard",
"file": "lib/views/admin/rides/rides.dart",
"title": "Rides Dashboard",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "charts|grid|cards",
"hasLoadingState": true,
"hasEmptyState": false,
"issues": "Custom Container header; SingleChildScrollView+Column; LineChart; GridView for metrics"
},
{
"route": "/admin/rides/lookup",
"file": "lib/views/admin/rides/ride_lookup_page.dart",
"title": "Ride Lookup / Management",
"appBarPattern": "SliverAppBar",
"usesCsColors": false,
"hasHardcodedColors": true,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards|map",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "HARDCODED colors (bgColor, primaryColor, textPrimary); no Theme.of(context).colorScheme; complex SliverAppBar; custom ride cards; separate map screen"
},
{
"route": "/admin/drivers/monitor",
"file": "lib/views/admin/drivers/monitor_ride.dart",
"title": "Live Ride Monitoring",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "map|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Custom header for search; two views (search + map); loading/error overlays on map; bottom info panel"
},
{
"route": "/admin/drivers/tracker",
"file": "lib/views/admin/drivers/driver_tracker_screen.dart",
"title": "Captain Tracker (Siro Tracker)",
"appBarPattern": "Container-based (Positioned)",
"usesCsColors": true,
"hasHardcodedColors": true,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "map|dashboard",
"hasLoadingState": true,
"hasEmptyState": false,
"issues": "HARDCODED dark theme (Color(0xFF0A0E27)); Stack with Positioned overlays; custom dashboard panel; no standard Scaffold/AppBar"
},
{
"route": "/transit/orgs",
"file": "lib/views/transit/org_list_page.dart",
"title": "Transit Organizations",
"appBarPattern": "AppBar",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Standard AppBar; simple ListView with Cards; RefreshIndicator; clean minimal"
},
{
"route": "/admin/financial/v2",
"file": "lib/views/admin/financial/financial_v2_page.dart",
"title": "Financial Report V2",
"appBarPattern": "AppBar",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "cards|charts|lists",
"hasLoadingState": true,
"hasEmptyState": false,
"issues": "Standard AppBar with refresh; SingleChildScrollView+Column; LinearProgressIndicator; ListView.builder shrinkWrap"
},
{
"route": "/admin/wallet",
"file": "lib/views/admin/wallet/wallet.dart",
"title": "Financial Wallets",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Custom Container header; Pay All button; custom MyCircularProgressIndicator; consistent cs usage"
},
{
"route": "/admin/packages",
"file": "lib/views/admin/packages.dart",
"title": "Packages & Subscriptions",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Custom Container header; Get.dialog for edit; platform icons; controller in same file"
},
{
"route": "/invoice",
"file": "lib/views/invoice/invoice_list_page.dart",
"title": "Invoice List",
"appBarPattern": "Container-based (gradient)",
"usesCsColors": true,
"hasHardcodedColors": true,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards|images",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Gradient Container header (not AppBar); FAB; InteractiveViewer for images; hardcoded Colors.white in header"
},
{
"route": "/kazan",
"file": "lib/views/admin/pricing/kazan_editor_page.dart",
"title": "Kazan Pricing Editor",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": true,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "form|grid",
"hasLoadingState": true,
"hasEmptyState": false,
"issues": "Custom Container header; hardcoded car type colors; GoogleFonts; GridView for km prices; Slider for percentages"
},
{
"route": "/promo",
"file": "lib/views/admin/promo/promo_management_page.dart",
"title": "Promo Code Management",
"appBarPattern": "AppBar",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Standard AppBar; BottomSheet forms; PopupMenuButton; date pickers; GoogleFonts; custom widgets MyTextForm/MyElevatedButton"
},
{
"route": "/marketing",
"file": "lib/views/admin/marketing/marketing_page.dart",
"title": "Marketing & AI Automation",
"appBarPattern": "AppBar (complex bottom)",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "tabs|charts|lists|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "AppBar with PreferredSize bottom (country selector + TabBar); 3 tabs; FlChart charts; inline Card widgets; AI prompt editor"
},
{
"route": "/heatmap",
"file": "lib/views/admin/marketing/heatmap_page.dart",
"title": "Heatmap Page",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "map|filters",
"hasLoadingState": true,
"hasEmptyState": false,
"issues": "Custom Container header; FlutterMap with CircleLayer; filter chips; Dio HTTP; legend overlay"
},
{
"route": "/social-intelligence",
"file": "lib/views/admin/marketing/social_intelligence_screen.dart",
"title": "Social Intelligence",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|html",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Custom Container header; http package directly; HtmlWidget for HTML; ExpansionTile reports"
},
{
"route": "/complaints",
"file": "lib/views/admin/complaints/complaint_list_page.dart",
"title": "Complaints Management",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards",
"hasLoadingState": true,
"hasEmptyState": false,
"issues": "Custom Container header; delayed complaints banner; ExpansionTile; BottomSheet with dropdown; GoogleFonts"
},
{
"route": "/admin/server",
"file": "lib/views/admin/server/monitor_server_page.dart",
"title": "Server Monitor",
"appBarPattern": "SliverAppBar",
"usesCsColors": false,
"hasHardcodedColors": true,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "cards|charts|lists",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "HARDCODED dark theme (Color(0xFF0A0E27)); no Theme.of(context).colorScheme; SliverAppBar with gradient; LayoutBuilder responsive; all colors hardcoded"
},
{
"route": "/admin/security/audit-logs",
"file": "lib/views/admin/security/audit_logs_page.dart",
"title": "Audit Logs",
"appBarPattern": "Container-based",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Custom Container header; GetBuilder with SecurityV2Controller; simple ListView; empty state with DB hint"
},
{
"route": "/admin/employee",
"file": "lib/views/admin/employee/employee_page.dart",
"title": "Employee Management",
"appBarPattern": "SliverAppBar",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards|images",
"hasLoadingState": false,
"hasEmptyState": true,
"issues": "SliverAppBar with FlexibleSpaceBar; CustomScrollView with Slivers; FAB; image viewers for IDs; form inline in same file"
},
{
"route": "/admin/staff/add",
"file": "lib/views/admin/staff/add_staff_page.dart",
"title": "Add Staff Page",
"appBarPattern": "AppBar",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "form",
"hasLoadingState": true,
"hasEmptyState": false,
"issues": "Standard AppBar; form with helper methods; Dropdown for gender/country; role via constructor"
},
{
"route": "/admin/staff/pending",
"file": "lib/views/admin/staff/pending_admins_page.dart",
"title": "Pending Admins",
"appBarPattern": "AppBar",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards",
"hasLoadingState": true,
"hasEmptyState": true,
"issues": "Standard AppBar with surfaceContainerHighest bg; StatefulWidget with setState; CRUD in widget; action buttons per item"
},
{
"route": "/admin/error",
"file": "lib/views/admin/error/error/error_page.dart",
"title": "Error Logs",
"appBarPattern": "AppBar",
"usesCsColors": true,
"hasHardcodedColors": false,
"importsColorsDart": false,
"importsThemeDart": false,
"dataDisplay": "list|cards",
"hasLoadingState": true,
"hasEmptyState": false,
"issues": "Standard AppBar; search with phone filter; ExpansionTile for details; multiple _buildInfoBadge chips; StatefulWidget; ErrorLog model in same file"
}
],
"summary": {
"totalPages": 31,
"appBarPatterns": {
"AppBar": 8,
"SliverAppBar": 4,
"Container-based (custom)": 19
},
"colorSystemUsage": {
"usesColorScheme": 27,
"hasHardcodedColors": 4
},
"imports": {
"importsColorsDart": 0,
"importsThemeDart": 0
},
"dataDisplayTypes": {
"list": 22,
"cards": 20,
"charts": 9,
"map": 4,
"tables": 3,
"forms": 5,
"images": 3,
"html": 1
},
"loadingStates": 29,
"emptyStates": 22
}
}
@@ -40,15 +40,14 @@ class RideAdminController extends GetxController {
} }
Future getRidesDetails() async { Future getRidesDetails() async {
// isLoading = true; isLoading = true;
// update(); update();
var res = await CRUD().get(link: AppLink.getRidesDetails, payload: {}); var res = await CRUD().get(link: AppLink.getRidesDetails, payload: {});
var d = jsonDecode(res); var d = jsonDecode(res);
ridesDetails = d['message']; ridesDetails = d['message'];
isLoading = false;
// isLoading = false; update();
// update();
} }
@override @override
@@ -176,19 +176,21 @@ class WalletAdminController extends GetxController {
return token; return token;
} }
Future getWalletForEachDriverToPay() async { Future getWalletForEachDriverToPay() async {
isLoading = true; isLoading = true;
update(); update();
var res = await CRUD() var res = await CRUD()
.postWallet(link: AppLink.getVisaForEachDriver, payload: {}); .postWallet(link: AppLink.getVisaForEachDriver, payload: {});
var d = (res); var d = (res);
if (d != 'failure') { if (d != 'failure') {
driversWalletPoints = d['message']; driversWalletPoints = d['message'] ?? [];
isLoading = false; isLoading = false;
update(); update();
} } else {
driversWalletPoints = []; driversWalletPoints = [];
isLoading = false; isLoading = false;
update(); update();
} }
}
}
} }
@@ -5,20 +5,27 @@ import '../../views/widgets/snackbar.dart';
import '../functions/crud.dart'; import '../functions/crud.dart';
class DriverController extends GetxController { class DriverController extends GetxController {
bool isLoading = false;
List drivers = []; List drivers = [];
Map driverDetails = {}; Map driverDetails = {};
// جلب السائقين pending // جلب السائقين pending
getDriversPending() async { getDriversPending() async {
isLoading = true;
update();
var res = await CRUD().post( var res = await CRUD().post(
link: AppLink.getDriversPending, // رابط drivers_pending_list.php link: AppLink.getDriversPending,
payload: {}, payload: {},
); );
if (res != 'failure') { if (res != 'failure') {
drivers = (res)['message']; drivers = (res)['message'];
update(['drivers']); // تحديث الـ UI isLoading = false;
update(['drivers']);
} else { } else {
mySnackbarError('Failed to load drivers'); mySnackbarError('Failed to load drivers');
isLoading = false;
update();
}
} }
} }
@@ -23,13 +23,16 @@ class DriversPendingPage extends StatelessWidget {
body: Column( body: Column(
children: [ children: [
_buildAppBar(context, cs), _buildAppBar(context, cs),
Expanded( Expanded(
child: GetBuilder<DriverController>( child: GetBuilder<DriverController>(
id: 'drivers', id: 'drivers',
builder: (c) { if (c.drivers.isEmpty) { builder: (c) {
if (c.isLoading) {
return _buildLoadingState(cs);
}
if (c.drivers.isEmpty) {
return _buildEmptyState(cs); return _buildEmptyState(cs);
} }
return RefreshIndicator( return RefreshIndicator(
onRefresh: () => controller.getDriversPending(), onRefresh: () => controller.getDriversPending(),
color: cs.primary, color: cs.primary,
@@ -147,13 +147,16 @@ class BlacklistPage extends StatelessWidget {
itemCount: controller.driversBlacklist.length, itemCount: controller.driversBlacklist.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
var driver = controller.driversBlacklist[index]; var driver = controller.driversBlacklist[index];
final String phone = (driver['phone'] ?? driver['phone_normalized'] ?? driver['mobile'] ?? driver['number'] ?? '').toString();
final String reason = (driver['reason'] ?? driver['block_reason'] ?? driver['note'] ?? 'غير محدد').toString();
final String date = (driver['created_at'] ?? driver['createdAt'] ?? driver['date'] ?? driver['blocked_at'] ?? '').toString();
return _buildBlacklistItem( return _buildBlacklistItem(
phone: driver['phone'], phone: phone,
reason: driver['reason'] ?? 'غير محدد', reason: reason,
date: driver['created_at'], date: date,
type: 'سائق', type: 'سائق',
icon: Icons.drive_eta_rounded, icon: Icons.drive_eta_rounded,
onUnblock: () => controller.unblockDriver(driver['phone'].toString()), onUnblock: () => controller.unblockDriver(phone),
cs: cs, cs: cs,
); );
}, },
@@ -170,14 +173,17 @@ class BlacklistPage extends StatelessWidget {
itemCount: controller.passengersBlacklist.length, itemCount: controller.passengersBlacklist.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
var passenger = controller.passengersBlacklist[index]; var passenger = controller.passengersBlacklist[index];
final String phone = (passenger['phone'] ?? passenger['phone_normalized'] ?? passenger['mobile'] ?? passenger['number'] ?? '').toString();
final String reason = (passenger['reason'] ?? passenger['block_reason'] ?? passenger['note'] ?? 'غير محدد').toString();
final String date = (passenger['created_at'] ?? passenger['createdAt'] ?? passenger['date'] ?? passenger['blocked_at'] ?? '').toString();
final String phoneForUnblock = (passenger['phone_normalized'] ?? passenger['phone'] ?? passenger['mobile'] ?? passenger['number'] ?? '').toString();
return _buildBlacklistItem( return _buildBlacklistItem(
phone: passenger['phone'] ?? passenger['phone_normalized'], phone: phone,
reason: passenger['reason'] ?? 'غير محدد', reason: reason,
date: passenger['created_at'], date: date,
type: 'راكب', type: 'راكب',
icon: Icons.person_rounded, icon: Icons.person_rounded,
onUnblock: () => controller.unblockPassenger( onUnblock: () => controller.unblockPassenger(phoneForUnblock),
passenger['phone_normalized'].toString()),
cs: cs, cs: cs,
); );
}, },
@@ -204,11 +204,6 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
late final RidesListController controller; late final RidesListController controller;
late TabController _tabController; late TabController _tabController;
// 🎨 الألوان العصرية
final Color bgColor = const Color(0xFFF4F7FE);
final Color primaryColor = const Color(0xFF4318FF);
final Color textPrimary = const Color(0xFF2B3674);
@override @override
void initState() { void initState() {
super.initState(); super.initState();
@@ -232,10 +227,11 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final cs = Theme.of(context).colorScheme;
return Scaffold( return Scaffold(
backgroundColor: bgColor, backgroundColor: cs.surface,
body: SafeArea( body: SafeArea(
top: false, // نسمح للـ AppBar بالتمدد لأعلى الشاشة top: false,
child: CustomScrollView( child: CustomScrollView(
physics: const BouncingScrollPhysics(), physics: const BouncingScrollPhysics(),
slivers: [ slivers: [
@@ -243,16 +239,16 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
SliverAppBar( SliverAppBar(
pinned: true, pinned: true,
floating: false, floating: false,
expandedHeight: 310.0, // ارتفاع الجزء العلوي بالكامل expandedHeight: 310.0,
backgroundColor: primaryColor, backgroundColor: cs.primary,
elevation: 4, elevation: 4,
shadowColor: primaryColor.withOpacity(0.4), shadowColor: cs.primary.withValues(alpha: 0.4),
iconTheme: const IconThemeData(color: Colors.white), iconTheme: IconThemeData(color: cs.onPrimary),
centerTitle: true, centerTitle: true,
title: const Text( title: Text(
'إدارة الرحلات', 'إدارة الرحلات',
style: TextStyle( style: TextStyle(
color: Colors.white, color: cs.onPrimary,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 20, fontSize: 20,
), ),
@@ -263,16 +259,16 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
const EdgeInsets.symmetric(horizontal: 16, vertical: 10), const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
padding: const EdgeInsets.symmetric(horizontal: 14), padding: const EdgeInsets.symmetric(horizontal: 14),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withOpacity(0.2), color: cs.onPrimary.withValues(alpha: 0.2),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
alignment: Alignment.center, alignment: Alignment.center,
child: const Text( child: Text(
'اليوم', 'اليوم',
style: TextStyle( style: TextStyle(
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.white, color: cs.onPrimary,
), ),
), ),
), ),
@@ -281,7 +277,10 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
background: Container( background: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( gradient: LinearGradient(
colors: [primaryColor, primaryColor.withOpacity(0.8)], colors: [
cs.primary,
cs.primary.withValues(alpha: 0.8),
],
begin: Alignment.topCenter, begin: Alignment.topCenter,
end: Alignment.bottomCenter, end: Alignment.bottomCenter,
), ),
@@ -290,12 +289,12 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
mainAxisAlignment: MainAxisAlignment.end, mainAxisAlignment: MainAxisAlignment.end,
children: [ children: [
// الإحصائيات تختفي عند التمرير لأعلى // الإحصائيات تختفي عند التمرير لأعلى
_buildStatisticsSection(), _buildStatisticsSection(cs),
const SizedBox(height: 12), const SizedBox(height: 12),
// شريط البحث يختفي عند التمرير لأعلى // شريط البحث يختفي عند التمرير لأعلى
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 16), padding: const EdgeInsets.symmetric(horizontal: 16),
child: _buildSearchBar(), child: _buildSearchBar(cs),
), ),
const SizedBox(height: 60), // مساحة للـ TabBar بالأسفل const SizedBox(height: 60), // مساحة للـ TabBar بالأسفل
], ],
@@ -306,18 +305,17 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
bottom: PreferredSize( bottom: PreferredSize(
preferredSize: const Size.fromHeight(54), preferredSize: const Size.fromHeight(54),
child: Container( child: Container(
decoration: const BoxDecoration( decoration: BoxDecoration(
color: color: cs.surface,
Color(0xFFF4F7FE), // لون خلفية التطبيق ليظهر بشكل مدمج
borderRadius: borderRadius:
BorderRadius.vertical(top: Radius.circular(24)), const BorderRadius.vertical(top: Radius.circular(24)),
), ),
child: TabBar( child: TabBar(
controller: _tabController, controller: _tabController,
isScrollable: true, isScrollable: true,
labelColor: primaryColor, labelColor: cs.primary,
unselectedLabelColor: Colors.grey, unselectedLabelColor: cs.onSurfaceVariant,
indicatorColor: primaryColor, indicatorColor: cs.primary,
indicatorWeight: 3, indicatorWeight: 3,
labelStyle: const TextStyle( labelStyle: const TextStyle(
fontWeight: FontWeight.bold, fontSize: 14), fontWeight: FontWeight.bold, fontSize: 14),
@@ -359,13 +357,13 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Icon(Icons.inbox_rounded, Icon(Icons.inbox_rounded,
size: 80, color: Colors.grey[400]), size: 80, color: cs.onSurfaceVariant),
const SizedBox(height: 16), const SizedBox(height: 16),
Text( Text(
'لا توجد رحلات في هذا القسم', 'لا توجد رحلات في هذا القسم',
style: TextStyle( style: TextStyle(
fontSize: 16, fontSize: 16,
color: Colors.grey[600], color: cs.onSurfaceVariant,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
@@ -380,7 +378,7 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
(context, index) { (context, index) {
final ride = controller.displayedRides[index]; final ride = controller.displayedRides[index];
return _buildRideCardCompact( return _buildRideCardCompact(
ride, controller.isSuperAdmin); ride, controller.isSuperAdmin, cs);
}, },
childCount: controller.displayedRides.length, childCount: controller.displayedRides.length,
), ),
@@ -395,7 +393,7 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
// --- Components --- // --- Components ---
Widget _buildStatisticsSection() { Widget _buildStatisticsSection(ColorScheme cs) {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
@@ -446,17 +444,17 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
} }
Widget _buildStatCard( Widget _buildStatCard(
String label, String value, IconData icon, Color iconColor) { String label, String value, IconData icon, Color iconColor, ColorScheme cs) {
return Container( return Container(
width: 105, width: 105,
margin: const EdgeInsets.only(left: 10), margin: const EdgeInsets.only(left: 10),
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8), padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: cs.surface,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: Colors.black.withOpacity(0.1), color: cs.shadow.withValues(alpha: 0.1),
blurRadius: 10, blurRadius: 10,
offset: const Offset(0, 4), offset: const Offset(0, 4),
) )
@@ -470,7 +468,7 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
Text( Text(
value, value,
style: TextStyle( style: TextStyle(
fontSize: 18, fontWeight: FontWeight.bold, color: textPrimary), fontSize: 18, fontWeight: FontWeight.bold, color: cs.onSurface),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@@ -479,7 +477,7 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
label, label,
style: TextStyle( style: TextStyle(
fontSize: 11, fontSize: 11,
color: Colors.grey[600], color: cs.onSurfaceVariant,
fontWeight: FontWeight.bold), fontWeight: FontWeight.bold),
), ),
], ],
@@ -487,7 +485,7 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
); );
} }
Widget _buildSearchBar() { Widget _buildSearchBar(ColorScheme cs) {
return Container( return Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white, color: Colors.white,
@@ -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!,
],
],
),
);
}
}