Add Note

🧭 التسلسل المنطقي (احفظه)
UI (Add Page)

Cubit

UseCase

Repository (abstract)

RepositoryImpl

DataSource

Supabase
Dart
🧱 1) DataSource (أول مكان فعلي يحدث فيه العمل)
📁 notes_remote_datasource.dart
📄 الكود + شرح داخلي
import 'package:supabase_flutter/supabase_flutter.dart';
import '../models/note_model.dart';

/// هذا الكلاس مسؤول فقط عن الاتصال مع Supabase
/// ❌ لا يعرف Cubit
/// ❌ لا يعرف UI
/// ✅ فقط API

class NotesRemoteDataSource {
  final SupabaseClient client;

  /// نستقبل client من الخارج (Dependency Injection)
  NotesRemoteDataSource(this.client);

  /// 🔥 دالة إضافة ملاحظة
  Future<void> addNote(NoteModel note) async {

    /// insert = إدخال بيانات إلى الجدول
    /// note.toJson() = تحويل object إلى Map
    await client
        .from('notes') // اسم الجدول
        .insert(note.toJson());
  }
}
Dart
🧠 شرح الملف
هذا الملف هو "المتحدث الوحيد مع Supabase"
أي عملية API تتم هنا فقط
Dart
🧱 2) RepositoryImpl (التحويل + الربط)
📁 notes_repository_impl.dart
📄 الكود + شرح
import '../../domain/entities/note.dart';
import '../../domain/repository/notes_repository.dart';
import '../datasource/notes_remote_datasource.dart';
import '../models/note_model.dart';

/// هذا الكلاس يطبق interface الموجود في domain
/// مهمته:
/// تحويل Entity → Model
/// ثم إرسالها للـ DataSource

class NotesRepositoryImpl implements NotesRepository {
  final NotesRemoteDataSource remote;

  NotesRepositoryImpl(this.remote);

  @override
  Future<void> addNote(Note note) async {

    /// تحويل Entity إلى Model
    final model = NoteModel(
      id: note.id,
      title: note.title,
      content: note.content,
    );

    /// إرسال البيانات للـ API
    await remote.addNote(model);
  }
}
Dart
🧠 شرح الملف
هذا هو "الجسر" بين domain و data
Dart
🧱 3) Repository (Interface)
📁 notes_repository.dart
📄 الكود
import '../entities/note.dart';

/// هذا مجرد عقد (contract)
/// لا يحتوي تنفيذ

abstract class NotesRepository {

  /// تعريف العملية فقط
  Future<void> addNote(Note note);
}
Dart
🧠 شرح
Domain لا يعرف Supabase
فقط يعرف أن هناك عملية "إضافة"
Dart
🧱 4) UseCase (منطق العملية)
📁 add_note_usecase.dart
📄 الكود
import '../entities/note.dart';
import '../repository/notes_repository.dart';

/// UseCase = يمثل "فعل" في التطبيق
/// هنا: إضافة ملاحظة

class AddNoteUseCase {
  final NotesRepository repo;

  AddNoteUseCase(this.repo);

  /// call() يسمح باستدعاء الكلاس كدالة
  Future<void> call(Note note) async {

    /// تنفيذ العملية عبر repository
    await repo.addNote(note);
  }
}
Dart
🧠 شرح
UseCase = الطبقة التي تقول "ماذا نفعل"
وليس "كيف نفعل"
Dart
🧱 5) Cubit (إدارة الحالة)
📁 notes_cubit.dart
📄 الكود
import 'package:flutter_bloc/flutter_bloc.dart';
import '../../domain/entities/note.dart';
import '../../domain/usecases/add_note_usecase.dart';
import '../../domain/usecases/get_notes_usecase.dart';
import 'notes_state.dart';

/// Cubit = مدير الحالة
/// لا يعرف Supabase
/// لا يعرف Model
/// فقط ينادي UseCases

class NotesCubit extends Cubit<NotesState> {
  final GetNotesUseCase getNotesUseCase;
  final AddNoteUseCase addNoteUseCase;

  NotesCubit(
    this.getNotesUseCase,
    this.addNoteUseCase,
  ) : super(NotesInitial());

  /// إضافة ملاحظة
  Future<void> addNote(Note note) async {

    /// تنفيذ العملية
    await addNoteUseCase(note);

    /// تحديث القائمة بعد الإضافة
    fetchNotes();
  }

  /// جلب البيانات
  Future<void> fetchNotes() async {
    emit(NotesLoading());

    try {
      final notes = await getNotesUseCase();
      emit(NotesLoaded(notes));
    } catch (e) {
      emit(NotesError(e.toString()));
    }
  }
}
Dart
🧠 شرح
Cubit = حلقة الوصل بين UI و UseCase
Dart
🧱 6) صفحة إضافة ملاحظة (UI)
📁 add_note_page.dart
📄 الكود
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:uuid/uuid.dart';

import '../../domain/entities/note.dart';
import '../cubit/notes_cubit.dart';

/// هذه الصفحة مسؤولة فقط عن:
/// أخذ input من المستخدم

class AddNotePage extends StatefulWidget {
  const AddNotePage({super.key});

  @override
  State createState() => _AddNotePageState();
}

class _AddNotePageState extends State {

  /// Controllers لجلب النص من الحقول
  final titleController = TextEditingController();
  final contentController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("إضافة ملاحظة")),

      body: Padding(
        padding: const EdgeInsets.all(16),

        child: Column(
          children: [

            /// إدخال العنوان
            TextField(
              controller: titleController,
            ),

            /// إدخال المحتوى
            TextField(
              controller: contentController,
            ),

            const SizedBox(height: 20),

            /// زر الحفظ
            ElevatedButton(
              onPressed: () {

                /// إنشاء Note
                final note = Note(
                  id: const Uuid().v4(),
                  title: titleController.text,
                  content: contentController.text,
                );

                /// إرسال البيانات للـ Cubit
                context.read().addNote(note);

                /// الرجوع للصفحة السابقة
                Navigator.pop(context);
              },
              child: const Text("حفظ"),
            ),
          ],
        ),
      ),
    );
  }
}
Dart
🧠 شرح
UI لا يحتوي logic
فقط يجمع البيانات ويرسلها
Dart
🧱 7) زر الإضافة
📁 notes_page.dart
✏️ أضف:
floatingActionButton: FloatingActionButton(
  onPressed: () {
    Navigator.push(
      context,
      MaterialPageRoute(
        builder: (_) => const AddNotePage(),
      ),
    );
  },
  child: const Icon(Icons.add),
),
Dart
💥 الربط النهائي (مهم جداً)
AddPage

Cubit.addNote()

UseCase

Repository

RepositoryImpl

DataSource

Supabase

رجوع

fetchNotes()

UI يتحدث
Dart