🎯 ما هو MRE CashBook؟ What is MRE CashBook?

هو تطبيق أندرويد و iOS لإدارة السجلات المالية الشخصية (Ledger) والمعاملات اليومية. يركز التطبيق على الخصوصية (Private) والعمل بدون إنترنت (Offline-first) مع توفير أدوات احترافية مثل تصدير التقارير بصيغة PDF والنسخ الاحتياطي المشفر.

It's an Android & iOS application for managing personal financial ledgers and daily transactions. The app focuses on privacy and an offline-first experience, providing professional tools like PDF report export and encrypted backups.

💡

تم تصميم التطبيق ليكون بديلاً رقمياً متطوراً لدفاتر الحسابات الورقية التقليدية، مع التركيز على السرعة والدقة في إدخال البيانات.

The app is designed to be a sophisticated digital alternative to traditional paper account books, focusing on speed and accuracy in data entry.

🖥️ أول خطوة: تجهيز المشروع First Step: Project Setup

قبل ما نفتح الكود، لازم نتأكد إن كل المكتبات جاهزة. بنستخدم أمر `flutter pub get` الأساسي.

Before we open the code, we must ensure all libraries are ready. We use the fundamental `flutter pub get` command.

🖥️ Terminal Command
flutter pub get
flutter pub get
🔍 بيعمل إيه؟ 🔍 What does it do?

بيحمل كل الـ dependencies المذكورة في ملف `pubspec.yaml`. بيقارن النسخ المطلوبة وبينزلها من موقع pub.dev للفولدر المحلي على جهازك.

Downloads all dependencies listed in `pubspec.yaml`. It compares requested versions and downloads them from pub.dev to your local cache.

🤔 ليه محتاجينه؟ 🤔 Why do we need it?

من غيره الكود مش هيقدر يشوف المكاتب الخارجية زي Drift أو BLoC، وهتلاقي errors مالية الشاشة في الـ IDE.

Without it, the code won't recognize external libraries like Drift or BLoC, leading to errors everywhere in your IDE.

📋 ملف الـ pubspec.lock 📋 The pubspec.lock file

الأمر ده بيولد ملف `pubspec.lock`. ده ملف "البصمة" اللي بيضمن إن كل المطورين شغالين بظبط على نفس النسخ عشان ميبقاش في bug عند واحد وشغال عند التاني.

This command generates `pubspec.lock`. This "fingerprint" file ensures all developers work on the exact same versions to prevent "works on my machine" bugs.

📦 شرح المكتبات (Dependencies) Dependencies Deep Dive

التطبيق بيعتمد على مجموعة من المكتبات القوية. في ملف `pubspec.yaml` بنلاحظ استخدام علامة الـ `^` (Caret) قبل أرقام النسخ.

The app relies on a set of powerful libraries. In `pubspec.yaml`, we notice the use of the `^` (Caret) symbol before version numbers.

💡

ماذا تعني علامة الـ ^؟ هي بتسمح بتحديث المكتبة لأي نسخة "متوافقة" (Semantic Versioning) بشرط متكونش Breaking Change.

What does the ^ mean? It allows upgrading to any "compatible" version (Semantic Versioning) as long as it's not a breaking change.

1
المكتبات الأساسية / Core Packages
PackagePurposeWhy?
driftLocal DatabaseType-safe, reactive SQL.
flutter_blocState MgmtStandard, predictable flow.
get_itDIDecouple services from UI.
firebase_coreFirebaseThe base for cloud services.
share_plusSharingExport PDFs and share data.
path_providerStorageFind local directories on device.
🏗️ هندسة التطبيق (Detailed Architecture) App Architecture (Deep Dive)

بنستخدم Clean Architecture مقسمة لثلاث طبقات أساسية. ده بيضمن إننا لو حبينا نغير قاعدة البيانات مستقبلاً، مش هنحتاج نغير حاجة في الـ UI.

We use Clean Architecture divided into three main layers. This ensures that if we want to change the database in the future, we won't need to change anything in the UI.

1
طبقة البيانات (Data Layer) Data Layer

دي أوطى طبقة، مسؤولة عن "إزاي بنجيب البيانات". فيها الـ Models (DTOs)، الـ DataSources، والـ Repositories الحقيقية.

The lowest layer, responsible for "how to fetch data". It contains Models (DTOs), DataSources, and concrete Repositories.

