الفصل التاسع: الواجهة والثيمات Chapter 09: UI Theming & Responsiveness

إزاي خلينا MRE CashBook جميل ومريح على كل الأجهزة والظروف.

🏛️ معمارية الجمال: كيف صممنا السيستم؟ The Architecture of Beauty

التصميم في MRE CashBook مش مجرد ألوان، هو "نظام" (Design System). بنعتمد فيه على 3 ركائز أساسية:

1

التجريد (Abstraction): الألوان مش مكتوبة هارد كود، هي معرفة في كلاسات خاصة.

2

السياق (Context): بنوصل للألوان من الـ Context بسهولة، وده بيضمن إن التصميم يتغير لحظياً لو قلبنا Dark Mode.

3

المرونة (Material 3): بنستخدم أحدث معايير جوجل في التصميم لضمان شكل مودرن وانسيابي.

⚙️ إدارة الثيمات (Theme Management) Deep Dive: AppTheme

كلاس AppTheme هو القلب النابض للتصميم. بيجمع بين الـ ColorScheme الأساسي والإضافات الخاصة بينا (Extensions).

lib/core/theme/app_theme.dart
final class AppTheme {
  // Light Mode Build
  static ThemeData get lightTheme => _build(Brightness.light, _lightExtension);

  // Dark Mode Build
  static ThemeData get darkTheme => _build(Brightness.dark, _darkExtension);

  static ThemeData _build(Brightness brightness, AppColorsExtension ext) {
    final ColorScheme cs = ColorScheme.fromSeed(
      seedColor: ext.primary,
      brightness: brightness,
    );
    // ... Returns ThemeData with full Material 3 configuration
  }
}
ColorScheme.fromSeed
إيه دي؟What is it?
ميزة في Material 3 بتاخد لون واحد وتعمل منه "لوحة ألوان" (Palette) كاملة متناسقة أوتوماتيك.A Material 3 feature that generates a full harmonious palette from a single seed color.
🎨 التلوين الدلالي (Semantic Coloring) AppColorsExtension: Functional Colors

في تطبيقات الحسابات، الألوان ليها معنى. الأخضر يعني "دخل" والأحمر يعني "خارج". عشان كدة ضفنا حقول مخصصة للثيم:

class AppColorsExtension extends ThemeExtension<AppColorsExtension> {
  final Color income;   // Emerald Green
  final Color expense;  // Coral Red
  final Color surfaceCard;
  final LinearGradient masterBalanceGradient;
  // ... copyWith and lerp logic
}

بالطريقة دي، لما نغير من Light لـ Dark، "الأخضر" بتاع الـ Income بيتغير لدرجة أهدى تناسب العين في الضلمة، والتغيير بيحصل بسلاسة (Interpolation) بفضل ميزة lerp.

إضافات السياق: وداعاً للتعقيد Context Extensions: Clean Access

مش منطقي نكتب Theme.of(context).extension<AppColorsExtension>()! في كل مكان. عشان كدة استخدمنا الـ Extensions:

lib/core/utils/extensions/context_extension.dart
extension BuildContextExtension on BuildContext {
  AppColorsExtension get colors => Theme.of(this).extension<AppColorsExtension>()!;
  TextTheme get textTheme => Theme.of(this).textTheme;
  ColorScheme get colorScheme => Theme.of(this).colorScheme;
}
context.colors.income
النتيجةOutcome
كود أقصر، أسرع في الكتابة، وأقل عرضة للأخطاء.Shorter code, faster writing, and fewer errors.
📱 الاستجابة الدقيقة (Micro-Responsiveness) Micro-Responsiveness: Beyond Mobile

التطبيق مش بس بيشتغل على الموبايل، هو بيغير "شخصيته" لما تفتحه على تابلت أو آيباد. استخدمنا ResponsiveLayout عشان نحقق ده:

lib/core/utils/responsive/responsive_layout.dart
class ResponsiveLayout extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return LayoutBuilder(
      builder: (context, constraints) {
        if (constraints.maxWidth > AppSizes.tabletBreakpoint) {
          return desktopBody;
        } else if (constraints.maxWidth >= AppSizes.mobileBreakpoint) {
          return tabletBody;
        } else {
          return mobileBody;
        }
      },
    );
  }
}

