Files
tripz-llc/dashboards/admin/lib/constant/theme.dart
T
Hamza-AyedandClaude Opus 5 4d8414c96b feat: استيراد كود سيرو إلى تريبز (سيرو @ecfe7568) — بلا تعديل
قرار المالك 2026-07-27: باك إند سيرو PHP هو المعتمد، وتطبيقاته المجرّبة
ميدانياً تحل محل إعادة البناء المؤرشفة. سيرو نفسه لم يُمسّ.

الخريطة:
  backend · payment_server · loction_server · ride_server ·
  passenger_server · docker · dashboard · stress_test  → الجذر
  siro_rider  → apps/rider          siro_driver  → apps/driver
  siro_admin  → dashboards/admin    siro_service → dashboards/service
  android_bot → apps/android_bot    socialBot    → apps/socialBot

نُسخ المتعقَّب في git سيرو فقط عبر `git archive` (3,198 ملفاً / ~169 م.ب)
لا `cp -r` — فاستُثنيت مخلفات البناء تلقائياً. بلا أي تعديل محتوى عمداً:
كل ما يلي يصير فرقاً مقروءاً مقابل المصدر.

لم يُستورد وسببه: siromove.com (الموقع التسويقي يبقى marketing/ في تريبز،
سيرو فيه 8 ملفات) · docs و planning (تريبز له docs/ الخاص) · deploy.sh
(ليس نشراً على سيرفر بل `git add . && git push origin --all` — فخّ في
مستودع آخر) · transit_dashboard (بانتظار قرار مصير backend-transit و
dashboards/transit-web).

⚠️ لا يبني بعد — ثلاثة نواقص متوقعة ومقصودة:
1. `.env` و `lib/env/env.g.dart` غير متعقَّبين في سيرو (أسرار لكل مستأجر):
   كل تطبيق فلاتر يحتاج .env خاصاً ثم توليد env.g.dart بـ build_runner.
2. إعدادات Firebase (9 ملفات google-services.json و GoogleService-Info.plist)
   يستبعدها .gitignore تريبز — ولكل مستأجر مشروع Firebase خاص أصلاً.
3. apps/driver في سيرو يشير إلى `../../Intaleq/packages/get` خارج المستودع →
   يجب ضمّ الحزم داخله أسوة بـ apps/rider.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 05:14:13 +03:00

609 lines
21 KiB
Dart

