supabase And Clean

🧭 التسلسل اللي رح نمشي عليه
  1. Core
  2. Domain (Entity + Repository)
  3. UseCases
  4. Data (Model + DataSource + RepositoryImpl)
  5. Cubit
  6. UI
  7. main.dart
🧱 1. CORE
📁 lib/core/supabase/supabase_client.dart
🧠 شرح الملف (خارج الكود)

هذا الملف مسؤول عن:

👉 إنشاء نقطة اتصال واحدة مع Supabase لكل التطبيق

ليش مهم؟

  • بدل ما تنشئ client بكل مكان
  • تستخدمه مرة واحدة وتشاركه

📌 هذا يسمى:

Singleton Pattern
JavaScript
📄 الكود:
import 'package:supabase_flutter/supabase_flutter.dart';

/// هذا الكلاس مسؤول عن:
/// - توفير SupabaseClient جاهز
/// - استخدامه في كل المشروع بدون تكرار

class SupabaseConfig {
  /// static = نستخدمه بدون إنشاء object
  /// final = لا يمكن تغييره

  static final SupabaseClient client = Supabase.instance.client;

  /// Supabase.instance → instance واحد من Supabase
  /// .client → الاتصال الفعلي مع قاعدة البيانات
}
JavaScript
🧱 2. DOMAIN
📁 lib/features/notes/domain/entities/note.dart
🧠 شرح الملف

هذا الملف يمثل:

👉 “الملاحظة” داخل التطبيق

📌 أهم نقطة:

  • لا يعرف API
  • لا يعرف Supabase
  • لا يعرف JSON

👉 فقط بيانات نظيفة

📄 الكود:
/// هذا الكلاس يمثل "كيان الملاحظة"
/// Entity = الشكل الرسمي للبيانات داخل التطبيق

class Note {
  /// id الخاص بالملاحظة
  final String id;  /// عنوان الملاحظة
  final String title;  /// محتوى الملاحظة
  final String content;  /// Constructor لإنشاء Note
  Note({
    required this.id,
    required this.title,
    required this.content,
  });  
  
  /// required = يجب تمرير القيمة
  /// this.id = تخزين القيمة داخل المتغير
}
Dart
📁 domain/repository/notes_repository.dart
🧠 شرح الملف

هذا الملف هو:

👉 Contract (عقد)

يعني:

  • يحدد ماذا نريد
  • لا يحدد كيف
📄 الكود:
import '../entities/note.dart';
/// abstract = لا يمكن إنشاء object منه
  /// هو فقط "واجهة" أو "عقد"

abstract class NotesRepository {
  /// جلب كل الملاحظات
  Future<List<Note>> getNotes();  /// إضافة ملاحظة
  Future<void> addNote(Note note);  /// حذف ملاحظة
  Future<void> deleteNote(String id);  /// تعديل ملاحظة
  Future<void> updateNote(Note note);
}
Dart
🧱 3. USE CASES 🔥
📁 add_note_usecase.dart
🧠 شرح الملف

هذا الملف يمثل:

👉 عملية واحدة فقط: “إضافة ملاحظة”

📌 هنا نضع:

  • القوانين
  • التحقق
  • business logic
📄 الكود:
import '../repository/notes_repository.dart';
import '../entities/note.dart';
/// هذا الكلاس يمثل عملية "إضافة ملاحظة"

class AddNoteUseCase {
  final NotesRepository repo;  /// نمرر repository  -- مرجع وليس كائن أو أوبجكت 
  AddNoteUseCase(this.repo);  /// call() تجعل الكلاس يعمل كدالة
  Future<void> call(Note note) async {
    /// مثال على business logic
    if (note.title.isEmpty) {
      throw Exception("العنوان فارغ");
    }    /// استدعاء repository
    return await repo.addNote(note);
  }
}
Dart
📁 get_notes_usecase.dart
import '../repository/notes_repository.dart';
import '../entities/note.dart';