2
طبقة الدومين (Domain Layer) Domain Layer

دي "قلب المشروع". مفيهاش أي علاقة بـ Flutter أو أي مكتبة خارجية. فيها الـ Entities والـ UseCases والـ Repository Interfaces.

The "heart of the project". It has zero dependencies on Flutter or external libs. Contains Entities, UseCases, and Repository Interfaces.

ملاحظة: طبقة الدومين هي الأكثر استقراراً. لو الـ UI اتغير أو الـ DB اتغير، الدومين بيفضل زي ما هو.

Note: Domain layer is the most stable. If UI or DB changes, Domain remains untouched.

3
طبقة العرض (Presentation Layer) Presentation Layer

دي الطبقة اللي بتشوفها. فيها الـ UI (Widgets) والـ State Management (BLoC/Cubit).

The layer you see. Contains UI (Widgets) and State Management (BLoC/Cubit).

🚀 مسار التشغيل (Main Startup Flow) Main Startup Flow

يبدأ التطبيق في `main.dart` حيث يتم تجهيز كل شيء قبل ظهور أول شاشة للمستخدم. يتم تهيئة الـ Dependency Injection، الـ Database، وخدمات Firebase.

The app starts in `main.dart` where everything is prepared before the first screen appears. DI, Database, and Firebase services are initialized here.

📁 lib/main.dart
void main() async {
  try {
    // Ensuring Flutter is ready for async calls
    WidgetsFlutterBinding.ensureInitialized();

    // 1. Initialize Dependency Injection (GetIt)
    await initDI();

    try {
      // 2. Initialize Firebase with a 3-second timeout
      await Firebase.initializeApp(
        options: DefaultFirebaseOptions.currentPlatform,
      ).timeout(
        const Duration(seconds: 3),
        onTimeout: () => throw Exception('Firebase init timeout'),
      );
      
      // Setup Crashlytics
      FlutterError.onError = FirebaseCrashlytics.instance.recordFlutterError;
    } catch (e) {
      debugPrint('Firebase failed: $e');
    }

    // 3. Global Bloc Observer for debugging
    Bloc.observer = AppBlocObserver();

    // 4. Run the Application
    runApp(const LedgerApp());
    
  } catch (e) {
    debugPrint('Critical Failure: $e');
  }
}
await initDI();
🔍 بيعمل إيه؟ 🔍 What does it do?

بينادي على حاوية حقن التبعيات (GetIt) عشان يسجل كل الـ Repositories والـ Blocs.

Calls the DI container to register all Repositories and Blocs.

🤔 ليه كتبناه كده؟ 🤔 Why this way?

لازم يتم قبل الـ `runApp` لأن كل الـ Widgets هتطلب الـ dependencies دي فوراً.

Must happen before `runApp` because widgets will request these dependencies immediately.

.timeout(const Duration(seconds: 3), ...)
🔍 بيعمل إيه؟ 🔍 What does it do?

بيحدد وقت أقصى لمحاولة الاتصال بـ Firebase.

Sets a maximum timeout for Firebase connection attempt.

❓ لو حذفناه؟ ❓ What breaks if removed?

لو الموبايل معلهوش خدمات جوجل (زي هواوي)، التطبيق ممكن يعلق (Hang) للأبد في الـ Splash screen.

On devices without GMS (like Huawei), the app might hang forever on the splash screen.

Main() ──► initDI() ──► Firebase Init ──► Error Handlers ──► runApp(LedgerApp)
                                         │
                                         └─► MultiBlocProvider
                                              ├─ AppSettingsCubit
                                              ├─ AppPreferencesCubit
                                              └─ BooksBloc
      
🖼️ إدارة الصور واللوجو (Assets) Asset Management Hierarchy

التطبيق محتاج يوصل للصور والخطوط. ده بيتم تعريفه في قسم `flutter:` داخل `pubspec.yaml`.

The app needs access to images and fonts. This is defined in the `flutter:` section of `pubspec.yaml`.

📄 pubspec.yaml (Assets Section)
flutter:
  uses-material-design: true

  assets:
    - assets/images/
    - assets/icons/
    - assets/splash/
    - assets/lottie/
⚠️

التسلسل الهرمي: بنحاول دايماً نخلي الـ Icons في فولدر منفصل والـ Images في فولدر منفصل عشان التنظيم.

