إصلاح أخطاء شاشة الكباتن من تحديث الذكاء الاصطناعي
This commit is contained in:
+812
-907
File diff suppressed because it is too large
Load Diff
@@ -37,6 +37,6 @@ _flutter.buildConfig = {"engineRevision":"6c0baaebf70e0148f485f27d5616b3d3382da7
|
|||||||
|
|
||||||
_flutter.loader.load({
|
_flutter.loader.load({
|
||||||
serviceWorkerSettings: {
|
serviceWorkerSettings: {
|
||||||
serviceWorkerVersion: "4149845318" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
|
serviceWorkerVersion: "191517914" /* Flutter's service worker is deprecated and will be removed in a future Flutter release. */
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+70438
-70201
File diff suppressed because one or more lines are too long
@@ -216,14 +216,14 @@ class AppTheme {
|
|||||||
side: const BorderSide(color: AppColor.divider),
|
side: const BorderSide(color: AppColor.divider),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
pageTransitionsTheme: const PageTransitionsTheme(
|
pageTransitionsTheme: PageTransitionsTheme(
|
||||||
builders: {
|
builders: {
|
||||||
TargetPlatform.windows: FadeUpwardsPageTransitionsBuilder(),
|
TargetPlatform.windows: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
TargetPlatform.macOS: FadeUpwardsPageTransitionsBuilder(),
|
TargetPlatform.macOS: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
TargetPlatform.linux: FadeUpwardsPageTransitionsBuilder(),
|
TargetPlatform.linux: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
TargetPlatform.fuchsia: FadeUpwardsPageTransitionsBuilder(),
|
TargetPlatform.fuchsia: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
TargetPlatform.android: CupertinoPageTransitionsBuilder(),
|
TargetPlatform.android: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
|
TargetPlatform.iOS: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -240,13 +240,11 @@ class AppTheme {
|
|||||||
const textMutedLight = Color(0xFF9CA3AF);
|
const textMutedLight = Color(0xFF9CA3AF);
|
||||||
const accentLight = Color(0xFF6366F1);
|
const accentLight = Color(0xFF6366F1);
|
||||||
const accentSoftLight = Color(0x1A6366F1);
|
const accentSoftLight = Color(0x1A6366F1);
|
||||||
const accentBorderLight = Color(0x336366F1);
|
|
||||||
const glowLight = Color(0xFF4F46E5);
|
const glowLight = Color(0xFF4F46E5);
|
||||||
const dangerLight = Color(0xFFDC2626);
|
const dangerLight = Color(0xFFDC2626);
|
||||||
const dangerSoftLight = Color(0x1ADC2626);
|
const dangerSoftLight = Color(0x1ADC2626);
|
||||||
const successLight = Color(0xFF059669);
|
const successLight = Color(0xFF059669);
|
||||||
const successSoftLight = Color(0x1A059669);
|
const successSoftLight = Color(0x1A059669);
|
||||||
const warningLight = Color(0xFFD97706);
|
|
||||||
const infoLight = Color(0xFF2563EB);
|
const infoLight = Color(0xFF2563EB);
|
||||||
|
|
||||||
final lightScheme = ColorScheme.light(
|
final lightScheme = ColorScheme.light(
|
||||||
@@ -457,14 +455,14 @@ class AppTheme {
|
|||||||
side: const BorderSide(color: dividerLight),
|
side: const BorderSide(color: dividerLight),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
pageTransitionsTheme: const PageTransitionsTheme(
|
pageTransitionsTheme: PageTransitionsTheme(
|
||||||
builders: {
|
builders: {
|
||||||
TargetPlatform.windows: FadeUpwardsPageTransitionsBuilder(),
|
TargetPlatform.windows: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
TargetPlatform.macOS: FadeUpwardsPageTransitionsBuilder(),
|
TargetPlatform.macOS: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
TargetPlatform.linux: FadeUpwardsPageTransitionsBuilder(),
|
TargetPlatform.linux: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
TargetPlatform.fuchsia: FadeUpwardsPageTransitionsBuilder(),
|
TargetPlatform.fuchsia: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
TargetPlatform.android: CupertinoPageTransitionsBuilder(),
|
TargetPlatform.android: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
TargetPlatform.iOS: CupertinoPageTransitionsBuilder(),
|
TargetPlatform.iOS: const FadeUpwardsPageTransitionsBuilder(),
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -192,5 +192,4 @@ Future getWalletForEachDriverToPay() async {
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ class DriverController extends GetxController {
|
|||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// جلب تفاصيل سائق واحد
|
// جلب تفاصيل سائق واحد
|
||||||
getDriverDetails(String driverId) async {
|
getDriverDetails(String driverId) async {
|
||||||
|
|||||||
@@ -515,6 +515,11 @@ class _AdminHomePageState extends State<AdminHomePage>
|
|||||||
final maxBar = [comfort, speed, lady].reduce((a, b) => a > b ? a : b);
|
final maxBar = [comfort, speed, lady].reduce((a, b) => a > b ? a : b);
|
||||||
final barMaxY = maxBar > 0 ? (maxBar * 1.3).ceilToDouble() : 10.0;
|
final barMaxY = maxBar > 0 ? (maxBar * 1.3).ceilToDouble() : 10.0;
|
||||||
|
|
||||||
|
final payments = (data['payments'] ?? 0).toDouble();
|
||||||
|
final passengerCount = (data['countPassengers'] ?? 0).toDouble();
|
||||||
|
final driverCount = (data['countDriver'] ?? 0).toDouble();
|
||||||
|
final monthRides = (data['countRideThisMonth'] ?? 0).toDouble();
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: Column(
|
child: Column(
|
||||||
@@ -697,6 +702,203 @@ class _AdminHomePageState extends State<AdminHomePage>
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
AnimationConfiguration.staggeredList(
|
||||||
|
position: 0,
|
||||||
|
duration: const Duration(milliseconds: 450),
|
||||||
|
child: SlideAnimation(
|
||||||
|
verticalOffset: 40.0,
|
||||||
|
child: FadeInAnimation(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: cs.surfaceContainerHighest,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
border: Border.all(color: cs.outline),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.account_balance_rounded, color: cs.primary, size: 18),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text('نظرة عامة على الإيرادات', style: TextStyle(color: cs.onSurface, fontSize: 13, fontWeight: FontWeight.w600)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
SizedBox(
|
||||||
|
height: 120,
|
||||||
|
child: BarChart(
|
||||||
|
BarChartData(
|
||||||
|
alignment: BarChartAlignment.center,
|
||||||
|
maxY: (payments * 1.3) > 0 ? (payments * 1.3) : 10,
|
||||||
|
barTouchData: BarTouchData(
|
||||||
|
touchTooltipData: BarTouchTooltipData(
|
||||||
|
getTooltipColor: (_) => cs.surfaceContainerHighest,
|
||||||
|
getTooltipItem: (group, groupIndex, rod, rodIndex) {
|
||||||
|
return BarTooltipItem(
|
||||||
|
_formatCurrency(rod.toY),
|
||||||
|
TextStyle(color: cs.onSurface, fontSize: 11, fontWeight: FontWeight.w600),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
titlesData: FlTitlesData(
|
||||||
|
show: true,
|
||||||
|
topTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
||||||
|
leftTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
||||||
|
rightTitles: const AxisTitles(sideTitles: SideTitles(showTitles: false)),
|
||||||
|
bottomTitles: AxisTitles(
|
||||||
|
sideTitles: SideTitles(
|
||||||
|
showTitles: true,
|
||||||
|
reservedSize: 30,
|
||||||
|
getTitlesWidget: (value, meta) {
|
||||||
|
return Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 6),
|
||||||
|
child: Text('Payments', style: TextStyle(color: cs.onSurfaceVariant, fontSize: 10)),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
gridData: const FlGridData(show: false),
|
||||||
|
borderData: FlBorderData(show: false),
|
||||||
|
barGroups: [
|
||||||
|
BarChartGroupData(
|
||||||
|
x: 0,
|
||||||
|
barRods: [
|
||||||
|
BarChartRodData(
|
||||||
|
toY: payments,
|
||||||
|
color: cs.primary,
|
||||||
|
width: 40,
|
||||||
|
borderRadius: const BorderRadius.vertical(top: Radius.circular(6)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
Center(
|
||||||
|
child: Text(
|
||||||
|
'إجمالي المدفوعات: ${_formatCurrency(payments)}',
|
||||||
|
style: TextStyle(color: cs.onSurface, fontSize: 16, fontWeight: FontWeight.bold),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
AnimationConfiguration.staggeredList(
|
||||||
|
position: 1,
|
||||||
|
duration: const Duration(milliseconds: 450),
|
||||||
|
child: SlideAnimation(
|
||||||
|
verticalOffset: 40.0,
|
||||||
|
child: FadeInAnimation(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: cs.surfaceContainerHighest,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
border: Border.all(color: cs.outline),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
Icon(Icons.compare_arrows_rounded, color: cs.primary, size: 18),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text('نسبة السائقين إلى الركاب', style: TextStyle(color: cs.onSurface, fontSize: 13, fontWeight: FontWeight.w600)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 16),
|
||||||
|
_buildRatioBar('السائقين', driverCount, driverCount + passengerCount, cs.secondary, cs),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
_buildRatioBar('الركاب', passengerCount, driverCount + passengerCount, cs.tertiary, cs),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
AnimationConfiguration.staggeredList(
|
||||||
|
position: 2,
|
||||||
|
duration: const Duration(milliseconds: 450),
|
||||||
|
child: SlideAnimation(
|
||||||
|
verticalOffset: 40.0,
|
||||||
|
child: FadeInAnimation(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: cs.surfaceContainerHighest,
|
||||||
|
borderRadius: BorderRadius.circular(16),
|
||||||
|
border: Border.all(color: cs.outline),
|
||||||
|
),
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
_buildMiniStatCard('رحلات الشهر', monthRides, Icons.calendar_today_rounded, cs.primary, cs),
|
||||||
|
_buildMiniStatCard('الركاب', passengerCount, Icons.group_rounded, cs.tertiary, cs),
|
||||||
|
_buildMiniStatCard('السائقين', driverCount, Icons.drive_eta_rounded, cs.secondary, cs),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildRatioBar(String label, double value, double total, Color color, ColorScheme cs) {
|
||||||
|
final ratio = total > 0 ? value / total : 0.0;
|
||||||
|
return Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Text(label, style: TextStyle(color: cs.onSurfaceVariant, fontSize: 11)),
|
||||||
|
Text(value.toInt().toString(), style: TextStyle(color: cs.onSurface, fontSize: 12, fontWeight: FontWeight.w600)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
const SizedBox(height: 6),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(8),
|
||||||
|
child: LinearProgressIndicator(
|
||||||
|
value: ratio,
|
||||||
|
backgroundColor: cs.surface,
|
||||||
|
color: color,
|
||||||
|
minHeight: 12,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget _buildMiniStatCard(String label, dynamic value, IconData icon, Color color, ColorScheme cs) {
|
||||||
|
return Expanded(
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: color.withValues(alpha: 0.12),
|
||||||
|
borderRadius: BorderRadius.circular(12),
|
||||||
|
),
|
||||||
|
child: Icon(icon, color: color, size: 22),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 8),
|
||||||
|
Text(value.toString(), style: TextStyle(color: cs.onSurface, fontSize: 18, fontWeight: FontWeight.bold)),
|
||||||
|
const SizedBox(height: 2),
|
||||||
|
Text(label, style: TextStyle(color: cs.onSurfaceVariant, fontSize: 10)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -18,13 +18,27 @@ class LiveAnalyticsPage extends StatelessWidget {
|
|||||||
length: 4,
|
length: 4,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: cs.surface,
|
backgroundColor: cs.surface,
|
||||||
appBar: AppBar(
|
body: Column(
|
||||||
title: const Text('لوحة البيانات التفاعلية',
|
children: [
|
||||||
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
|
Container(
|
||||||
backgroundColor: cs.surfaceContainerHighest,
|
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
|
||||||
elevation: 0,
|
child: Row(
|
||||||
centerTitle: true,
|
children: [
|
||||||
actions: [
|
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),
|
||||||
|
Text('لوحة البيانات التفاعلية', style: TextStyle(color: cs.onSurface, fontSize: 18, fontWeight: FontWeight.w700)),
|
||||||
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.calendar_month_rounded, size: 22),
|
icon: const Icon(Icons.calendar_month_rounded, size: 22),
|
||||||
onPressed: () => _pickDate(context, c),
|
onPressed: () => _pickDate(context, c),
|
||||||
@@ -34,7 +48,11 @@ class LiveAnalyticsPage extends StatelessWidget {
|
|||||||
onPressed: () => c.fetchAll(),
|
onPressed: () => c.fetchAll(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
bottom: TabBar(
|
),
|
||||||
|
),
|
||||||
|
Container(
|
||||||
|
color: cs.surface,
|
||||||
|
child: TabBar(
|
||||||
isScrollable: true,
|
isScrollable: true,
|
||||||
indicatorColor: cs.primary,
|
indicatorColor: cs.primary,
|
||||||
labelColor: cs.primary,
|
labelColor: cs.primary,
|
||||||
@@ -48,7 +66,8 @@ class LiveAnalyticsPage extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: GetBuilder<LiveAnalyticsController>(
|
Expanded(
|
||||||
|
child: GetBuilder<LiveAnalyticsController>(
|
||||||
builder: (ctrl) {
|
builder: (ctrl) {
|
||||||
if (ctrl.isLoading) {
|
if (ctrl.isLoading) {
|
||||||
return Center(
|
return Center(
|
||||||
@@ -85,6 +104,9 @@ class LiveAnalyticsPage extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:siro_admin/constant/box_name.dart';
|
|
||||||
import 'package:siro_admin/constant/info.dart';
|
|
||||||
import 'package:siro_admin/constant/char_map.dart';
|
|
||||||
import 'package:siro_admin/controller/drivers/driver_not_active_controller.dart';
|
import 'package:siro_admin/controller/drivers/driver_not_active_controller.dart';
|
||||||
import 'package:siro_admin/main.dart';
|
|
||||||
import 'package:siro_admin/print.dart';
|
|
||||||
import 'package:siro_admin/constant/theme.dart';
|
|
||||||
import 'driver_details_not_active_page.dart';
|
import 'driver_details_not_active_page.dart';
|
||||||
|
|
||||||
class DriversPendingPage extends StatelessWidget {
|
class DriversPendingPage extends StatelessWidget {
|
||||||
|
|||||||
@@ -17,17 +17,31 @@ class DriverDocsReviewPage extends StatelessWidget {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: cs.surface,
|
backgroundColor: cs.surface,
|
||||||
appBar: AppBar(
|
body: Column(
|
||||||
backgroundColor: cs.surface,
|
children: [
|
||||||
elevation: 0,
|
Container(
|
||||||
centerTitle: true,
|
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
|
||||||
title: Text('مراجعة طلبات التسجيل'.tr, style: GoogleFonts.inter(fontWeight: FontWeight.w600, color: cs.onSurface)),
|
child: Row(
|
||||||
leading: GestureDetector(
|
children: [
|
||||||
|
GestureDetector(
|
||||||
onTap: () => Get.back(),
|
onTap: () => Get.back(),
|
||||||
child: Icon(Icons.arrow_back_ios_new_rounded, color: cs.onSurface),
|
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),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: Obx(() => controller.isLoading.value && controller.pendingDrivers.isEmpty
|
const SizedBox(width: 12),
|
||||||
|
Text('مراجعة طلبات التسجيل'.tr, style: TextStyle(color: cs.onSurface, fontSize: 18, fontWeight: FontWeight.w700)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Obx(() => controller.isLoading.value && controller.pendingDrivers.isEmpty
|
||||||
? Center(child: CircularProgressIndicator(color: cs.primary))
|
? Center(child: CircularProgressIndicator(color: cs.primary))
|
||||||
: controller.pendingDrivers.isEmpty
|
: controller.pendingDrivers.isEmpty
|
||||||
? Center(
|
? Center(
|
||||||
@@ -71,6 +85,9 @@ class DriverDocsReviewPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'package:siro_admin/constant/links.dart';
|
import 'package:siro_admin/constant/links.dart';
|
||||||
import 'package:siro_admin/controller/functions/crud.dart';
|
import 'package:siro_admin/controller/functions/crud.dart';
|
||||||
|
|
||||||
@@ -130,30 +131,26 @@ class _ErrorListPageState extends State<ErrorListPage> {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: cs.surface,
|
backgroundColor: cs.surface,
|
||||||
appBar: _buildAppBar(cs),
|
|
||||||
body: Column(
|
body: Column(
|
||||||
children: [
|
children: [
|
||||||
_SearchBar(
|
Container(
|
||||||
controller: _phoneCtrl,
|
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
|
||||||
onSearch: _searchByPhone,
|
child: Row(
|
||||||
onClear: _clearSearch,
|
children: [
|
||||||
cs: cs,
|
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),
|
||||||
),
|
),
|
||||||
Expanded(
|
child: Icon(Icons.arrow_back_ios_new_rounded, color: cs.onSurfaceVariant, size: 16),
|
||||||
child: _buildBody(cs),
|
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
const SizedBox(width: 12),
|
||||||
}
|
Container(
|
||||||
|
|
||||||
PreferredSizeWidget _buildAppBar(ColorScheme cs) {
|
|
||||||
return AppBar(
|
|
||||||
elevation: 0,
|
|
||||||
backgroundColor: cs.surfaceContainerHighest,
|
|
||||||
foregroundColor: cs.onSurface,
|
|
||||||
centerTitle: true,
|
|
||||||
title: Container(
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: cs.onSurface.withValues(alpha: 0.1),
|
color: cs.onSurface.withValues(alpha: 0.1),
|
||||||
@@ -176,6 +173,20 @@ class _ErrorListPageState extends State<ErrorListPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
_SearchBar(
|
||||||
|
controller: _phoneCtrl,
|
||||||
|
onSearch: _searchByPhone,
|
||||||
|
onClear: _clearSearch,
|
||||||
|
cs: cs,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: _buildBody(cs),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,21 +12,36 @@ class FinancialV2Page extends StatelessWidget {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: cs.surface,
|
backgroundColor: cs.surface,
|
||||||
appBar: AppBar(
|
body: Column(
|
||||||
title: Text('الإدارة المالية المتقدمة',
|
children: [
|
||||||
style: TextStyle(fontWeight: FontWeight.bold, color: cs.onSurface)),
|
Container(
|
||||||
backgroundColor: cs.surface,
|
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
|
||||||
elevation: 0,
|
child: Row(
|
||||||
centerTitle: true,
|
children: [
|
||||||
iconTheme: IconThemeData(color: cs.onSurface),
|
GestureDetector(
|
||||||
actions: [
|
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),
|
||||||
|
Text('الإدارة المالية المتقدمة', style: TextStyle(color: cs.onSurface, fontSize: 18, fontWeight: FontWeight.w700)),
|
||||||
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.refresh_rounded, color: cs.onSurface),
|
icon: Icon(Icons.refresh_rounded, color: cs.onSurfaceVariant),
|
||||||
onPressed: () => controller.fetchAllFinancials(),
|
onPressed: () => controller.fetchAllFinancials(),
|
||||||
)
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: GetBuilder<FinancialV2Controller>(
|
),
|
||||||
|
Expanded(
|
||||||
|
child: GetBuilder<FinancialV2Controller>(
|
||||||
builder: (ctrl) {
|
builder: (ctrl) {
|
||||||
if (ctrl.isLoading) {
|
if (ctrl.isLoading) {
|
||||||
return Center(
|
return Center(
|
||||||
@@ -51,6 +66,9 @@ class FinancialV2Page extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,20 +24,33 @@ class MarketingPage extends StatelessWidget {
|
|||||||
length: 3,
|
length: 3,
|
||||||
child: Scaffold(
|
child: Scaffold(
|
||||||
backgroundColor: cs.surface,
|
backgroundColor: cs.surface,
|
||||||
appBar: AppBar(
|
body: Column(
|
||||||
title: Text(
|
|
||||||
'أتمتة التسويق الذكي (Siro AI Marketing)',
|
|
||||||
style: TextStyle(fontWeight: FontWeight.w700, fontSize: 16, color: cs.onSurface),
|
|
||||||
),
|
|
||||||
backgroundColor: cs.surface,
|
|
||||||
elevation: 0,
|
|
||||||
foregroundColor: cs.onSurface,
|
|
||||||
bottom: PreferredSize(
|
|
||||||
preferredSize: const Size.fromHeight(98),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
children: [
|
||||||
|
Container(
|
||||||
|
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
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),
|
||||||
|
Text('أتمتة التسويق الذكي (Siro AI Marketing)', style: TextStyle(color: cs.onSurface, fontSize: 18, fontWeight: FontWeight.w700)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
_buildCountrySelector(c, cs),
|
_buildCountrySelector(c, cs),
|
||||||
TabBar(
|
Container(
|
||||||
|
color: cs.surface,
|
||||||
|
child: TabBar(
|
||||||
indicatorColor: cs.primary,
|
indicatorColor: cs.primary,
|
||||||
labelColor: cs.primary,
|
labelColor: cs.primary,
|
||||||
unselectedLabelColor: cs.onSurfaceVariant,
|
unselectedLabelColor: cs.onSurfaceVariant,
|
||||||
@@ -48,11 +61,9 @@ class MarketingPage extends StatelessWidget {
|
|||||||
Tab(icon: Icon(Icons.settings_outlined, size: 20), text: 'إعدادات الأتمتة والتحكم'),
|
Tab(icon: Icon(Icons.settings_outlined, size: 20), text: 'إعدادات الأتمتة والتحكم'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
Expanded(
|
||||||
),
|
child: TabBarView(
|
||||||
body: TabBarView(
|
|
||||||
children: [
|
children: [
|
||||||
_buildAnomaliesTab(context, c, cs),
|
_buildAnomaliesTab(context, c, cs),
|
||||||
_buildLogsTab(context, c, cs),
|
_buildLogsTab(context, c, cs),
|
||||||
@@ -60,6 +71,9 @@ class MarketingPage extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -17,23 +17,36 @@ class PromoManagementPage extends StatelessWidget {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: cs.surface,
|
backgroundColor: cs.surface,
|
||||||
appBar: AppBar(
|
body: Column(
|
||||||
backgroundColor: cs.surface,
|
children: [
|
||||||
elevation: 0,
|
Container(
|
||||||
centerTitle: true,
|
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
|
||||||
title: Text('إدارة أكواد الخصم'.tr, style: GoogleFonts.inter(fontWeight: FontWeight.w600, color: cs.onSurface)),
|
child: Row(
|
||||||
leading: GestureDetector(
|
children: [
|
||||||
|
GestureDetector(
|
||||||
onTap: () => Get.back(),
|
onTap: () => Get.back(),
|
||||||
child: Icon(Icons.arrow_back_ios_new_rounded, color: cs.onSurface),
|
child: Container(
|
||||||
|
padding: const EdgeInsets.all(8),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: cs.surfaceContainerHighest,
|
||||||
|
borderRadius: BorderRadius.circular(10),
|
||||||
|
border: Border.all(color: cs.outline),
|
||||||
),
|
),
|
||||||
actions: [
|
child: Icon(Icons.arrow_back_ios_new_rounded, color: cs.onSurfaceVariant, size: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text('إدارة أكواد الخصم'.tr, style: TextStyle(color: cs.onSurface, fontSize: 18, fontWeight: FontWeight.w700)),
|
||||||
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.add_circle_outline_rounded, color: cs.primary),
|
icon: Icon(Icons.add_circle_outline_rounded, color: cs.primary),
|
||||||
onPressed: () => _showPromoSheet(context),
|
onPressed: () => _showPromoSheet(context),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Obx(() => controller.isLoading.value && controller.promoList.isEmpty
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Obx(() => controller.isLoading.value && controller.promoList.isEmpty
|
||||||
? Center(child: CircularProgressIndicator(color: cs.primary))
|
? Center(child: CircularProgressIndicator(color: cs.primary))
|
||||||
: controller.promoList.isEmpty
|
: controller.promoList.isEmpty
|
||||||
? Center(
|
? Center(
|
||||||
@@ -61,6 +74,9 @@ class PromoManagementPage extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -418,24 +418,24 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
|
|||||||
'جارية',
|
'جارية',
|
||||||
controller.beginCount.toString(),
|
controller.beginCount.toString(),
|
||||||
Icons.directions_car_rounded,
|
Icons.directions_car_rounded,
|
||||||
const Color(0xFF10B981))),
|
const Color(0xFF10B981), cs)),
|
||||||
Obx(() => _buildStatCard('جديدة', controller.newCount.toString(),
|
Obx(() => _buildStatCard('جديدة', controller.newCount.toString(),
|
||||||
Icons.new_releases_rounded, const Color(0xFF3B82F6))),
|
Icons.new_releases_rounded, const Color(0xFF3B82F6), cs)),
|
||||||
Obx(() => _buildStatCard(
|
Obx(() => _buildStatCard(
|
||||||
'مكتملة',
|
'مكتملة',
|
||||||
controller.completedCount.toString(),
|
controller.completedCount.toString(),
|
||||||
Icons.check_circle_rounded,
|
Icons.check_circle_rounded,
|
||||||
const Color(0xFF14B8A6))),
|
const Color(0xFF14B8A6), cs)),
|
||||||
Obx(() => _buildStatCard(
|
Obx(() => _buildStatCard(
|
||||||
'ملغاة',
|
'ملغاة',
|
||||||
controller.canceledCount.toString(),
|
controller.canceledCount.toString(),
|
||||||
Icons.cancel_rounded,
|
Icons.cancel_rounded,
|
||||||
const Color(0xFFEF4444))),
|
const Color(0xFFEF4444), cs)),
|
||||||
Obx(() => _buildStatCard(
|
Obx(() => _buildStatCard(
|
||||||
'الإيرادات',
|
'الإيرادات',
|
||||||
controller.totalRevenue.value.toStringAsFixed(0),
|
controller.totalRevenue.value.toStringAsFixed(0),
|
||||||
Icons.payments_rounded,
|
Icons.payments_rounded,
|
||||||
const Color(0xFFF59E0B))),
|
const Color(0xFFF59E0B), cs)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -488,11 +488,11 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
|
|||||||
Widget _buildSearchBar(ColorScheme cs) {
|
Widget _buildSearchBar(ColorScheme cs) {
|
||||||
return Container(
|
return Container(
|
||||||
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.05),
|
color: cs.shadow.withValues(alpha: 0.05),
|
||||||
blurRadius: 8,
|
blurRadius: 8,
|
||||||
offset: const Offset(0, 4),
|
offset: const Offset(0, 4),
|
||||||
)
|
)
|
||||||
@@ -501,14 +501,14 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
|
|||||||
child: TextField(
|
child: TextField(
|
||||||
controller: controller.searchController,
|
controller: controller.searchController,
|
||||||
onChanged: (val) => controller.filterRides(val),
|
onChanged: (val) => controller.filterRides(val),
|
||||||
style: TextStyle(color: textPrimary, fontWeight: FontWeight.w600),
|
style: TextStyle(color: cs.onSurface, fontWeight: FontWeight.w600),
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: 'ابحث عن رقم الرحلة، السائق، أو الراكب...',
|
hintText: 'ابحث عن رقم الرحلة، السائق، أو الراكب...',
|
||||||
hintStyle: TextStyle(color: Colors.grey[400], fontSize: 13),
|
hintStyle: TextStyle(color: cs.onSurfaceVariant, fontSize: 13),
|
||||||
prefixIcon: Icon(Icons.search_rounded, color: primaryColor),
|
prefixIcon: Icon(Icons.search_rounded, color: cs.primary),
|
||||||
suffixIcon: controller.searchController.text.isNotEmpty
|
suffixIcon: controller.searchController.text.isNotEmpty
|
||||||
? IconButton(
|
? IconButton(
|
||||||
icon: const Icon(Icons.close_rounded, color: Colors.grey),
|
icon: Icon(Icons.close_rounded, color: cs.onSurfaceVariant),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
controller.searchController.clear();
|
controller.searchController.clear();
|
||||||
controller.filterRides('');
|
controller.filterRides('');
|
||||||
@@ -527,23 +527,23 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
|
|||||||
// تصميم بطاقة الرحلة (المدمج والمنظم - Slim Design)
|
// تصميم بطاقة الرحلة (المدمج والمنظم - Slim Design)
|
||||||
// ═══════════════════════════════════════════════════════════════════════════
|
// ═══════════════════════════════════════════════════════════════════════════
|
||||||
|
|
||||||
Widget _buildRideCardCompact(RideDashboardModel ride, bool isAdmin) {
|
Widget _buildRideCardCompact(RideDashboardModel ride, bool isAdmin, ColorScheme cs) {
|
||||||
Color statusColor = _getStatusColor(ride.status);
|
Color statusColor = _getStatusColor(ride.status);
|
||||||
String statusText = _getStatusText(ride.status);
|
String statusText = _getStatusText(ride.status);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(bottom: 16),
|
margin: const EdgeInsets.only(bottom: 16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white,
|
color: cs.surface,
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: Colors.black.withOpacity(0.04),
|
color: cs.shadow.withValues(alpha: 0.04),
|
||||||
blurRadius: 10,
|
blurRadius: 10,
|
||||||
offset: const Offset(0, 4),
|
offset: const Offset(0, 4),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
border: Border.all(color: Colors.grey.withOpacity(0.1)),
|
border: Border.all(color: cs.outline.withValues(alpha: 0.1)),
|
||||||
),
|
),
|
||||||
child: Material(
|
child: Material(
|
||||||
color: Colors.transparent,
|
color: Colors.transparent,
|
||||||
@@ -567,11 +567,11 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(6),
|
padding: const EdgeInsets.all(6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: primaryColor.withOpacity(0.1),
|
color: cs.primary.withValues(alpha: 0.1),
|
||||||
borderRadius: BorderRadius.circular(8),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
),
|
||||||
child: Icon(Icons.confirmation_number_rounded,
|
child: Icon(Icons.confirmation_number_rounded,
|
||||||
color: primaryColor, size: 18),
|
color: cs.primary, size: 18),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 10),
|
const SizedBox(width: 10),
|
||||||
Column(
|
Column(
|
||||||
@@ -582,13 +582,13 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
|
|||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 15,
|
fontSize: 15,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
color: textPrimary),
|
color: cs.onSurface),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
'${ride.date} • ${ride.time}',
|
'${ride.date} • ${ride.time}',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: Colors.grey[500],
|
color: cs.onSurfaceVariant,
|
||||||
fontWeight: FontWeight.w600),
|
fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -672,7 +672,7 @@ class _RidesDashboardScreenState extends State<RidesDashboardScreen>
|
|||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: bgColor,
|
color:Colors.white,
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
|
|||||||
@@ -8,13 +8,13 @@ class ServerMonitorPage extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final controller = Get.put(ServerMonitorController());
|
final controller = Get.put(ServerMonitorController());
|
||||||
final themeColor = const Color(0xFF6366F1);
|
final cs = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: const Color(0xFF0A0E27),
|
backgroundColor: cs.surface,
|
||||||
body: RefreshIndicator(
|
body: RefreshIndicator(
|
||||||
onRefresh: controller.fetchServerData,
|
onRefresh: controller.fetchServerData,
|
||||||
color: themeColor,
|
color: cs.primary,
|
||||||
backgroundColor: const Color(0xFF1A1F3A),
|
backgroundColor: const Color(0xFF1A1F3A),
|
||||||
child: CustomScrollView(
|
child: CustomScrollView(
|
||||||
physics: const BouncingScrollPhysics(),
|
physics: const BouncingScrollPhysics(),
|
||||||
@@ -24,23 +24,23 @@ class ServerMonitorPage extends StatelessWidget {
|
|||||||
expandedHeight: 100,
|
expandedHeight: 100,
|
||||||
floating: true,
|
floating: true,
|
||||||
pinned: true,
|
pinned: true,
|
||||||
backgroundColor: const Color(0xFF0A0E27),
|
backgroundColor: cs.surface,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
flexibleSpace: FlexibleSpaceBar(
|
flexibleSpace: FlexibleSpaceBar(
|
||||||
titlePadding: const EdgeInsets.only(bottom: 16),
|
titlePadding: const EdgeInsets.only(bottom: 16),
|
||||||
title: Row(
|
title: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.dns_rounded,
|
Icon(Icons.dns_rounded,
|
||||||
color: Colors.white, size: 20),
|
color: cs.onSurface, size: 20),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
const Text(
|
Text(
|
||||||
'Server Monitor',
|
'Server Monitor',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 18,
|
fontSize: 18,
|
||||||
color: Colors.white,
|
color: cs.onSurface,
|
||||||
fontFamily: 'Segoe UI', // أو أي خط تفضله
|
fontFamily: 'Segoe UI',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -52,15 +52,15 @@ class ServerMonitorPage extends StatelessWidget {
|
|||||||
begin: Alignment.topCenter,
|
begin: Alignment.topCenter,
|
||||||
end: Alignment.bottomCenter,
|
end: Alignment.bottomCenter,
|
||||||
colors: [
|
colors: [
|
||||||
themeColor.withOpacity(0.3),
|
cs.primary.withValues(alpha: 0.3),
|
||||||
const Color(0xFF0A0E27),
|
cs.surface,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
actions: [
|
actions: [
|
||||||
_buildRefreshButton(controller),
|
_buildRefreshButton(controller, cs),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|
||||||
@@ -85,7 +85,7 @@ class ServerMonitorPage extends StatelessWidget {
|
|||||||
child: ConstrainedBox(
|
child: ConstrainedBox(
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
maxWidth:
|
maxWidth:
|
||||||
1000), // لمنع التمدد الزائد في الشاشات الكبيرة
|
1000),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
@@ -125,7 +125,7 @@ class ServerMonitorPage extends StatelessWidget {
|
|||||||
child: _TopProcessesCard(
|
child: _TopProcessesCard(
|
||||||
data: data,
|
data: data,
|
||||||
height:
|
height:
|
||||||
600), // ارتفاع ثابت في وضع الكمبيوتر
|
600),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@@ -139,7 +139,7 @@ class ServerMonitorPage extends StatelessWidget {
|
|||||||
_StorageNetworkCard(data: data),
|
_StorageNetworkCard(data: data),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_TopProcessesCard(
|
_TopProcessesCard(
|
||||||
data: data), // ارتفاع ديناميكي
|
data: data),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -159,22 +159,22 @@ class ServerMonitorPage extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildRefreshButton(ServerMonitorController controller) {
|
Widget _buildRefreshButton(ServerMonitorController controller, ColorScheme cs) {
|
||||||
return Obx(() => Container(
|
return Obx(() => Container(
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white.withOpacity(0.1),
|
color: cs.onSurface.withValues(alpha: 0.1),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: IconButton(
|
child: IconButton(
|
||||||
icon: controller.isLoading.value
|
icon: controller.isLoading.value
|
||||||
? const SizedBox(
|
? SizedBox(
|
||||||
width: 20,
|
width: 20,
|
||||||
height: 20,
|
height: 20,
|
||||||
child: CircularProgressIndicator(
|
child: CircularProgressIndicator(
|
||||||
strokeWidth: 2, color: Colors.white),
|
strokeWidth: 2, color: cs.onSurface),
|
||||||
)
|
)
|
||||||
: const Icon(Icons.refresh_rounded, color: Colors.white),
|
: Icon(Icons.refresh_rounded, color: cs.onSurface),
|
||||||
onPressed: controller.fetchServerData,
|
onPressed: controller.fetchServerData,
|
||||||
),
|
),
|
||||||
));
|
));
|
||||||
@@ -219,18 +219,19 @@ class _HeaderInfo extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
padding: const EdgeInsets.symmetric(vertical: 12, horizontal: 16),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white.withOpacity(0.05),
|
color: cs.onSurface.withValues(alpha: 0.05),
|
||||||
borderRadius: BorderRadius.circular(50),
|
borderRadius: BorderRadius.circular(50),
|
||||||
border: Border.all(color: Colors.white.withOpacity(0.1)),
|
border: Border.all(color: cs.onSurface.withValues(alpha: 0.1)),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Icon(Icons.timer_outlined,
|
Icon(Icons.timer_outlined,
|
||||||
size: 16, color: Colors.greenAccent.withOpacity(0.8)),
|
size: 16, color: Colors.greenAccent.withValues(alpha: 0.8)),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
"Uptime: ${data.uptime.formatted}",
|
"Uptime: ${data.uptime.formatted}",
|
||||||
@@ -245,7 +246,7 @@ class _HeaderInfo extends StatelessWidget {
|
|||||||
color: Colors.white24,
|
color: Colors.white24,
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 12)),
|
margin: const EdgeInsets.symmetric(horizontal: 12)),
|
||||||
Icon(Icons.update,
|
Icon(Icons.update,
|
||||||
size: 16, color: Colors.blueAccent.withOpacity(0.8)),
|
size: 16, color: Colors.blueAccent.withValues(alpha: 0.8)),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Text(
|
Text(
|
||||||
"Last Update: ${data.timestamp.split(' ')[1]}",
|
"Last Update: ${data.timestamp.split(' ')[1]}",
|
||||||
@@ -276,18 +277,19 @@ class _MetricCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
gradient: LinearGradient(
|
gradient: LinearGradient(
|
||||||
begin: Alignment.topLeft,
|
begin: Alignment.topLeft,
|
||||||
end: Alignment.bottomRight,
|
end: Alignment.bottomRight,
|
||||||
colors: [color.withOpacity(0.9), color.withOpacity(0.6)],
|
colors: [color.withValues(alpha: 0.9), color.withValues(alpha: 0.6)],
|
||||||
),
|
),
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
color: color.withOpacity(0.3),
|
color: color.withValues(alpha: 0.3),
|
||||||
blurRadius: 12,
|
blurRadius: 12,
|
||||||
offset: const Offset(0, 8),
|
offset: const Offset(0, 8),
|
||||||
),
|
),
|
||||||
@@ -302,15 +304,15 @@ class _MetricCard extends StatelessWidget {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(10),
|
padding: const EdgeInsets.all(10),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white.withOpacity(0.2),
|
color: cs.onSurface.withValues(alpha: 0.2),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Icon(icon, color: Colors.white, size: 24),
|
child: Icon(icon, color: cs.onSurface, size: 24),
|
||||||
),
|
),
|
||||||
Text(
|
Text(
|
||||||
value,
|
value,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: cs.onSurface,
|
||||||
fontSize: 28,
|
fontSize: 28,
|
||||||
fontWeight: FontWeight.bold),
|
fontWeight: FontWeight.bold),
|
||||||
),
|
),
|
||||||
@@ -321,8 +323,8 @@ class _MetricCard extends StatelessWidget {
|
|||||||
style: const TextStyle(color: Colors.white70, fontSize: 14)),
|
style: const TextStyle(color: Colors.white70, fontSize: 14)),
|
||||||
const SizedBox(height: 4),
|
const SizedBox(height: 4),
|
||||||
Text(subtitle,
|
Text(subtitle,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: cs.onSurface,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.w600)),
|
fontWeight: FontWeight.w600)),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
@@ -332,7 +334,7 @@ class _MetricCard extends StatelessWidget {
|
|||||||
value: percent / 100,
|
value: percent / 100,
|
||||||
minHeight: 6,
|
minHeight: 6,
|
||||||
backgroundColor: Colors.black12,
|
backgroundColor: Colors.black12,
|
||||||
valueColor: const AlwaysStoppedAnimation(Colors.white),
|
valueColor: AlwaysStoppedAnimation(cs.onSurface),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -347,6 +349,7 @@ class _ServicesCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
return _BaseCard(
|
return _BaseCard(
|
||||||
title: "حالة الخدمات",
|
title: "حالة الخدمات",
|
||||||
icon: Icons.security,
|
icon: Icons.security,
|
||||||
@@ -362,8 +365,8 @@ class _ServicesCard extends StatelessWidget {
|
|||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: isActive
|
color: isActive
|
||||||
? Colors.green.withOpacity(0.3)
|
? const Color(0xFF10B981).withValues(alpha: 0.3)
|
||||||
: Colors.red.withOpacity(0.3),
|
: cs.error.withValues(alpha: 0.3),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -377,8 +380,8 @@ class _ServicesCard extends StatelessWidget {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Text(
|
child: Text(
|
||||||
e.key.toUpperCase(),
|
e.key.toUpperCase(),
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white, fontWeight: FontWeight.w600),
|
color: cs.onSurface, fontWeight: FontWeight.w600),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Container(
|
Container(
|
||||||
@@ -386,8 +389,8 @@ class _ServicesCard extends StatelessWidget {
|
|||||||
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: isActive
|
color: isActive
|
||||||
? Colors.green.withOpacity(0.1)
|
? const Color(0xFF10B981).withValues(alpha: 0.1)
|
||||||
: Colors.red.withOpacity(0.1),
|
: cs.error.withValues(alpha: 0.1),
|
||||||
borderRadius: BorderRadius.circular(6),
|
borderRadius: BorderRadius.circular(6),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -414,6 +417,7 @@ class _StorageNetworkCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
return _BaseCard(
|
return _BaseCard(
|
||||||
title: "التخزين والشبكة",
|
title: "التخزين والشبكة",
|
||||||
icon: Icons.cloud_queue_rounded,
|
icon: Icons.cloud_queue_rounded,
|
||||||
@@ -421,19 +425,19 @@ class _StorageNetworkCard extends StatelessWidget {
|
|||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
_buildRowItem(Icons.pie_chart_outline, "Storage",
|
_buildRowItem(Icons.pie_chart_outline, "Storage",
|
||||||
"${data.disk.percent}%", "${data.disk.usedGb} GB Used"),
|
"${data.disk.percent}%", "${data.disk.usedGb} GB Used", cs),
|
||||||
const Divider(color: Colors.white10, height: 24),
|
const Divider(color: Colors.white10, height: 24),
|
||||||
_buildRowItem(Icons.download_rounded, "Download",
|
_buildRowItem(Icons.download_rounded, "Download",
|
||||||
"${data.network.receivedMb} MB", "In"),
|
"${data.network.receivedMb} MB", "In", cs),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
_buildRowItem(Icons.upload_rounded, "Upload",
|
_buildRowItem(Icons.upload_rounded, "Upload",
|
||||||
"${data.network.sentMb} MB", "Out"),
|
"${data.network.sentMb} MB", "Out", cs),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildRowItem(IconData icon, String label, String value, String sub) {
|
Widget _buildRowItem(IconData icon, String label, String value, String sub, ColorScheme cs) {
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(icon, color: Colors.white54, size: 20),
|
Icon(icon, color: Colors.white54, size: 20),
|
||||||
@@ -445,13 +449,13 @@ class _StorageNetworkCard extends StatelessWidget {
|
|||||||
style: const TextStyle(color: Colors.white60, fontSize: 12)),
|
style: const TextStyle(color: Colors.white60, fontSize: 12)),
|
||||||
Text(sub,
|
Text(sub,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white.withOpacity(0.4), fontSize: 10)),
|
color: cs.onSurface.withValues(alpha: 0.4), fontSize: 10)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
const Spacer(),
|
const Spacer(),
|
||||||
Text(value,
|
Text(value,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: cs.onSurface,
|
||||||
fontWeight: FontWeight.bold,
|
fontWeight: FontWeight.bold,
|
||||||
fontSize: 16)),
|
fontSize: 16)),
|
||||||
],
|
],
|
||||||
@@ -466,12 +470,13 @@ class _TopProcessesCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
return Container(
|
return Container(
|
||||||
height: height, // إذا كان null سيأخذ الارتفاع بناءً على المحتوى
|
height: height,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFF1A1F3A),
|
color: const Color(0xFF1A1F3A),
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
border: Border.all(color: Colors.white.withOpacity(0.05)),
|
border: Border.all(color: cs.onSurface.withValues(alpha: 0.05)),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -483,31 +488,30 @@ class _TopProcessesCard extends StatelessWidget {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.orange.withOpacity(0.1),
|
color: Colors.orange.withValues(alpha: 0.1),
|
||||||
borderRadius: BorderRadius.circular(8)),
|
borderRadius: BorderRadius.circular(8)),
|
||||||
child: const Icon(Icons.analytics_rounded,
|
child: const Icon(Icons.analytics_rounded,
|
||||||
color: Colors.orange, size: 18),
|
color: Colors.orange, size: 18),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
const Text("Top Processes",
|
Text("Top Processes",
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: cs.onSurface,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold)),
|
fontWeight: FontWeight.bold)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Divider(height: 1, color: Colors.white10),
|
const Divider(height: 1, color: Colors.white10),
|
||||||
// نستخدم ListView.builder داخل Expanded إذا كان هناك ارتفاع محدد، وإلا Column للموبايل
|
|
||||||
height != null
|
height != null
|
||||||
? Expanded(child: _buildList())
|
? Expanded(child: _buildList(cs: cs))
|
||||||
: _buildList(shrinkWrap: true),
|
: _buildList(shrinkWrap: true, cs: cs),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildList({bool shrinkWrap = false}) {
|
Widget _buildList({bool shrinkWrap = false, required ColorScheme cs}) {
|
||||||
return ListView.separated(
|
return ListView.separated(
|
||||||
padding: const EdgeInsets.all(16),
|
padding: const EdgeInsets.all(16),
|
||||||
physics: shrinkWrap
|
physics: shrinkWrap
|
||||||
@@ -521,7 +525,7 @@ class _TopProcessesCard extends StatelessWidget {
|
|||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.white.withOpacity(0.03),
|
color: cs.onSurface.withValues(alpha: 0.03),
|
||||||
borderRadius: BorderRadius.circular(12),
|
borderRadius: BorderRadius.circular(12),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: Row(
|
||||||
@@ -535,8 +539,8 @@ class _TopProcessesCard extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
Text(process.name,
|
Text(process.name,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white, fontWeight: FontWeight.w500),
|
color: cs.onSurface, fontWeight: FontWeight.w500),
|
||||||
overflow: TextOverflow.ellipsis),
|
overflow: TextOverflow.ellipsis),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -545,7 +549,7 @@ class _TopProcessesCard extends StatelessWidget {
|
|||||||
padding:
|
padding:
|
||||||
const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Colors.orange.withOpacity(0.1),
|
color: Colors.orange.withValues(alpha: 0.1),
|
||||||
borderRadius: BorderRadius.circular(20),
|
borderRadius: BorderRadius.circular(20),
|
||||||
),
|
),
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -579,13 +583,14 @@ class _BaseCard extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
padding: const EdgeInsets.all(20),
|
padding: const EdgeInsets.all(20),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: const Color(0xFF1A1F3A),
|
color: const Color(0xFF1A1F3A),
|
||||||
borderRadius: BorderRadius.circular(24),
|
borderRadius: BorderRadius.circular(24),
|
||||||
border: Border.all(color: Colors.white.withOpacity(0.05)),
|
border: Border.all(color: cs.onSurface.withValues(alpha: 0.05)),
|
||||||
),
|
),
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
@@ -595,14 +600,14 @@ class _BaseCard extends StatelessWidget {
|
|||||||
Container(
|
Container(
|
||||||
padding: const EdgeInsets.all(8),
|
padding: const EdgeInsets.all(8),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: iconColor.withOpacity(0.1),
|
color: iconColor.withValues(alpha: 0.1),
|
||||||
borderRadius: BorderRadius.circular(8)),
|
borderRadius: BorderRadius.circular(8)),
|
||||||
child: Icon(icon, color: iconColor, size: 18),
|
child: Icon(icon, color: iconColor, size: 18),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 12),
|
const SizedBox(width: 12),
|
||||||
Text(title,
|
Text(title,
|
||||||
style: const TextStyle(
|
style: TextStyle(
|
||||||
color: Colors.white,
|
color: cs.onSurface,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
fontWeight: FontWeight.bold)),
|
fontWeight: FontWeight.bold)),
|
||||||
],
|
],
|
||||||
@@ -620,14 +625,15 @@ class _LoadingState extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
return Center(
|
return Center(
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
const CircularProgressIndicator(color: Color(0xFF6366F1)),
|
CircularProgressIndicator(color: cs.primary),
|
||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text("Connecting to server...",
|
Text("Connecting to server...",
|
||||||
style: TextStyle(color: Colors.white.withOpacity(0.5))),
|
style: TextStyle(color: cs.onSurface.withValues(alpha: 0.5))),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -640,6 +646,7 @@ class _ErrorState extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final cs = Theme.of(context).colorScheme;
|
||||||
return Center(
|
return Center(
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(20.0),
|
padding: const EdgeInsets.all(20.0),
|
||||||
@@ -651,12 +658,12 @@ class _ErrorState extends StatelessWidget {
|
|||||||
const SizedBox(height: 16),
|
const SizedBox(height: 16),
|
||||||
Text(controller.errorMessage.value,
|
Text(controller.errorMessage.value,
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
style: const TextStyle(color: Colors.white)),
|
style: TextStyle(color: cs.onSurface)),
|
||||||
const SizedBox(height: 24),
|
const SizedBox(height: 24),
|
||||||
ElevatedButton(
|
ElevatedButton(
|
||||||
onPressed: controller.fetchServerData,
|
onPressed: controller.fetchServerData,
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
backgroundColor: const Color(0xFF6366F1),
|
backgroundColor: cs.primary,
|
||||||
shape: const StadiumBorder(),
|
shape: const StadiumBorder(),
|
||||||
),
|
),
|
||||||
child: const Text("Try Again"),
|
child: const Text("Try Again"),
|
||||||
|
|||||||
@@ -14,12 +14,31 @@ class AddStaffPage extends StatelessWidget {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: cs.surface,
|
backgroundColor: cs.surface,
|
||||||
appBar: AppBar(
|
body: Column(
|
||||||
title: Text(role == 'admin' ? "إضافة مدير جديد" : "إضافة موظف خدمة عملاء"),
|
children: [
|
||||||
backgroundColor: cs.surface,
|
Container(
|
||||||
elevation: 0,
|
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
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),
|
||||||
),
|
),
|
||||||
body: SingleChildScrollView(
|
child: Icon(Icons.arrow_back_ios_new_rounded, color: cs.onSurfaceVariant, size: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text(role == 'admin' ? "إضافة مدير جديد" : "إضافة موظف خدمة عملاء", style: TextStyle(color: cs.onSurface, fontSize: 18, fontWeight: FontWeight.w700)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: SingleChildScrollView(
|
||||||
padding: const EdgeInsets.all(24),
|
padding: const EdgeInsets.all(24),
|
||||||
child: Form(
|
child: Form(
|
||||||
key: controller.formKey,
|
key: controller.formKey,
|
||||||
@@ -120,6 +139,9 @@ class AddStaffPage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import '../../../constant/links.dart';
|
import '../../../constant/links.dart';
|
||||||
import '../../../controller/functions/crud.dart';
|
import '../../../controller/functions/crud.dart';
|
||||||
import '../../widgets/snackbar.dart';
|
import '../../widgets/snackbar.dart';
|
||||||
@@ -63,16 +64,38 @@ class _PendingAdminsPageState extends State<PendingAdminsPage> {
|
|||||||
|
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
backgroundColor: cs.surface,
|
backgroundColor: cs.surface,
|
||||||
appBar: AppBar(
|
body: Column(
|
||||||
title: const Text('طلبات الانضمام المعلقة', style: TextStyle(fontWeight: FontWeight.bold)),
|
children: [
|
||||||
backgroundColor: cs.surfaceContainerHighest,
|
Container(
|
||||||
elevation: 0,
|
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
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),
|
||||||
),
|
),
|
||||||
body: _isLoading
|
child: Icon(Icons.arrow_back_ios_new_rounded, color: cs.onSurfaceVariant, size: 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Text('طلبات الانضمام المعلقة', style: TextStyle(color: cs.onSurface, fontSize: 18, fontWeight: FontWeight.w700)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: _isLoading
|
||||||
? Center(child: CircularProgressIndicator(color: cs.primary))
|
? Center(child: CircularProgressIndicator(color: cs.primary))
|
||||||
: _pendingAdmins.isEmpty
|
: _pendingAdmins.isEmpty
|
||||||
? _buildEmptyState(cs)
|
? _buildEmptyState(cs)
|
||||||
: _buildList(cs),
|
: _buildList(cs),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,13 +30,27 @@ class _TransitOrgListPageState extends State<TransitOrgListPage> {
|
|||||||
return GetBuilder<TransitAdminController>(
|
return GetBuilder<TransitAdminController>(
|
||||||
builder: (c) => Scaffold(
|
builder: (c) => Scaffold(
|
||||||
backgroundColor: cs.surface,
|
backgroundColor: cs.surface,
|
||||||
appBar: AppBar(
|
body: Column(
|
||||||
backgroundColor: cs.surface,
|
children: [
|
||||||
elevation: 0,
|
Container(
|
||||||
title: Text('مواصلاتي — المؤسسات',
|
padding: const EdgeInsets.fromLTRB(16, 50, 16, 16),
|
||||||
style: TextStyle(color: cs.onSurface)),
|
child: Row(
|
||||||
iconTheme: IconThemeData(color: cs.onSurface),
|
children: [
|
||||||
actions: [
|
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),
|
||||||
|
Text('مواصلاتي — المؤسسات', style: TextStyle(color: cs.onSurface, fontSize: 18, fontWeight: FontWeight.w700)),
|
||||||
|
const Spacer(),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: Icon(Icons.route_rounded, color: cs.tertiary),
|
icon: Icon(Icons.route_rounded, color: cs.tertiary),
|
||||||
tooltip: 'اعتماد الخطوط',
|
tooltip: 'اعتماد الخطوط',
|
||||||
@@ -51,7 +65,9 @@ class _TransitOrgListPageState extends State<TransitOrgListPage> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
body: Column(
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(12),
|
padding: const EdgeInsets.all(12),
|
||||||
@@ -95,6 +111,9 @@ class _TransitOrgListPageState extends State<TransitOrgListPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -39,7 +39,6 @@ class WebSidebar extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final cs = Theme.of(context).colorScheme;
|
final cs = Theme.of(context).colorScheme;
|
||||||
final isDark = Theme.of(context).brightness == Brightness.dark;
|
|
||||||
final String myPhone = box.read(BoxName.adminPhone)?.toString() ?? '';
|
final String myPhone = box.read(BoxName.adminPhone)?.toString() ?? '';
|
||||||
final String role = box.read('admin_role')?.toString() ?? 'admin';
|
final String role = box.read('admin_role')?.toString() ?? 'admin';
|
||||||
final bool isSuperAdmin = (role == 'super_admin') ||
|
final bool isSuperAdmin = (role == 'super_admin') ||
|
||||||
|
|||||||
@@ -892,10 +892,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: matcher
|
name: matcher
|
||||||
sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6"
|
sha256: dc0b7dc7651697ea4ff3e69ef44b0407ea32c487a39fff6a4004fa585e901861
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.12.18"
|
version: "0.12.19"
|
||||||
material_color_utilities:
|
material_color_utilities:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -908,10 +908,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: meta
|
name: meta
|
||||||
sha256: "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394"
|
sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.17.0"
|
version: "1.18.0"
|
||||||
mgrs_dart:
|
mgrs_dart:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1232,10 +1232,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: test_api
|
name: test_api
|
||||||
sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636"
|
sha256: "949a932224383300f01be9221c39180316445ecb8e7547f70a41a35bf421fb9e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "0.7.9"
|
version: "0.7.11"
|
||||||
typed_data:
|
typed_data:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
@@ -1413,5 +1413,5 @@ packages:
|
|||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.3"
|
version: "3.1.3"
|
||||||
sdks:
|
sdks:
|
||||||
dart: ">=3.9.0-0 <4.0.0"
|
dart: ">=3.10.0-0 <4.0.0"
|
||||||
flutter: ">=3.32.0"
|
flutter: ">=3.32.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user