لاحظ استخدام AnimatedSwitcher في الكود الحقيقي؛ ده بيخلي الانتقال بين الموبايل والتابلت ناعم (Fade Transition) مش مجرد خبط لزق.

🎭 أغطية متغيرة (Adaptive Overlays) Morphing UI: Bottom Sheets vs. Dialogs

من أجمل الميزات في MRE CashBook هي الـ Modals. لو إنت على موبايل بتطلع من تحت (Bottom Sheet)، ولو على تابلت بتظهر في النص (Centered Dialog):

lib/core/utils/overlays/adaptive_dialogs.dart
static Future<T?> showAdaptiveModal<T>(BuildContext context, {required Widget child}) {
  if (ResponsiveLayout.isMobile(context)) {
    return _showMobileSheet(context, child: child);
  }
  return _showDesktopDialog(context, child: child);
}

ده بيوفر تجربة مستخدم (UX) ممتازة، لأن الـ Bottom Sheet مريحة للإيد الواحدة في الموبايل، بينما الـ Dialog أحسن في المساحات الكبيرة.

🌙 استراتيجية الوضع الليلي The Dark Side: Dark Mode Strategy

الوضع الليلي في MRE CashBook مش مجرد خلفية سودة. هو تبديل كامل لمجموعة الألوان عشان نحافظ على تباين النصوص (Accessibility).

1

التخزين: بنحفظ اختيار المستخدم (Light / Dark / System) في الـ SharedPreferences.

2

البث: الـ AppSettingsCubit بيبث الثيم المختار للتطبيق كله.

3

التفاعل: الـ MaterialApp بيستقبل الثيم ويحدث الواجهة فوراً.

main.dart
BlocBuilder<AppSettingsCubit, AppSettingsState>(
  builder: (context, state) {
    return MaterialApp(
      theme: AppTheme.lightTheme,
      darkTheme: AppTheme.darkTheme,
      themeMode: state.themeMode,
      // ...
    );
  },
)
🛠️ حل مشاكل الواجهة (UI Troubleshooting) Debugger's Guide: UI & Themes

أشهر المشاكل اللي ممكن تقابلك وأنت بتعدل في الثيم:

1
The "Magic Number" Bug

المشكلة: المسافات مش متناسقة بين الشاشات.

الحل: دايماً استخدم AppSizes. لو استخدمت أرقام ثابتة زي 15 أو 20 يدوياً، الشكل هيبوظ في الشاشات المختلفة.

2
Invisible Text in Dark Mode

المشكلة: الكلام مش باين لما اقلب Dark Mode.

الحل: اتأكد إنك بتستخدم context.textTheme.bodyMedium بدل ما تدي لون ثابت للـ Text. الـ Theme هو اللي بيعرف يغير لون الخط حسب الخلفية.

أسئلة شائعة حول التصميم UI & Theming FAQ
إزاي أغير اللون الأساسي لكل التطبيق؟
How to change the primary color app-wide?
عدل قيمة الـ primary في كلاس AppColors. الـ ColorScheme.fromSeed هيتكفل بتغيير الدرجات المشتقة منه في كل حتة.
Change the primary value in AppColors. ColorScheme.fromSeed will automatically update all derived shades.
هل التطبيق بيدعم التابلت بشكل كامل؟
Does the app fully support tablets?
أيوة، بفضل الـ ResponsiveLayout والـ AdaptiveOverlays، الواجهة بتتحول لـ Grid Layout و Dialogs عشان تستغل المساحة الكبيرة.
Yes, thanks to ResponsiveLayout and AdaptiveOverlays, the UI adapts to Grid Layouts and centered Dialogs for larger screens.
📖 قاموس الواجهة (UI Glossary) Design Terminology
  • ThemeExtension: وسيلة لإضافة ألوان مخصصة مش موجودة أساساً في الـ ThemeData.
  • Lerp: تقنية حسابية بتخلي الألوان تتغير بنعومة أثناء الانتقال.
  • Breakpoint: عرض معين للشاشة التطبيق عنده بيغير شكله (مثلاً 600px).
  • Adaptive: القدرة على تغيير نوع الـ Widget (زي Bottom Sheet لـ Dialog).
  • Responsive: القدرة على تغيير حجم الـ Widget أو ترتيبه (زي Column لـ Row).
🧱 المكونات الأساسية (Core Widgets) Building Blocks: The Core Widgets

