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

View File

@@ -0,0 +1,146 @@
import 'package:flutter/material.dart';
class AppDimensions {
// Private constructor to prevent instantiation
AppDimensions._();
// Screen breakpoints
static const double smallScreenWidth = 460;
static const double tabletWidth = 600;
static const double largeScreenWidth = 1200;
// Padding values
static const double paddingXS = 4.0;
static const double paddingS = 8.0;
static const double paddingM = 12.0;
static const double paddingL = 16.0;
static const double paddingXL = 25.0;
static const double paddingXXL = 30.0;
static const double paddingXXXL = 30.0;
static const double paddingHuge = 40.0;
// Spacing values
static const double spacingXS = 4.0;
static const double spacingS = 8.0;
static const double spacingM = 12.0;
static const double spacingL = 16.0;
static const double spacingXL = 20.0;
static const double spacingXXL = 23.0;
static const double spacingXXXL = 30.0;
static const double spacingHuge = 40.0;
// Font sizes
static const double fontSizeXS = 10.0;
static const double fontSizeS = 12.0;
static const double fontSizeM = 14.0;
static const double fontSizeL = 16.0;
static const double fontSizeXL = 18.0;
static const double fontSizeXXL = 20.0;
static const double fontSizeXXXL = 22.0;
static const double fontSizeHuge = 24.0;
static const double fontSizeTitle = 36.0;
static const double fontSizeTitleLarge = 42.0;
// Icon sizes
static const double iconSizeXS = 16.0;
static const double iconSizeS = 20.0;
static const double iconSizeM = 24.0;
static const double iconSizeL = 30.0;
static const double iconSizeXL = 33.0;
static const double iconSizeXXL = 40.0;
static const double iconSizeHuge = 60.0;
// Border radius
static const double radiusXS = 3.0;
static const double radiusS = 5.0;
static const double radiusM = 8.0;
static const double radiusL = 10.0;
static const double radiusXL = 15.0;
static const double radiusXXL = 20.0;
static const double radiusCircle = 50.0;
// Button heights
static const double buttonHeightS = 40.0;
static const double buttonHeightM = 48.0;
static const double buttonHeightL = 56.0;
// Image heights
static const double imageHeightS = 150.0;
static const double imageHeightM = 200.0;
static const double imageHeightL = 250.0;
// Page indicator sizes
static const double pageIndicatorSize = 10.0;
static const double pageIndicatorSizeActive = 16.0;
// Responsive methods
static bool isSmallScreen(BuildContext context) {
return MediaQuery.of(context).size.width < smallScreenWidth;
}
static bool isTablet(BuildContext context) {
final width = MediaQuery.of(context).size.width;
return width >= tabletWidth && width < largeScreenWidth;
}
static bool isLargeScreen(BuildContext context) {
return MediaQuery.of(context).size.width >= largeScreenWidth;
}
// Responsive padding
static double getHorizontalPadding(BuildContext context) {
return isSmallScreen(context) ? paddingXL : paddingXXL;
}
static double getVerticalPadding(BuildContext context) {
return isSmallScreen(context) ? paddingL : paddingXXL;
}
// Responsive font size
static double getTitleFontSize(BuildContext context) {
final screenWidth = MediaQuery.of(context).size.width;
if (isSmallScreen(context)) {
return screenWidth * 0.07;
} else if (isTablet(context)) {
return fontSizeTitleLarge;
} else {
return screenWidth * 0.08;
}
}
static double getSubtitleFontSize(BuildContext context) {
return isSmallScreen(context) ? fontSizeM : fontSizeL;
}
static double getBodyFontSize(BuildContext context) {
return isSmallScreen(context) ? fontSizeS : fontSizeM;
}
// Responsive spacing
static double getVerticalSpacing(BuildContext context) {
return isSmallScreen(context) ? spacingL : spacingXXL;
}
static double getSmallVerticalSpacing(BuildContext context) {
return isSmallScreen(context) ? spacingM : spacingL;
}
// Responsive icon size
static double getIconSize(BuildContext context) {
return isSmallScreen(context) ? iconSizeM : iconSizeXL;
}
// Screen dimensions
static double screenWidth(BuildContext context) {
return MediaQuery.of(context).size.width;
}
static double screenHeight(BuildContext context) {
return MediaQuery.of(context).size.height;
}
// Safe area padding
static EdgeInsets getSafeAreaPadding(BuildContext context) {
return MediaQuery.of(context).padding;
}
}

View File