class GetNotesUseCase {
  final NotesRepository repo;  /// نمرر repository  -- مرجع وليس كائن أو أوبجكت 
  GetNotesUseCase(this.repo);  
  Future<List<Note>> call() async {
    return await repo.getNotes();
  }
}
Dart
🧱 4. DATA
📁 note_model.dart
🧠 شرح الملف

هذا الملف يحول:

JSONObject
Dart

📌 الفرق:

  • Entity = نظيف
  • Model = يتعامل مع JSON
📄 الكود:
import '../../domain/entities/note.dart';

/// Model يرث من Entity
  /// يعني هو Note + وظائف إضافية
  
  class NoteModel extends Note {
  NoteModel({
    required super.id,
    required super.title,
    required super.content,
  });
  
    /// تحويل JSON إلى Object
  factory NoteModel.fromJson(Map<String, dynamic> json) {
    return NoteModel(
      id: json['id'].toString(), // حل مشكلة int/String
      title: json['title'],
      content: json['content'],
    );
  }
  
    /// تحويل Object إلى JSON
  Map<String, dynamic> toJson() {
    return {
      /// لا نرسل id لأن Supabase يولده
      'title': title,
      'content': content,
    };
  }
}
Dart
📁 notes_remote_datasource.dart
🧠 شرح الملف

هذا الملف:

👉 يتعامل مباشرة مع Supabase

📄 الكود:
import 'package:supabase_flutter/supabase_flutter.dart';
import '../models/note_model.dart';

class NotesRemoteDataSource {
  final SupabaseClient client; 
  
   /// dependency injection
  NotesRemoteDataSource(this.client);  /// جلب البيانات
  Future<List<NoteModel>> getNotes() async {
    final response = await client.from('notes').select();
        return response.map<NoteModel>((e) {
      return NoteModel.fromJson(e);
    }).toList(); 
  }
  
    /// إضافة
  Future<void> addNote(NoteModel note) async {
    await client.from('notes').insert(note.toJson());
  }
  
    /// حذف
  Future<void> deleteNote(String id) async {
    await client.from('notes').delete().eq('id', id);
  }
  
    /// تعديل
  Future<void> updateNote(NoteModel note) async {
    await client
        .from('notes')
        .update(note.toJson())
        .eq('id', note.id);
  }
}
Dart
📁 notes_repository_impl.dart
🧠 شرح الملف

هذا الملف:

👉 يربط Domain مع Data

📄 الكود:
import '../../domain/entities/note.dart';
import '../../domain/repository/notes_repository.dart';
import '../datasource/notes_remote_datasource.dart';
import '../models/note_model.dart';

class NotesRepositoryImpl implements NotesRepository {
  final NotesRemoteDataSource remote;
  NotesRepositoryImpl(this.remote); 
  
   @override
  Future<List<Note>> getNotes() async {
    return await remote.getNotes();
  } 
  
  @override
  Future<void> addNote(Note note) async {
    final model = NoteModel(
      id: note.id,
      title: note.title,
      content: note.content,
    );    await remote.addNote(model);
  }
  
  @override
  Future<void> deleteNote(String id) async {
    await remote.deleteNote(id);
  }
  
  
  @override
  Future<void> updateNote(Note note) async {
    final model = NoteModel(
      id: note.id,
      title: note.title,
      content: note.content,
    );    await remote.updateNote(model);
  }
}
Dart
🧠 الخلاصة (لهذه المرحلة)

أنت الآن فهمت:

  • Entity = بيانات
  • Model = تحويل
  • DataSource = API
  • Repository = وسيط
  • UseCase = منطق
🧱 5. PRESENTATION (Cubit)
📁 lib/features/notes/presentation/cubit/notes_state.dart
🧠 شرح الملف

هذا الملف يمثل:

👉 حالات التطبيق (States)

ليش مهم؟

لأن UI لازم يعرف:

  • هل البيانات عم تتحمّل؟
  • هل وصلت؟
  • هل في خطأ؟
