174 lines
5.6 KiB
Markdown
174 lines
5.6 KiB
Markdown
# هيكلية المشروع (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
|