@@ -0,0 +1,41 @@
import 'package:dio/dio.dart';
import 'package:get_it/get_it.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../network/api_client.dart';
final sl = GetIt.instance;
Future<void> initializeDependencies() async {
// External
sl.registerLazySingleton<Dio>(() => Dio());
// SharedPreferences
final sharedPreferences = await SharedPreferences.getInstance();
sl.registerLazySingleton<SharedPreferences>(() => sharedPreferences);
// Core
sl.registerLazySingleton<ApiClient>(() => ApiClient(dio: sl()));
// Data sources will be registered here
// Example:
// sl.registerLazySingleton<AuthRemoteDataSource>(
// () => AuthRemoteDataSourceImpl(apiClient: sl()),
// );
// Repositories will be registered here
// Example:
// sl.registerLazySingleton<AuthRepository>(
// () => AuthRepositoryImpl(
// remoteDataSource: sl(),
// localDataSource: sl(),
// ),
// );
// Use cases will be registered here
// Example:
// sl.registerLazySingleton(() => LoginUseCase(repository: sl()));
// Blocs will be registered here
// Example:
// sl.registerFactory(() => LoginBloc(loginUseCase: sl()));
}

View File

@@ -0,0 +1,7 @@
// Add your app-specific enums here
// Example:
// enum UserRole {
// admin,
// user,
// guest,
// }

View File

@@ -0,0 +1,18 @@
class ServerException implements Exception {
final String message;
final int? statusCode;
ServerException({required this.message, this.statusCode});
}
class NetworkException implements Exception {
final String message;
NetworkException({required this.message});
}
class ValidationException implements Exception {
final String message;
ValidationException({required this.message});
}

View File

@@ -0,0 +1,22 @@
import 'package:equatable/equatable.dart';
abstract class Failure extends Equatable {
final String message;
const Failure(this.message);
@override
List<Object> get props => [message];
}
class ServerFailure extends Failure {
const ServerFailure(super.message);
}
class NetworkFailure extends Failure {
const NetworkFailure(super.message);
}
class ValidationFailure extends Failure {
const ValidationFailure(super.message);
}

View File

@@ -0,0 +1,103 @@
import 'package:dio/dio.dart';
class ApiClient {
final Dio dio;
static const String baseUrl = 'YOUR_API_BASE_URL_HERE';
ApiClient({required this.dio}) {
dio.options = BaseOptions(
baseUrl: baseUrl,
connectTimeout: const Duration(seconds: 30),
receiveTimeout: const Duration(seconds: 30),
headers: {
'Content-Type': 'application/json',
'accept': 'text/plain',
},
);
// Add interceptors for logging and error handling
dio.interceptors.add(
LogInterceptor(
requestBody: true,
responseBody: true,
error: true,
requestHeader: true,
responseHeader: false,
),
);
}
Future<Response> post(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
try {
final response = await dio.post(
path,
data: data,
queryParameters: queryParameters,
options: options,
);
return response;
} catch (e) {
rethrow;
}
}
Future<Response> get(
String path, {
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
try {
final response = await dio.get(
path,
queryParameters: queryParameters,
options: options,
);
return response;
} catch (e) {
rethrow;
}
}
Future<Response> put(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
try {
final response = await dio.put(
path,
data: data,
queryParameters: queryParameters,
options: options,
);
return response;
} catch (e) {
rethrow;
}
}
Future<Response> delete(
String path, {
dynamic data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
try {
final response = await dio.delete(
path,
data: data,
queryParameters: queryParameters,
options: options,
);
return response;
} catch (e) {
rethrow;
}
}
}

View File

@@ -0,0 +1,37 @@
class Validators {
static String? validateEmail(String? value) {
if (value == null || value.isEmpty) {
return 'البريد الإلكتروني مطلوب';
}
final emailRegex = RegExp(r'^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$');
if (!emailRegex.hasMatch(value)) {
return 'البريد الإلكتروني غير صحيح';
}
return null;
}
static String? validatePhone(String? value) {
if (value == null || value.isEmpty) {
return 'رقم الهاتف مطلوب';
}
// Add your phone validation logic here
return null;
}
static String? validateRequired(String? value, String fieldName) {
if (value == null || value.isEmpty) {
return '$fieldName مطلوب';
}
return null;
}
static String? validatePassword(String? value) {
if (value == null || value.isEmpty) {
return 'كلمة المرور مطلوبة';
}
if (value.length < 6) {
return 'كلمة المرور يجب أن تكون 6 أحرف على الأقل';
}
return null;
}
}