📄 الكود:
import '../../domain/entities/note.dart';

   /// هذا هو الأب لكل الحالات
abstract class NotesState {}/// الحالة الابتدائية (قبل أي شيء)
class NotesInitial extends NotesState {}/// حالة التحميل
class NotesLoading extends NotesState {}/// حالة نجاح (فيها بيانات)
class NotesLoaded extends NotesState {
  final List<Note> notes; 
   NotesLoaded(this.notes);
  
  
}/// حالة الخطأ 

class NotesError extends NotesState {
  final String message; 
NotesError(this.message);
}
Dart
📁 notes_cubit.dart
🧠 شرح الملف

هذا أهم ملف 👇

👉 مسؤول عن:

  • إدارة الحالة
  • استدعاء UseCases
  • إرسال States للـ UI
📄 الكود:
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../domain/entities/note.dart';
import '../../domain/usecases/get_notes_usecase.dart';
import '../../domain/usecases/add_note_usecase.dart';
import '../../domain/usecases/delete_note_usecase.dart';
import '../../domain/usecases/update_note_usecase.dart';
import 'notes_state.dart';


/// Cubit = مدير الحالة
class NotesCubit extends Cubit<NotesState> {
  /// UseCases
  final GetNotesUseCase getNotesUseCase;
  final AddNoteUseCase addNoteUseCase;
  final DeleteNoteUseCase deleteNoteUseCase;
  final UpdateNoteUseCase updateNoteUseCase; 
  
  
   /// Constructor
  NotesCubit(
    this.getNotesUseCase,
    this.addNoteUseCase,
    this.deleteNoteUseCase,
    this.updateNoteUseCase,
  ) : super(NotesInitial()); 
  
  
   /// 📥 جلب البيانات
  Future<void> fetchNotes() async {
    emit(NotesLoading());   
     try {
      final notes = await getNotesUseCase();
      emit(NotesLoaded(notes));
    } catch (e) {
      emit(NotesError(e.toString()));
    }
  }
  
  
    /// ➕ إضافة
  Future<void> addNote(Note note) async {
    await addNoteUseCase(note);
    fetchNotes(); 
    
    // تحديث
  }
  
    /// ❌ حذف
  Future<void> deleteNote(String id) async {
    await deleteNoteUseCase(id);
    fetchNotes();
  }
  
  
    /// 🔄 تعديل
  Future<void> updateNote(Note note) async {
    await updateNoteUseCase(note);
    fetchNotes();
  }
}
Dart
🧱 6. UI📁 notes_page.dart
🧠 شرح الملف

هذه الصفحة:

👉 الصفحة الرئيسية للتطبيق

تحتوي على:

  • إدخال ملاحظة
  • عرض قائمة
  • حذف
  • انتقال لصفحة التفاصيل
📄 الكود:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../cubit/notes_cubit.dart';
import '../cubit/notes_state.dart';
import '../../domain/entities/note.dart';
import 'note_details_page.dart';


class NotesPage extends StatelessWidget {
  NotesPage({super.key});  final TextEditingController titleController = TextEditingController();
  final TextEditingController contentController = TextEditingController();  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("الملاحظات")),   
         body: Column(
        children: [
          /// إدخال العنوان
          TextField(controller: titleController),          /// إدخال المحتوى
          TextField(controller: contentController),          /// زر إضافة
          ElevatedButton(
            onPressed: () {
              final note = Note(
                id: "",
                title: titleController.text,
                content: contentController.text,
              );              context.read<NotesCubit>().addNote(note);
            },
            child: const Text("إضافة"),
          ),          /// عرض البيانات
          Expanded(
            child: BlocBuilder<NotesCubit, NotesState>(
              builder: (context, state) {
                /// تحميل
                if (state is NotesLoading || state is NotesInitial) {
                  return const CircularProgressIndicator();
                }                /// بيانات
                if (state is NotesLoaded) {
                  return ListView.builder(
                    itemCount: state.notes.length,
                    itemBuilder: (context, index) {
                      final note = state.notes[index];                      return ListTile(
                        title: Text(note.title),
                        subtitle: Text(note.content),                        /// فتح التفاصيل
                        onTap: () {
                          Navigator.push(
                            context,
                            MaterialPageRoute(
                              builder: (_) =>
                                  NoteDetailsPage(note: note),
                            ),
                          );
                        },                        /// حذف
                        trailing: IconButton(
                          icon: const Icon(Icons.delete),
                          onPressed: () {
                            context
                                .read<NotesCubit>()
                                .deleteNote(note.id);
                          },
                        ),
                      );
                    },
                  );
                }                return const Text("لا يوجد بيانات");
              },
            ),
          ),
        ],
      ),
    );
  }
}
Dart
📁 note_details_page.dart
🧠 شرح الملف

