This commit is contained in:
Mohammed Al-Samarraie
2026-01-13 12:43:43 +03:00
parent 4df24f5d8d
commit ac8a769ff0
23 changed files with 945 additions and 2 deletions

173
lib/ARCHITECTURE.md Normal file
View File

@@ -0,0 +1,173 @@
# هيكلية المشروع (Project Architecture)
هذا المشروع يتبع نمط Clean Architecture مع فصل واضح بين الطبقات.
## الهيكلية العامة
```
lib/
├── core/ # المكونات الأساسية المشتركة
│ ├── constants/ # الثوابت (مثل الأبعاد)
│ ├── di/ # Dependency Injection (GetIt)
│ ├── enums/ # التعدادات
│ ├── error/ # معالجة الأخطاء (Exceptions & Failures)
│ ├── network/ # عميل API (ApiClient)
│ └── utils/ # الأدوات المساعدة
├── data/ # طبقة البيانات
│ ├── datasources/ # مصادر البيانات (Remote & Local)
│ ├── dto/ # Data Transfer Objects (للاتصال مع API)
│ └── repositories/ # تطبيقات الـ Repositories
├── domain/ # طبقة الأعمال (Business Logic)
│ ├── models/ # نماذج الأعمال
│ ├── repositories/ # واجهات الـ Repositories
│ └── usecases/ # حالات الاستخدام (Use Cases)
├── presentation/ # طبقة العرض
│ ├── blocs/ # State Management (BLoC)
│ ├── screens/ # الشاشات
│ └── widgets/ # الويدجتات القابلة لإعادة الاستخدام
├── models/ # النماذج القديمة (يمكن نقلها لـ domain/models)
├── screens/ # الشاشات القديمة (يمكن نقلها لـ presentation/screens)
├── services/ # الخدمات القديمة
└── widgets/ # الويدجتات القديمة (يمكن نقلها لـ presentation/widgets)
```
## كيفية الاستخدام
### 1. إضافة API جديد
#### أ) إنشاء DTO في `data/dto/`
```dart
class LoginDto {
final String phoneNumber;
final String password;
LoginDto({required this.phoneNumber, required this.password});
Map<String, dynamic> toJson() => {
'phoneNumber': phoneNumber,
'password': password,
};
}
```
#### ب) إنشاء Remote Data Source في `data/datasources/`
```dart
abstract class AuthRemoteDataSource {
Future<LoginResponseDto> login(LoginDto dto);
}
class AuthRemoteDataSourceImpl implements AuthRemoteDataSource {
final ApiClient apiClient;
AuthRemoteDataSourceImpl({required this.apiClient});
@override
Future<LoginResponseDto> login(LoginDto dto) async {
try {
final response = await apiClient.post('/Auth/login', data: dto.toJson());
// Handle response
} on DioException catch (e) {
// Handle errors
}
}
}
```
#### ج) إنشاء Repository Interface في `domain/repositories/`
```dart
abstract class AuthRepository {
Future<Either<Failure, LoginResponseModel>> login(LoginRequest request);
}
```
#### د) إنشاء Repository Implementation في `data/repositories/`
```dart
class AuthRepositoryImpl implements AuthRepository {
final AuthRemoteDataSource remoteDataSource;
AuthRepositoryImpl({required this.remoteDataSource});
@override
Future<Either<Failure, LoginResponseModel>> login(LoginRequest request) async {
try {
final dto = LoginDto(...);
final responseDto = await remoteDataSource.login(dto);
final model = _convertDtoToModel(responseDto);
return Right(model);
} on ServerException catch (e) {
return Left(ServerFailure(e.message));
}
}
}
```
#### هـ) إنشاء Use Case في `domain/usecases/`
```dart
class LoginUseCase {
final AuthRepository repository;
LoginUseCase({required this.repository});
Future<Either<Failure, LoginResponseModel>> call(LoginRequest request) {
return repository.login(request);
}
}
```
#### و) تسجيل في `core/di/injection_container.dart`
```dart
// Data source
sl.registerLazySingleton<AuthRemoteDataSource>(
() => AuthRemoteDataSourceImpl(apiClient: sl()),
);
// Repository
sl.registerLazySingleton<AuthRepository>(
() => AuthRepositoryImpl(remoteDataSource: sl()),
);
// Use case
sl.registerLazySingleton(() => LoginUseCase(repository: sl()));
```
### 2. استخدام في BLoC
```dart
class LoginBloc extends Bloc<LoginEvent, LoginState> {
final LoginUseCase loginUseCase;
LoginBloc({required this.loginUseCase}) : super(LoginInitial()) {
on<LoginSubmitted>(_onLoginSubmitted);
}
Future<void> _onLoginSubmitted(
LoginSubmitted event,
Emitter<LoginState> emit,
) async {
emit(LoginLoading());
final result = await loginUseCase(event.request);
result.fold(
(failure) => emit(LoginError(failure.message)),
(response) => emit(LoginSuccess(response)),
);
}
}
```
## الحزم المستخدمة
- `dio`: للاتصال بالـ API
- `get_it`: لإدارة Dependency Injection
- `dartz`: لاستخدام `Either` للتعامل مع الأخطاء
- `equatable`: للمساواة بين الكائنات
- `shared_preferences`: للتخزين المحلي
## ملاحظات مهمة
1. **تحديث baseUrl**: قم بتحديث `baseUrl` في `core/network/api_client.dart`
2. **إضافة Token**: يمكن إضافة interceptor في `ApiClient` لإضافة token تلقائياً
3. **معالجة الأخطاء**: جميع الأخطاء تمر عبر `Exceptions` ثم `Failures`
4. **التحويل**: DTOs للـ API، Models للـ Domain