Hierarchy: We always keep Icons and Images in separate folders for better organization.

🛡️ نظام الحماية من الانهيار (Crash Protection) Global Error Handling Deep Dive

في `main.dart` بنستخدم `protected` blocks عشان نضمن إن أي مشكلة في البداية متبوظش تجربة المستخدم.

In `main.dart`, we use protected blocks to ensure startup issues don't ruin the user experience.

📁 lib/main.dart (Error Handling)
// Capture Async errors outside Flutter Context
PlatformDispatcher.instance.onError = (error, stack) {
  FirebaseCrashlytics.instance.recordError(error, stack, fatal: true);
  return true;
};

// Custom Error Widget for UI crashes
ErrorWidget.builder = (FlutterErrorDetails details) {
  return Scaffold(
    body: Center(
      child: Text('هناك خطأ ما، تم إبلاغ المطورين.'),
    ),
  );
};
🪜 خطوات تشغيل المشروع من الصفر Setup Steps from Scratch
1
تحديث المكاتب / Update Deps

أول حاجة لازم تحمل المكاتب المطلوبة.

🖥️ Terminal
flutter pub get
2
توليد ملفات قاعدة البيانات (CODE GEN) Run Code Generation

بما إننا بنستخدم Drift، لازم نولّد الكود الخاص بالجداول.

🖥️ Terminal
dart run build_runner build --delete-conflicting-outputs
3
تشغيل التطبيق / Launch
🖥️ Terminal
flutter run
🧩 أنماط برمجية (Patterns) Programming Patterns
التوسع عبر الـ Extensions Expansion via Extensions

بنشوف استخدام كبير للـ `BuildContext` extension عشان نسهل الوصول للألوان والخطوط.

We see heavy use of `BuildContext` extensions to simplify access to colors and text themes.

📁 lib/core/utils/extensions.dart
extension BuildContextHelper on BuildContext {
  AppColors get colors => Theme.of(this).extension()!;
  TextTheme get textTheme => Theme.of(this).textTheme;
}
🛠️ أدوات التطوير: FVM Development Tooling: FVM

بنستخدم FVM (Flutter Version Management) للتأكد إن كل المطورين شغالين بظبط على نفس نسخة Flutter (وهي 3.24.5 في مشروعنا).

We use FVM (Flutter Version Management) to ensure all developers use the exact same Flutter version (3.24.5 in our project).

🖥️ Terminal Command
fvm flutter run
💡

ليه FVM؟ فلاتر بتتطور بسرعة جداً. لو واحد شغال بـ 3.27 والتاني بـ 3.24، ممكن الكود يشتغل عند واحد ويبوظ عند التاني. FVM بيثبت النسخة للمشروع ده تحديداً.

Why FVM? Flutter evolves fast. If one dev uses 3.27 and another 3.24, code might break. FVM locks the version for this specific project.

💭 فلسفة المشروع (Philosophy Corner) Project Philosophy

المشروع ده بيتبع مبادئ الـ "MRE" والـ "Clean Code". الهدف هو إن الكود يكون بيشرح نفسه (Self-documenting).

The project follows "MRE" and "Clean Code" principles. The goal is self-documenting code.

قواعد ذهبية ممنوع كسرها:

📖 قاموس المصطلحات البرمجية Technical Glossary
TermDefinition
DTOData Transfer Object - كائن لنقل البيانات من الـ Database.
Entityأبسط شكل للبيانات في طبقة الدومين (بدون إضافات).
UseCaseكلاس بيوصف "فعل" واحد بيقوم بيه المستخدم (زي "إضافة دفتر").
Singletonنمط بيضمن إن كلاس معين منه نسخة واحدة بس في الذاكرة.
Lazy Singletonنسخة واحدة بس، بس مش بتتعمل غير لما نحتاجها فعلاً (توفير رام).
📝 ملخص الفصل Chapter Summary

أنهينا نظرة عامة شاملة على المشروع، من أول "ما هو التطبيق" لحد "إزاي نشغله" و "إيه الأدوات اللي بنستخدمها".

We finished a comprehensive project overview, from "What is the app" to "How to run it" and "What tools we use".

تذكر: القاعدة الأولى هي Clean Architecture، القواعد التانية هي تفاصيل.

Remember: Rule #1 is Clean Architecture; everything else is detail.

الرئيسيةHome الفصل التاليNext