هذه الصفحة:

👉 تعرض الملاحظة + تسمح بالتعديل

📄 الكود:
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../domain/entities/note.dart';
import '../cubit/notes_cubit.dart';
class NoteDetailsPage extends StatefulWidget {
  final Note note; 
   const NoteDetailsPage({super.key, required this.note});  @override
  State<NoteDetailsPage> createState() => _NoteDetailsPageState();
}
class _NoteDetailsPageState extends State<NoteDetailsPage> {
  late TextEditingController titleController;
  late TextEditingController contentController;  
  bool isEditing = false;
  @override
  void initState() {
    super.initState();    /// تعبئة الحقول
    titleController = TextEditingController(text: widget.note.title);
    contentController = TextEditingController(text: widget.note.content);
  } 
  
   void save() {
    final updated = Note(
      id: widget.note.id,
      title: titleController.text,
      content: contentController.text,
    );   
    
   context.read<NotesCubit>().updateNote(updated);
    Navigator.pop(context);
  } 
  
 @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text("تفاصيل"),
        actions: [
          IconButton(
            icon: Icon(isEditing ? Icons.save : Icons.edit),
            onPressed: () {
              if (isEditing) {
                save();
              } else {
                setState(() => isEditing = true);
              }
            },
          )
        ],
      ),
      body: Column(
        children: [
          TextField(
            controller: titleController,
            readOnly: !isEditing,
          ),
          TextField(
            controller: contentController,
            readOnly: !isEditing,
          ),
        ],
      ),
    );
  }
}
Dart
🧱 7. main.dart
🧠 شرح الملف

هذا الملف يربط كل شيء:

👉 Dependency Injection

📄 الكود:
final datasource = NotesRemoteDataSource(client);
final repo = NotesRepositoryImpl(datasource);
final getNotes = GetNotesUseCase(repo);
final addNote = AddNoteUseCase(repo);
final deleteNote = DeleteNoteUseCase(repo);
final updateNote = UpdateNoteUseCase(repo);return NotesCubit(getNotes, addNote, deleteNote, updateNote);
Dart
🧠 الخلاصة النهائية

أنت الآن تملك:

✔ Clean Architecture
✔ UseCases
✔ Cubit
✔ Supabase
✔ Navigation + Edit

🧠 أولاً: شو دور UseCases (تذكير سريع)

UseCase = عملية واحدة واضحة في التطبيق

مثلاً:

  • جلب الملاحظات
  • إضافة ملاحظة
  • حذف
  • تعديل

👉 هي الطبقة بين Cubit و Repository

🧱 مكانها في المشروع
domain/
└── usecases/
    ├── get_notes_usecase.dart
    ├── add_note_usecase.dart
    ├── delete_note_usecase.dart
    └── update_note_usecase.dart
Dart
📁 1. get_notes_usecase.dart
🧠 شرح الملف

هذا الملف مسؤول عن:

👉 جلب جميع الملاحظات

📌 ممكن تضيف فيه لاحقاً:

  • فلترة
  • ترتيب
  • caching
📄 الكود:
import '../repository/notes_repository.dart';
import '../entities/note.dart';