import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import 'colors.dart';
class AppTheme {
AppTheme._();
// ─── Dark Theme (Premium SaaS) ─────────────────────────────────────────────
static ThemeData get darkTheme {
final darkScheme = ColorScheme.dark(
brightness: Brightness.dark,
primary: AppColor.accent,
onPrimary: Colors.white,
primaryContainer: AppColor.accentSoft,
onPrimaryContainer: AppColor.accent,
secondary: AppColor.glow,
onSecondary: Colors.white,
secondaryContainer: const Color(0x26818CF8),
onSecondaryContainer: AppColor.glow,
tertiary: AppColor.info,
onTertiary: Colors.white,
surface: AppColor.surface,
onSurface: AppColor.textPrimary,
onSurfaceVariant: AppColor.textSecondary,
error: AppColor.danger,
onError: Colors.white,
errorContainer: AppColor.dangerSoft,
onErrorContainer: AppColor.danger,
outline: AppColor.divider,
outlineVariant: const Color(0xFF3D3D42),
shadow: Colors.black,
scrim: Colors.black54,
inverseSurface: AppColor.textPrimary,
onInverseSurface: AppColor.bg,
inversePrimary: AppColor.glow,
);
return ThemeData(
useMaterial3: true,
brightness: Brightness.dark,
fontFamily: GoogleFonts.tajawal().fontFamily,
scaffoldBackgroundColor: AppColor.bg,
colorScheme: darkScheme,
dividerColor: AppColor.divider,
dividerTheme: const DividerThemeData(
color: AppColor.divider,
thickness: 1,
space: 1,
),
appBarTheme: AppBarTheme(
backgroundColor: AppColor.bg,
elevation: 0,
scrolledUnderElevation: 0,
centerTitle: true,
titleTextStyle: GoogleFonts.tajawal(
color: AppColor.textPrimary,
fontSize: 18,
fontWeight: FontWeight.bold,
),
iconTheme: const IconThemeData(color: AppColor.textPrimary),
),
cardTheme: CardThemeData(
color: AppColor.surface,
elevation: 0,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: const BorderSide(color: AppColor.divider, width: 1),
),
),
dialogTheme: DialogThemeData(
backgroundColor: AppColor.surface,
elevation: 24,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
side: const BorderSide(color: AppColor.divider, width: 1),
),
titleTextStyle: GoogleFonts.tajawal(
color: AppColor.textPrimary,
fontSize: 18,
fontWeight: FontWeight.bold,
),
contentTextStyle: GoogleFonts.tajawal(
color: AppColor.textSecondary,
fontSize: 14,
),
),
bottomSheetTheme: const BottomSheetThemeData(
backgroundColor: AppColor.surface,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
),
snackBarTheme: SnackBarThemeData(
backgroundColor: AppColor.surfaceElevated,
contentTextStyle: GoogleFonts.tajawal(
color: AppColor.textPrimary,
fontSize: 14,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
behavior: SnackBarBehavior.floating,
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: AppColor.surfaceElevated,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: AppColor.accent, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: AppColor.danger, width: 1),
),
labelStyle: const TextStyle(color: AppColor.textSecondary),
hintStyle: const TextStyle(color: AppColor.textMuted),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: AppColor.accent,
foregroundColor: Colors.white,
elevation: 0,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
textStyle: GoogleFonts.tajawal(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: AppColor.textPrimary,
side: const BorderSide(color: AppColor.divider),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
textStyle: GoogleFonts.tajawal(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: AppColor.accent,
textStyle: GoogleFonts.tajawal(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
switchTheme: SwitchThemeData(
thumbColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) return AppColor.success;
return AppColor.textMuted;
}),
trackColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) return AppColor.successSoft;
return AppColor.surfaceElevated;
}),
),
popupMenuTheme: PopupMenuThemeData(
color: AppColor.surface,
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: const BorderSide(color: AppColor.divider),
),
),
tooltipTheme: TooltipThemeData(
decoration: BoxDecoration(
color: AppColor.surfaceElevated,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: AppColor.divider),
),
textStyle: GoogleFonts.tajawal(
color: AppColor.textPrimary,
fontSize: 12,
),
),
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: AppColor.accent,
foregroundColor: Colors.white,
elevation: 4,
),
progressIndicatorTheme: const ProgressIndicatorThemeData(
color: AppColor.accent,
linearTrackColor: AppColor.surfaceElevated,
),
tabBarTheme: TabBarThemeData(
labelColor: AppColor.accent,
unselectedLabelColor: AppColor.textSecondary,
indicatorColor: AppColor.accent,
dividerColor: AppColor.divider,
),
chipTheme: ChipThemeData(
backgroundColor: AppColor.surfaceElevated,
labelStyle: GoogleFonts.tajawal(color: AppColor.textPrimary, fontSize: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: const BorderSide(color: AppColor.divider),
),
),
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.windows: const FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.macOS: const FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.linux: const FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.fuchsia: const FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.android: const FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.iOS: const FadeUpwardsPageTransitionsBuilder(),
},
),
);
}
// ─── Light Theme (Premium SaaS) ────────────────────────────────────────────
static ThemeData get lightTheme {
const bgLight = Color(0xFFF8F9FC);
const surfaceLight = Color(0xFFFFFFFF);
const surfaceElevatedLight = Color(0xFFF1F3F9);
const dividerLight = Color(0xFFE2E5ED);
const textPrimaryLight = Color(0xFF111827);
const textSecondaryLight = Color(0xFF6B7280);
const textMutedLight = Color(0xFF9CA3AF);
const accentLight = Color(0xFF6366F1);
const accentSoftLight = Color(0x1A6366F1);
const glowLight = Color(0xFF4F46E5);
const dangerLight = Color(0xFFDC2626);
const dangerSoftLight = Color(0x1ADC2626);
const successLight = Color(0xFF059669);
const successSoftLight = Color(0x1A059669);
const infoLight = Color(0xFF2563EB);
final lightScheme = ColorScheme.light(
brightness: Brightness.light,
primary: accentLight,
onPrimary: Colors.white,
primaryContainer: accentSoftLight,
onPrimaryContainer: accentLight,
secondary: glowLight,
onSecondary: Colors.white,
secondaryContainer: const Color(0x1A4F46E5),
onSecondaryContainer: glowLight,
tertiary: infoLight,
onTertiary: Colors.white,
surface: surfaceLight,
onSurface: textPrimaryLight,
onSurfaceVariant: textSecondaryLight,
error: dangerLight,
onError: Colors.white,
errorContainer: dangerSoftLight,
onErrorContainer: dangerLight,
outline: dividerLight,
outlineVariant: const Color(0xFFD1D5DB),
shadow: Colors.black26,
scrim: Colors.black38,
inverseSurface: textPrimaryLight,
onInverseSurface: surfaceLight,
inversePrimary: const Color(0xFFC7D2FE),
);
return ThemeData(
useMaterial3: true,
brightness: Brightness.light,
fontFamily: GoogleFonts.tajawal().fontFamily,
scaffoldBackgroundColor: bgLight,
colorScheme: lightScheme,
dividerColor: dividerLight,
dividerTheme: const DividerThemeData(
color: dividerLight,
thickness: 1,
space: 1,
),
appBarTheme: AppBarTheme(
backgroundColor: bgLight,
elevation: 0,
scrolledUnderElevation: 0,
centerTitle: true,
titleTextStyle: GoogleFonts.tajawal(
color: textPrimaryLight,
fontSize: 18,
fontWeight: FontWeight.bold,
),
iconTheme: const IconThemeData(color: textPrimaryLight),
),
cardTheme: CardThemeData(
color: surfaceLight,
elevation: 0,
margin: EdgeInsets.zero,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(16),
side: const BorderSide(color: dividerLight, width: 1),
),
),
dialogTheme: DialogThemeData(
backgroundColor: surfaceLight,
elevation: 24,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20),
side: const BorderSide(color: dividerLight, width: 1),
),
titleTextStyle: GoogleFonts.tajawal(
color: textPrimaryLight,
fontSize: 18,
fontWeight: FontWeight.bold,
),
contentTextStyle: GoogleFonts.tajawal(
color: textSecondaryLight,
fontSize: 14,
),
),
bottomSheetTheme: const BottomSheetThemeData(
backgroundColor: surfaceLight,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(top: Radius.circular(20)),
),
),
snackBarTheme: SnackBarThemeData(
backgroundColor: surfaceElevatedLight,
contentTextStyle: GoogleFonts.tajawal(
color: textPrimaryLight,
fontSize: 14,
),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
behavior: SnackBarBehavior.floating,
),
inputDecorationTheme: InputDecorationTheme(
filled: true,
fillColor: surfaceElevatedLight,
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
enabledBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: BorderSide.none,
),
focusedBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: accentLight, width: 1.5),
),
errorBorder: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: dangerLight, width: 1),
),
labelStyle: const TextStyle(color: textSecondaryLight),
hintStyle: const TextStyle(color: textMutedLight),
contentPadding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
),
elevatedButtonTheme: ElevatedButtonThemeData(
style: ElevatedButton.styleFrom(
backgroundColor: accentLight,
foregroundColor: Colors.white,
elevation: 0,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
textStyle: GoogleFonts.tajawal(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: OutlinedButton.styleFrom(
foregroundColor: textPrimaryLight,
side: const BorderSide(color: dividerLight),
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
),
textStyle: GoogleFonts.tajawal(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
textButtonTheme: TextButtonThemeData(
style: TextButton.styleFrom(
foregroundColor: accentLight,
textStyle: GoogleFonts.tajawal(
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
switchTheme: SwitchThemeData(
thumbColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) return successLight;
return textMutedLight;
}),
trackColor: WidgetStateProperty.resolveWith((states) {
if (states.contains(WidgetState.selected)) return successSoftLight;
return surfaceElevatedLight;
}),
),
popupMenuTheme: PopupMenuThemeData(
color: surfaceLight,
elevation: 8,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12),
side: const BorderSide(color: dividerLight),
),
),
tooltipTheme: TooltipThemeData(
decoration: BoxDecoration(
color: surfaceElevatedLight,
borderRadius: BorderRadius.circular(8),
border: Border.all(color: dividerLight),
),
textStyle: GoogleFonts.tajawal(
color: textPrimaryLight,
fontSize: 12,
),
),
floatingActionButtonTheme: const FloatingActionButtonThemeData(
backgroundColor: accentLight,
foregroundColor: Colors.white,
elevation: 4,
),
progressIndicatorTheme: const ProgressIndicatorThemeData(
color: accentLight,
linearTrackColor: surfaceElevatedLight,
),
tabBarTheme: TabBarThemeData(
labelColor: accentLight,
unselectedLabelColor: textSecondaryLight,
indicatorColor: accentLight,
dividerColor: dividerLight,
),
chipTheme: ChipThemeData(
backgroundColor: surfaceElevatedLight,
labelStyle: GoogleFonts.tajawal(color: textPrimaryLight, fontSize: 12),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
side: const BorderSide(color: dividerLight),
),
),
pageTransitionsTheme: PageTransitionsTheme(
builders: {
TargetPlatform.windows: const FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.macOS: const FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.linux: const FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.fuchsia: const FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.android: const FadeUpwardsPageTransitionsBuilder(),
TargetPlatform.iOS: const FadeUpwardsPageTransitionsBuilder(),
},
),
);
}
}
// ─── Context Extensions for Theme Access ──────────────────────────────────────
extension ThemeExtensions on BuildContext {
ColorScheme get colors => Theme.of(this).colorScheme;
TextTheme get textStyles => Theme.of(this).textTheme;
Brightness get brightness => Theme.of(this).brightness;
bool get isDark => brightness == Brightness.dark;
}
// ─── Semantic Color Getters (light/dark adaptive) ─────────────────────────────
// These replace direct AppColor.* usage in views. They automatically adapt
// based on the current theme brightness.
class AppColors {
AppColors._();
static Color bg(BuildContext context) => context.isDark
? const Color(0xFF0A0A0B)
: const Color(0xFFF8F9FC);
static Color surface(BuildContext context) => context.isDark
? const Color(0xFF161618)
: const Color(0xFFFFFFFF);
static Color surfaceElevated(BuildContext context) => context.isDark
? const Color(0xFF222225)
: const Color(0xFFF1F3F9);
static Color surfaceGlass(BuildContext context) => context.isDark
? const Color(0xCC161618)
: const Color(0xCCFFFFFF);
static Color accent(BuildContext context) => context.isDark
? const Color(0xFF6366F1)
: const Color(0xFF6366F1);
static Color accentSoft(BuildContext context) => context.isDark
? const Color(0x266366F1)
: const Color(0x1A6366F1);
static Color accentBorder(BuildContext context) => context.isDark
? const Color(0x4D6366F1)
: const Color(0x336366F1);
static Color glow(BuildContext context) => context.isDark
? const Color(0xFF818CF8)
: const Color(0xFF4F46E5);
static Color danger(BuildContext context) => context.isDark
? const Color(0xFFEF4444)
: const Color(0xFFDC2626);
static Color dangerSoft(BuildContext context) => context.isDark
? const Color(0x26EF4444)
: const Color(0x1ADC2626);
static Color success(BuildContext context) => context.isDark
? const Color(0xFF10B981)
: const Color(0xFF059669);
static Color successSoft(BuildContext context) => context.isDark
? const Color(0x2610B981)
: const Color(0x1A059669);
static Color warning(BuildContext context) => context.isDark
? const Color(0xFFF59E0B)
: const Color(0xFFD97706);
static Color warningSoft(BuildContext context) => context.isDark
? const Color(0x26F59E0B)
: const Color(0x1AD97706);
static Color info(BuildContext context) => context.isDark
? const Color(0xFF3B82F6)
: const Color(0xFF2563EB);
static Color infoSoft(BuildContext context) => context.isDark
? const Color(0x263B82F6)
: const Color(0x1A2563EB);
static Color textPrimary(BuildContext context) => context.isDark
? const Color(0xFFF3F4F6)
: const Color(0xFF111827);
static Color textSecondary(BuildContext context) => context.isDark
? const Color(0xFF9CA3AF)
: const Color(0xFF6B7280);
static Color textMuted(BuildContext context) => context.isDark
? const Color(0xFF6B7280)
: const Color(0xFF9CA3AF);
static Color divider(BuildContext context) => context.isDark
? const Color(0xFF2D2D30)
: const Color(0xFFE2E5ED);
static Color cardShadow(BuildContext context) => context.isDark
? const Color(0x66000000)
: const Color(0x0D000000);
// Gradient helpers for charts
static LinearGradient accentGradient(BuildContext context) => LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
accent(context).withValues(alpha: 0.4),
accent(context).withValues(alpha: 0.0),
],
);
static LinearGradient successGradient(BuildContext context) => LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
success(context).withValues(alpha: 0.4),
success(context).withValues(alpha: 0.0),
],
);
static LinearGradient dangerGradient(BuildContext context) => LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
danger(context).withValues(alpha: 0.4),
danger(context).withValues(alpha: 0.0),
],
);
static LinearGradient infoGradient(BuildContext context) => LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: [
info(context).withValues(alpha: 0.4),
info(context).withValues(alpha: 0.0),
],
);
}