عشان نحافظ على شكل ثابت في كل التطبيق، مابنكتبش ويدجتز من الصفر كل شوية. إحنا عندنا "مكتبة داخلية" في lib/core/widgets:

Widget NamePurpose (AR)Design Feature
AppTextFieldإدخال البيانات.حواف دائرية (RadiusMr) وتلوين ذكي عند الخطأ.
AppListTileعرض العمليات.Ripple effect كامل ومسافات متناسقة.
AppSwitchTileالإعدادات.بيستخدم ألوان الـ primary في حالة التفعيل.
AppCustomScrollViewالقوائم الطويلة.بيدعم الـ Slivers والـ Sticky Headers.

أي ويدجت جديد لازم يمر على الـ Core الأول؛ دي القاعدة الذهبية عندنا عشان نمنع تكرار الكود (DRY Principle).

🖋️ صوت التطبيق: نظام الخطوط The Voice of the App: Typography

الخط هو اللي بيوصل المعلومة. في MRE CashBook اخترنا خطوط واضحة بتدعم العربي والإنجليزي بنفس الكفاءة.

AppTheme configuration
textTheme: TextTheme(
  displayLarge: TextStyle(fontSize: 32, fontWeight: FontWeight.bold),
  titleMedium: TextStyle(fontSize: 18, fontWeight: FontWeight.w600),
  bodyMedium: TextStyle(fontSize: 14, fontWeight: FontWeight.normal),
),

استخدمنا حزمة Google Fonts عشان نضمن إن الخط يظهر بنفس الشكل على كل إصدارات أندرويد و iOS، وربطنا كل ده بالـ fontFamily في الـ ThemeData.

📊 مصفوفة مراجعة الواجهة UI Recap Matrix
ConceptArabic ValueEnglish Value
Primary Colorالأزرق البترولي الهادي.Calm Petrol Blue.
Corner Radius8px - 16px (Medium).Standardized Radii.
TransitionsFade & Scale.Smooth Switcher.
Breakpoints600px / 900px.Responsive Steps.
🚀 أداء الواجهة والقواعد الذهبية UI Performance & Best Practices

عشان التطبيق يفضل سريع (60 FPS) حتى على الأجهزة الضعيفة، اتبعنا القواعد دي:

1

استخدام const: أي ويدجت مش بيتغير لازم يكون const عشان Flutter مايعيدش بناؤه (Rebuild) بدون داعي.

2

تجنب Magic Numbers: مفيش Padding أو Radius مكتوب يدوياً. دايماً AppSizes.p16 أو AppSizes.radiusMd.

3

الأنيميشن الهادي: استخدمنا AppAnimations.smooth لكل الانتقالات عشان التجربة تكون مريحة للعين.

🧠 اختبر معلوماتك في التصميم Level Up: UI & Theming Quiz
إيه الفايدة الأساسية من استخدام AppColorsExtension؟
What is the primary benefit of using AppColorsExtension?
إضافة ألوان "دلالية" (Semantic) زي ألوان الدخل والمصروف للثيم الأساسي والتحكم في درجتها بين الـ Light والـ Dark.
Adding "Semantic" colors (like income/expense) to the base theme and controlling their shades across Light and Dark modes.
إزاي التطبيق بيعرف يقلب من Bottom Sheet لـ Dialog؟
How does the app switch from Bottom Sheet to Dialog?
عن طريق كلاس AdaptiveOverlays اللي بيفحص عرض الشاشة ويختار النوع المناسب أوتوماتيك.
Through the AdaptiveOverlays class which checks the screen width and selects the appropriate type automatically.
📝 ملخص الفصل Chapter Summary

في الفصل ده اتعلمنا إزاي نبني نظام تصميم متكامل، بيدعم الوضع الليلي، وبيستوعب كل أحجام الشاشات باحترافية.

🎓 خلاصة احتراف الواجهات Final Recap: UI Mastery
Feature Implementation Tool Primary Goal
Centralized Theme AppTheme Single source of truth for styles.
Semantic Colors AppColorsExtension Meaningful colors (Income/Expense).
Clean Access context.colors Developer experience and brevity.
Dark Mode System / User Preference User comfort and accessibility.
Layout Adaptivity ResponsiveLayout Support Mobile / Tablet / Desktop.
Overlay Adaptivity AdaptiveOverlays Optimal UX based on form factor.