/// UseCase لجلب الملاحظات
class GetNotesUseCase {
  final NotesRepository repo; 
 
   /// نمرر Repository
  GetNotesUseCase(this.repo); 
   
   /// call() تسمح باستخدام الكلاس كأنه function
  Future<List<Note>> call() async {
  
    /// فقط نطلب البيانات من repository
    return await repo.getNotes();
  }
}
Dart
📁 2. add_note_usecase.dart
🧠 شرح الملف

هذا الملف مسؤول عن:

👉 إضافة ملاحظة جديدة

📌 هنا المكان الصحيح لـ:

  • التحقق من البيانات
  • منع القيم الفارغة
  • أي business logic
📄 الكود:
import '../repository/notes_repository.dart';
import '../entities/note.dart';
/// UseCase لإضافة ملاحظة
class AddNoteUseCase {
  final NotesRepository repo; 
   AddNoteUseCase(this.repo); 
    Future<void> call(Note note) async {
    /// 🔴 Business Logic هنا
    if (note.title.trim().isEmpty) {
      throw Exception("العنوان لا يمكن أن يكون فارغ");
    }   
    
     if (note.content.trim().isEmpty) {
      throw Exception("المحتوى لا يمكن أن يكون فارغ");
    } 
    
       /// إرسال البيانات إلى Repository
    await repo.addNote(note);
  }
}
Dart
📁 3. delete_note_usecase.dart
🧠 شرح الملف

هذا الملف مسؤول عن:

👉 حذف ملاحظة

📄 الكود:
import '../repository/notes_repository.dart';
/// UseCase لحذف ملاحظة<br>class DeleteNoteUseCase {

final NotesRepository repo;
  DeleteNoteUseCase(this.repo);
    Future<void> call(String id) async {
  /// يمكن إضافة تحقق هنا لاحقاً<br> 
       if (id.isEmpty) {    
         throw Exception("id غير صالح");
   }
   await repo.deleteNote(id);
 }}
Dart
📁 4. update_note_usecase.dart
🧠 شرح الملف

هذا الملف مسؤول عن:

👉 تعديل ملاحظة

📌 هنا تضع:

  • تحقق
  • قواعد تعديل
📄 الكود:
import '../repository/notes_repository.dart';
import '../entities/note.dart';
/// UseCase لتعديل ملاحظة
class UpdateNoteUseCase {
  final NotesRepository repo;  
  UpdateNoteUseCase(this.repo);
    Future<void> call(Note note) async {
    /// تحقق
    if (note.id.isEmpty) {
      throw Exception("id غير موجود");
    }    if (note.title.trim().isEmpty) {
      throw Exception("العنوان فارغ");
    }    if (note.content.trim().isEmpty) {
      throw Exception("المحتوى فارغ");
    }    await repo.updateNote(note);
  }
}
Dart
🔗 كيف يرتبطوا مع بعض؟
🧠 في Cubit:
await addNoteUseCase(note);
await getNotesUseCase();
Dart
🧠 في main.dart:
final repo = NotesRepositoryImpl(datasource);
final getNotes = GetNotesUseCase(repo);
final addNote = AddNoteUseCase(repo);
final deleteNote = DeleteNoteUseCase(repo);
final updateNote = UpdateNoteUseCase(repo);
Dart
💥 الخلاصة القوية
الطبقةمسؤوليتها
Cubitإدارة الحالة
UseCaseتنفيذ العملية
Repositoryتعريف العمليات
DataSourceالاتصال مع Supabase
🚀 الآن أنت عندك:

✔ UseCases كاملة
✔ مكان واضح للـ business logic
✔ فصل نظيف بين الطبقات

رح أشرح لك:

  1. 🧠 كيف الملفات مرتبطة ببعض
  2. 🔁 كيف تمشي العملية خطوة خطوة (مثال حقيقي)
  3. 🎯 مين ينادي مين بالضبط

🧭 أولاً: الخريطة العامة

UI (notes_page.dart)

