notes_cubit.dart

📁 الملف: notes_cubit.dart
🧠 أولاً: شو هو Cubit أصلاً؟
Cubit = مدير الحالة (State Manager)
Dart
🎯 وظيفته في هذا المشروع:

👉 جلب البيانات
👉 إرسالها للـ UI
👉 التحكم بالحالات (Loading / Success / Error)

📄 الكود كامل
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../domain/entities/note.dart';
import '../../domain/usecases/get_notes_usecase.dart';
import 'notes_state.dart';

class NotesCubit extends Cubit<NotesState> {
  final GetNotesUseCase getNotesUseCase; 
   NotesCubit(
    this.getNotesUseCase,
  ) : super(NotesInitial()); 
  
   Future<void> fetchNotes() async {
    emit(NotesLoading());
    try {
      final notes = await getNotesUseCase();
      emit(NotesLoaded(notes));
    } catch (e) {
      emit(NotesError(e.toString()));
    }
  }
}
Dart
🔍 الآن نشرح كل جزء بالتفصيل
🧱 1. import flutter_bloc
import 'package:flutter_bloc/flutter_bloc.dart';
Dart
🧠 هذا يجلب:
  • Cubit
  • Bloc
  • أدوات إدارة الحالة
🎯 نحن نستخدم:
Cubit
Dart
🧱 2. import Note
import '../../domain/entities/note.dart';
Dart
🧠 لماذا؟

👉 لأننا سنرجع:

List<Note>
Dart
🧱 3. import UseCase
import '../../domain/usecases/get_notes_usecase.dart';
Dart
🧠 هذا أهم import

👉 لأن Cubit لا يتعامل مع Repository
👉 بل يتعامل مع UseCase

🎯 يعني:
CubitUseCase
Dart
🧱 4. import state
import 'notes_state.dart';
Dart
🧠 هذا يحتوي:
  • NotesInitial
  • NotesLoading
  • NotesLoaded
  • NotesError
🎯 Cubit يستخدمه لإخبار UI بالحالة
🧱 5. تعريف الكلاس
class NotesCubit extends Cubit<NotesState>
Dart
🧠 نشرحها:
🔹 class NotesCubit

👉 هذا كلاس

🔹 extends Cubit<NotesState>

👉 يعني:

هذا الكلاس يرث من Cubit
Dart
🎯 NotesState

👉 نوع الحالة اللي Cubit يديرها

💥 إذن:
NotesCubit = مدير حالات من نوع NotesState
Dart
🧱 6. المتغير
final GetNotesUseCase getNotesUseCase;
Dart
🧠 هذا:

👉 object من UseCase

🎯 دوره:
تنفيذ عملية جلب الملاحظات
Dart
💡 final

👉 لا يمكن تغييره

🧱 7. constructor
NotesCubit(
  this.getNotesUseCase,
) : super(NotesInitial());
Dart
🧠 نشرحها خطوة خطوة
🔹 this.getNotesUseCase

👉 نمرر UseCase من الخارج

🔥 هذا اسمه:
Dependency Injection
Dart
💡 لماذا؟
  • فصل الطبقات
  • اختبار أسهل
🔹 super(NotesInitial())

👉 نحدد الحالة الابتدائية

🎯 يعني:

عند إنشاء Cubit → الحالة = Initial
Dart
🧱 8. الدالة fetchNotes 🔥
Future<void> fetchNotes() async
Dart
🧠 تحليلها:
🔹 Future<void>

👉 دالة غير متزامنة
👉 لا ترجع قيمة

🔹 async

👉 نستخدم await داخلها

🔥 داخل الدالة
🟠 1. emit loading
emit(NotesLoading());
Dart
🧠 ماذا يحدث؟

👉 Cubit يقول:

أنا الآن أحمل البيانات
Dart
🎯 UI سيعرض:
CircularProgressIndicator
Dart
🟡 2. try
try {
Dart
🧠 لماذا؟

👉 لأن API ممكن يفشل

🟢 3. استدعاء UseCase
final notes = await getNotesUseCase();
Dart
🔥 أهم سطر
🧠 ماذا يحدث هنا؟
1️⃣ Cubit ينادي:
UseCase
Dart
2️⃣ UseCase ينادي:
Repository
Dart
3️⃣ Repository ينادي:
DataSource
Dart
4️⃣ DataSource ينادي:
Supabase
Dart
5️⃣ يرجع:
List<Note>
Dart
💥 السلسلة كاملة
CubitUseCaseRepositoryDataSourceSupabase
Dart
🟣 4. emit success
emit(NotesLoaded(notes));
Dart
🧠 ماذا يحدث؟

👉 Cubit يقول:

البيانات وصلت
Dart
🎯 UI يعرض القائمة
🔴 5. catch
} catch (e) {
Dart
🧠 إذا صار خطأ
🔥 مثال:
  • لا يوجد إنترنت
  • خطأ في Supabase
🔴 6. emit error
emit(NotesError(e.toString()));
Dart
🧠 ماذا يحدث؟

👉 إرسال رسالة خطأ

🎯 UI يعرض:
Error message
Dart
🔁 التدفق الكامل
UI → Cubit.fetchNotes()

emit(Loading)

UseCase()

Repository

DataSource

Supabase

رجوع البيانات

emit(Loaded)

UI يعرض
💥 خلاصة قوية جداً
🎯 Cubit مسؤول عن:
المهمةنعم/لا
إدارة الحالة
جلب البيانات❌ (UseCase)
منطق العمل
التواصل مع API
🧠 جملة تحفظها
Cubit controls state, not logic
Dart