feat: refactor code
This commit is contained in:
@@ -0,0 +1,28 @@
|
||||
/// تبدیل کد وضعیت HTTP و پیام سرور به پیام خطای فارسیِ قابلنمایش.
|
||||
String errorConvertor(int? statusCode, String? message) {
|
||||
if (statusCode != null) {
|
||||
switch (statusCode) {
|
||||
case 500:
|
||||
return 'ارتباط با سرور برقرار نشد؛ کمی بعد دوباره تلاش کنید';
|
||||
case 429:
|
||||
return 'تعداد درخواستها زیاد است؛ کمی بعد دوباره تلاش کنید';
|
||||
case 401:
|
||||
return 'دسترسی لازم را ندارید؛ دوباره وارد شوید';
|
||||
case 403:
|
||||
return 'این درخواست مجاز نیست';
|
||||
case 404:
|
||||
return message ?? 'یافت نشد';
|
||||
case 409:
|
||||
return message ?? 'قبلاً انجام شده است';
|
||||
case 402:
|
||||
return 'موجودی سکه کافی نیست';
|
||||
case 400:
|
||||
return message ?? 'درخواست نامعتبر است';
|
||||
case 422:
|
||||
return message ?? 'مقادیر وارد شده صحیح نیست';
|
||||
default:
|
||||
return message ?? 'خطای نامشخص';
|
||||
}
|
||||
}
|
||||
return message ?? 'خطا در ارتباط با سرور';
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
import 'package:get_it/get_it.dart';
|
||||
|
||||
import '../../feature/auth/data/data_source/local/auth_local_data.dart';
|
||||
import '../../feature/auth/data/data_source/remote/auth_api_provider.dart';
|
||||
import '../../feature/auth/data/repository/auth_repository_impl.dart';
|
||||
import '../../feature/auth/domain/repository/auth_repository.dart';
|
||||
import '../../feature/auth/domain/use_cases/check_otp_usecase.dart';
|
||||
import '../../feature/auth/domain/use_cases/login_usecase.dart';
|
||||
import '../../feature/auth/domain/use_cases/logout_usecase.dart';
|
||||
import '../../feature/auth/domain/use_cases/update_profile_usecase.dart';
|
||||
import '../../feature/auth/presentation/bloc/auth_bloc.dart';
|
||||
import '../../feature/game/data/data_source/remote/game_api_provider.dart';
|
||||
import '../../feature/game/data/data_source/remote/game_ws_provider.dart';
|
||||
import '../../feature/game/data/repository/game_repository_impl.dart';
|
||||
import '../../feature/game/domain/repository/game_repository.dart';
|
||||
import '../../feature/game/domain/use_cases/get_tables_info_usecase.dart';
|
||||
import '../../feature/game/domain/use_cases/get_tiers_usecase.dart';
|
||||
import '../../feature/game/presentation/bloc/game_bloc.dart';
|
||||
import '../../feature/game/presentation/bloc/private_info_bloc.dart';
|
||||
import '../../feature/game/presentation/bloc/tier_bloc.dart';
|
||||
import '../../feature/profile/data/data_source/remote/profile_api_provider.dart';
|
||||
import '../../feature/profile/data/repository/profile_repository_impl.dart';
|
||||
import '../../feature/profile/domain/repository/profile_repository.dart';
|
||||
import '../../feature/profile/domain/use_cases/get_profile_usecase.dart';
|
||||
import '../../feature/profile/domain/use_cases/save_profile_usecase.dart';
|
||||
import '../../feature/profile/presentation/bloc/profile_bloc.dart';
|
||||
import '../../feature/shop/data/data_source/remote/shop_api_provider.dart';
|
||||
import '../../feature/shop/data/repository/shop_repository_impl.dart';
|
||||
import '../../feature/shop/domain/repository/shop_repository.dart';
|
||||
import '../../feature/shop/domain/use_cases/ad_reward_usecase.dart';
|
||||
import '../../feature/shop/domain/use_cases/buy_card_usecase.dart';
|
||||
import '../../feature/shop/domain/use_cases/get_shop_usecase.dart';
|
||||
import '../../feature/shop/domain/use_cases/purchase_usecase.dart';
|
||||
import '../../feature/shop/domain/use_cases/select_card_usecase.dart';
|
||||
import '../../feature/shop/presentation/bloc/shop_bloc.dart';
|
||||
import '../../feature/wallet/data/data_source/remote/wallet_api_provider.dart';
|
||||
import '../../feature/wallet/data/repository/wallet_repository_impl.dart';
|
||||
import '../../feature/wallet/domain/repository/wallet_repository.dart';
|
||||
import '../../feature/wallet/domain/use_cases/claim_daily_usecase.dart';
|
||||
import '../../feature/wallet/domain/use_cases/get_wallet_usecase.dart';
|
||||
import '../../feature/wallet/presentation/bloc/wallet_bloc.dart';
|
||||
import '../network/api_provider_imp.dart';
|
||||
import '../storage/token_storage.dart';
|
||||
|
||||
final GetIt locator = GetIt.instance;
|
||||
|
||||
/// ثبتِ همهی وابستگیها (تکخط در main فراخوانی میشود).
|
||||
Future<void> setupLocator() async {
|
||||
// --- core ---
|
||||
locator.registerSingleton<TokenStorage>(TokenStorage());
|
||||
locator.registerSingleton<ApiProviderImp>(ApiProviderImp(locator()));
|
||||
|
||||
// --- data sources ---
|
||||
locator.registerSingleton<AuthLocalData>(AuthLocalData(locator()));
|
||||
locator.registerSingleton<AuthApiProvider>(AuthApiProvider());
|
||||
locator.registerSingleton<WalletApiProvider>(WalletApiProvider());
|
||||
locator.registerSingleton<ShopApiProvider>(ShopApiProvider());
|
||||
locator.registerSingleton<ProfileApiProvider>(ProfileApiProvider());
|
||||
locator.registerSingleton<GameApiProvider>(GameApiProvider());
|
||||
locator.registerSingleton<GameWsProvider>(GameWsProvider(locator()));
|
||||
|
||||
// --- repositories ---
|
||||
locator.registerSingleton<AuthRepository>(
|
||||
AuthRepositoryImpl(locator(), locator()));
|
||||
locator.registerSingleton<WalletRepository>(
|
||||
WalletRepositoryImpl(locator()));
|
||||
locator.registerSingleton<ShopRepository>(ShopRepositoryImpl(locator()));
|
||||
locator.registerSingleton<ProfileRepository>(
|
||||
ProfileRepositoryImpl(locator()));
|
||||
locator.registerSingleton<GameRepository>(
|
||||
GameRepositoryImpl(locator(), locator()));
|
||||
|
||||
// --- use cases ---
|
||||
locator.registerSingleton<LoginUseCase>(LoginUseCase(locator()));
|
||||
locator.registerSingleton<CheckOtpUseCase>(CheckOtpUseCase(locator()));
|
||||
locator.registerSingleton<UpdateProfileUseCase>(
|
||||
UpdateProfileUseCase(locator()));
|
||||
locator.registerSingleton<LogoutUseCase>(LogoutUseCase(locator()));
|
||||
locator.registerSingleton<GetWalletUseCase>(GetWalletUseCase(locator()));
|
||||
locator.registerSingleton<ClaimDailyUseCase>(ClaimDailyUseCase(locator()));
|
||||
locator.registerSingleton<GetShopUseCase>(GetShopUseCase(locator()));
|
||||
locator.registerSingleton<BuyCardUseCase>(BuyCardUseCase(locator()));
|
||||
locator.registerSingleton<SelectCardUseCase>(SelectCardUseCase(locator()));
|
||||
locator.registerSingleton<PurchaseUseCase>(PurchaseUseCase(locator()));
|
||||
locator.registerSingleton<AdRewardUseCase>(AdRewardUseCase(locator()));
|
||||
locator.registerSingleton<GetProfileUseCase>(GetProfileUseCase(locator()));
|
||||
locator.registerSingleton<SaveProfileUseCase>(SaveProfileUseCase(locator()));
|
||||
locator.registerSingleton<GetTiersUseCase>(GetTiersUseCase(locator()));
|
||||
locator.registerSingleton<GetTablesInfoUseCase>(
|
||||
GetTablesInfoUseCase(locator()));
|
||||
|
||||
// --- blocs (factory) ---
|
||||
locator.registerFactory<AuthBloc>(
|
||||
() => AuthBloc(locator(), locator(), locator(), locator()));
|
||||
locator.registerFactory<WalletBloc>(() => WalletBloc(locator(), locator()));
|
||||
locator.registerFactory<ShopBloc>(() =>
|
||||
ShopBloc(locator(), locator(), locator(), locator(), locator()));
|
||||
locator.registerFactory<ProfileBloc>(
|
||||
() => ProfileBloc(locator(), locator()));
|
||||
locator.registerFactory<GameBloc>(() => GameBloc(locator()));
|
||||
locator.registerFactory<TierBloc>(() => TierBloc(locator()));
|
||||
locator.registerFactory<PrivateInfoBloc>(() => PrivateInfoBloc(locator()));
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import '../config.dart';
|
||||
import '../storage/token_storage.dart';
|
||||
|
||||
/// کلاینت HTTP با تزریق خودکار توکن Bearer.
|
||||
class ApiClient {
|
||||
final Dio dio;
|
||||
|
||||
ApiClient(TokenStorage storage)
|
||||
: dio = Dio(BaseOptions(
|
||||
baseUrl: AppConfig.apiUrl,
|
||||
connectTimeout: const Duration(seconds: 10),
|
||||
receiveTimeout: const Duration(seconds: 10),
|
||||
headers: {'Accept': 'application/json'},
|
||||
)) {
|
||||
dio.interceptors.add(InterceptorsWrapper(
|
||||
onRequest: (options, handler) async {
|
||||
final token = await storage.read();
|
||||
if (token != null && token.isNotEmpty) {
|
||||
options.headers['Authorization'] = 'Bearer $token';
|
||||
}
|
||||
handler.next(options);
|
||||
},
|
||||
));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
import 'package:dio/dio.dart';
|
||||
|
||||
import '../config.dart';
|
||||
import '../storage/token_storage.dart';
|
||||
|
||||
/// لایهی پایهی شبکه: یک Dio با baseUrl، تزریق خودکار توکن Bearer و
|
||||
/// validateStatus باز (تا کدهای خطا throw نشوند و در repository بررسی شوند).
|
||||
class ApiProviderImp {
|
||||
final Dio dio;
|
||||
|
||||
ApiProviderImp(TokenStorage storage)
|
||||
: dio = Dio(BaseOptions(
|
||||
baseUrl: AppConfig.apiUrl,
|
||||
connectTimeout: const Duration(seconds: 10),
|
||||
receiveTimeout: const Duration(seconds: 15),
|
||||
headers: {'Accept': 'application/json'},
|
||||
validateStatus: (_) => true,
|
||||
)) {
|
||||
dio.interceptors.add(InterceptorsWrapper(
|
||||
onRequest: (options, handler) async {
|
||||
final token = await storage.read();
|
||||
if (token != null && token.isNotEmpty) {
|
||||
options.headers['Authorization'] = 'Bearer $token';
|
||||
}
|
||||
handler.next(options);
|
||||
},
|
||||
));
|
||||
}
|
||||
|
||||
Future<Response> get(String path, {Map<String, dynamic>? query}) =>
|
||||
dio.get(path, queryParameters: query);
|
||||
|
||||
Future<Response> post(String path, {Object? body}) =>
|
||||
dio.post(path, data: body);
|
||||
|
||||
Future<Response> put(String path, {Object? body}) =>
|
||||
dio.put(path, data: body);
|
||||
|
||||
Future<Response> delete(String path, {Object? body}) =>
|
||||
dio.delete(path, data: body);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
/// نتیجهی یک عملیات دادهای: موفق (داده) یا خطا (پیام).
|
||||
/// لایهی data همیشه DataState برمیگرداند تا لایههای بالا throw نگیرند.
|
||||
abstract class DataState<T> {
|
||||
final T? data;
|
||||
final String? error;
|
||||
const DataState(this.data, this.error);
|
||||
}
|
||||
|
||||
class DataSuccess<T> extends DataState<T> {
|
||||
const DataSuccess(T data) : super(data, null);
|
||||
}
|
||||
|
||||
class DataError<T> extends DataState<T> {
|
||||
const DataError(String error) : super(null, error);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/// قرارداد یوزکیس: هر یوزکیس با یک پارامتر فراخوانی میشود و یک Future برمیگرداند.
|
||||
abstract class UseCase<T, P> {
|
||||
Future<T> call(P params);
|
||||
}
|
||||
|
||||
/// نبودِ پارامتر (برای یوزکیسهای بدون ورودی).
|
||||
class NoParams {
|
||||
const NoParams();
|
||||
}
|
||||
|
||||
/// پارامتر بررسی کد یکبارمصرف.
|
||||
class OtpParams {
|
||||
final String mobile;
|
||||
final String token;
|
||||
const OtpParams(this.mobile, this.token);
|
||||
}
|
||||
|
||||
/// پارامتر بهروزرسانی پروفایل (نام و آواتار).
|
||||
class ProfileParams {
|
||||
final String firstName;
|
||||
final String avatar;
|
||||
const ProfileParams(this.firstName, this.avatar);
|
||||
}
|
||||
|
||||
/// پارامتر خرید درونبرنامهای (IAP).
|
||||
class PurchaseParams {
|
||||
final String store;
|
||||
final String kind;
|
||||
final String productId;
|
||||
final String token;
|
||||
const PurchaseParams({
|
||||
required this.store,
|
||||
required this.kind,
|
||||
required this.productId,
|
||||
required this.token,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user