Cubit (notes_cubit.dart)

UseCase (add_note_usecase.dart)

Repository (notes_repository_impl.dart)

DataSource (notes_remote_datasource.dart)

Supabase
Dart
🧠 أهم فكرة

👉 كل طبقة لا تعرف إلا الطبقة اللي تحتها فقط

🔗 العلاقات بين الملفات
🟢 1. UI

📁 notes_page.dart

context.read<NotesCubit>().addNote(note);
Dart

👉 UI ينادي Cubit فقط

❌ ما يعرف:

  • UseCase
  • Repository
  • Supabase
🔵 2. Cubit

📁 notes_cubit.dart

await addNoteUseCase(note);
Dart

👉 Cubit ينادي UseCase

🟣 3. UseCase

📁 add_note_usecase.dart

await repo.addNote(note);
Dart

👉 UseCase ينادي Repository

🟡 4. Repository

📁 notes_repository_impl.dart

await remote.addNote(model);
Dart

👉 Repository ينادي DataSource

🔴 5. DataSource

📁 notes_remote_datasource.dart

client.from('notes').insert(...)
Dart

👉 DataSource ينادي Supabase

🔥 الآن نفهمها بمثال حقيقي
🎯 سيناريو: إضافة ملاحظة
🟢 STEP 1 — UI
ElevatedButton(
 onPressed: () {
     context.read<NotesCubit>().addNote(note);
},)
Dart

👉 المستخدم ضغط زر

🔵 STEP 2 — Cubit

Future<void> addNote(Note note) async {
  await addNoteUseCase(note);
  fetchNotes();
}
Dart

👉 Cubit قال:

  • نفّذ العملية
  • ثم حدّث البيانات
🟣 STEP 3 — UseCase
Future<void> call(Note note) async {
  if (note.title.isEmpty) throw Exception(); 
 await repo.addNote(note);
}
Dart

👉 تحقق + تنفيذ

🟡 STEP 4 — Repository
final model = NoteModel(...);
await remote.addNote(model);
Dart

👉 تحويل Entity → Model

🔴 STEP 5 — DataSource
await client.from('notes').insert(...)
Dart

👉 إرسال إلى Supabase

🟢 يرجع الرد بالعكس 🔁
SupabaseDataSourceRepositoryUseCaseCubitUI
Dart
🧠 سيناريو جلب البيانات
UI
BlocBuilder(...)
Dart
Cubit
fetchNotes()
Dart
UseCase
getNotesUseCase()
Dart
Repository
remote.getNotes()
Dart
DataSource
select()
Dart
يرجع:
emit(NotesLoaded(notes));
Dart
💡 ليش هذا التقسيم عبقري؟
🎯 1. فصل المسؤوليات
طبقةعملها
UIعرض فقط
Cubitإدارة الحالة
UseCaseمنطق
Repositoryواجهة
DataSourceAPI
🎯 2. سهولة التغيير

مثلاً:

👉 بدك تغير Supabase إلى Firebase؟

✔ تغير DataSource فقط
❌ باقي المشروع لا يتغير

🎯 3. Testing سهل
  • تختبر UseCase لوحده
  • تختبر Cubit لوحده
🔥 ملخص ذهني سريع
UI ما يعرف إلا Cubit
Cubit ما يعرف إلا UseCase
UseCase ما يعرف إلا Repository
Repository ما يعرف إلا DataSource
DataSource يعرف Supabase
Dart

👉 مو في 2 Repository حقيقيين
👉 في واحد (واجهة) + واحد (تنفيذ)

🧠 خلّينا نفكها بهدوء
🔷 1. هذا مو Repository فعلي

📁 notes_repository.dart

abstract class NotesRepository {
  Future<List<Note>> getNotes();
}
Dart
🎯 هذا اسمه:
Contract / Interface
Dart
🧠 شو يعني؟

👉 يقول:

“أنا بدي هيك عمليات”

لكن ❌ ما يقول كيف تنفذ

🔶 2. هذا هو Repository الحقيقي

📁 notes_repository_impl.dart

class NotesRepositoryImpl implements NotesRepository {
Dart
🎯 هذا اسمه:
Implementation
Dart
🧠 شو يعمل؟

👉 ينفذ العمليات باستخدام:

DataSource (Supabase)
Dart
🔥 ليش عملنا هيك؟
🎯 السبب الأساسي:
Decoupling (فصل الطبقات)
Dart
🧠 بدون هذا الفصل ❌
CubitSupabase مباشرة
Dart

👉 كارثة 😅

🧠 مع الفصل ✅
CubitUseCaseRepository (Interface)

                  RepositoryImpl

                    DataSource
Dart
🎯 الفائدة
1️⃣ تقدر تغيّر المصدر بسهولة

اليوم:

Supabase
Dart

بكرة:

Firebase
Local DB
API
Dart

👉 فقط تغيّر:

NotesRepositoryImpl
Dart
2️⃣ Testing سهل 🔥

تقدر تعمل:

FakeNotesRepository
Dart

بدون Supabase

3️⃣ Clean Architecture حقيقي
🧠 مثال بسيط يوضح الفكرة
Interface:
abstract class Animal {
  void sound();
}
Dart
Implementation:
class Dog implements Animal {
  void sound() => print("woof");
  }
Dart

👉 نفس الفكرة بالضبط

🔥 الخلاصة
الملفدوره
notes_repository.dartتعريف (Interface)
notes_repository_impl.dartتنفيذ (Implementation)
💡 قاعدة ذهبية
Domain يعرف Interface فقط
Data يعرف Implementation
Dart

call شو عملها ???

👌 وهذا من أهم الأشياء اللي لازم تفهمها في UseCases 🔥

🧠 شو هي call() في Dart؟

ببساطة:

call() = تخلي الكلاس يشتغل كأنه function
Dart
🎯 مثال بسيط جداً
بدون call ❌
class Test {
  void execute() {
    print("Hello");
  }
}
Dart

الاستخدام:

final t = Test();
t.execute(); // لازم تكتب اسم الميثود
Dart
مع call ✅
class Test {
  void call() {
    print("Hello");
  }
}
Dart

الاستخدام:

final t = Test();
t(); // 🔥 كأنه function
Dart
💥 هذا هو السر
وجود call() داخل الكلاس = يسمح لك تناديه كدالة
Dart
🧩 كيف استخدمناه في UseCase

📁 add_note_usecase.dart
class AddNoteUseCase {
  final NotesRepository repo; 
   AddNoteUseCase(this.repo); 
   Future<void> call(Note note) async {
   await repo.addNote(note);
  }
}
Dart
🧠 الاستخدام في Cubit
await addNoteUseCase(note);
Dart
❗ شو صار هون؟

Dart فهمها كأنك كتبت:

await addNoteUseCase.call(note);
Dart
🔥 ليش نستخدم call؟
🎯 1. شكل أنظف

بدل:

addNoteUseCase.execute(note);
Dart

نكتب:

addNoteUseCase(note); // أجمل وأبسط
Dart
🎯 2. يخلّي UseCase كأنه function

وهذا الهدف أصلاً:

UseCase = عملية واحدة = Function
Dart
🎯 3. أسلوب Clean Architecture

معظم المشاريع الكبيرة تستخدم:

call()
Dart
🧠 ملاحظة مهمة
call ليست كلمة محجوزة ❌

لكن Dart يعطيها ميزة خاصة ✅

⚠️ بدون call

لازم تكتب:

addNoteUseCase.call(note);
Dart
💡 مثال أقوى
class Sum {
  int call(int a, int b) {
    return a + b;
  }
}
Dart
الاستخدام:
final s = Sum();
print(s(2, 3)); // 5 🔥
Dart
🔥 الخلاصة
الشيالمعنى
call()دالة خاصة داخل الكلاس
فائدتهاتخلي الكلاس callable
النتيجةكأنه function