feat:dio client done
This commit is contained in:
3
lib/core/constants/api_const.dart
Normal file
3
lib/core/constants/api_const.dart
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
abstract class ApiConst {
|
||||||
|
static const String baseUrl = "https://superapp.felixits.uz/api/v1";
|
||||||
|
}
|
||||||
@@ -2,3 +2,4 @@ export 'app_locale_keys.dart';
|
|||||||
export 'sizes_consts.dart';
|
export 'sizes_consts.dart';
|
||||||
export 'l10n.dart';
|
export 'l10n.dart';
|
||||||
export 'time_delay_cons.dart';
|
export 'time_delay_cons.dart';
|
||||||
|
export 'api_const.dart';
|
||||||
@@ -2,6 +2,6 @@ abstract class TimeDelayConst {
|
|||||||
static const Duration durationMill150 = Duration(milliseconds: 150);
|
static const Duration durationMill150 = Duration(milliseconds: 150);
|
||||||
static const Duration durationMill300 = Duration(milliseconds: 300);
|
static const Duration durationMill300 = Duration(milliseconds: 300);
|
||||||
static const Duration durationMill800 = Duration(milliseconds: 800);
|
static const Duration durationMill800 = Duration(milliseconds: 800);
|
||||||
|
static const Duration durationMill3500 = Duration(milliseconds: 3500);
|
||||||
static const Duration duration3 = Duration(seconds: 3);
|
static const Duration duration3 = Duration(seconds: 3);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,3 +12,5 @@ export 'l10n/app_localizations_ru.dart';
|
|||||||
export 'l10n/app_localizations_uz.dart';
|
export 'l10n/app_localizations_uz.dart';
|
||||||
export 'services/services.dart';
|
export 'services/services.dart';
|
||||||
export 'utils/app_utils.dart';
|
export 'utils/app_utils.dart';
|
||||||
|
export 'exceptions/exceptions.dart';
|
||||||
|
export 'exceptions/failure.dart';
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
// coverage:ignore-file
|
// coverage:ignore-file
|
||||||
|
|
||||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||||
|
import 'package:dio/dio.dart' as _i361;
|
||||||
import 'package:get_it/get_it.dart' as _i174;
|
import 'package:get_it/get_it.dart' as _i174;
|
||||||
import 'package:injectable/injectable.dart' as _i526;
|
import 'package:injectable/injectable.dart' as _i526;
|
||||||
|
|
||||||
@@ -24,7 +25,9 @@ import '../../feature/main/presentation/blocs/main_bloc/main_bloc.dart'
|
|||||||
import '../../feature/on_boarding/presentation/blocs/splash_bloc/splash_bloc.dart'
|
import '../../feature/on_boarding/presentation/blocs/splash_bloc/splash_bloc.dart'
|
||||||
as _i311;
|
as _i311;
|
||||||
import '../../food_delivery_client.dart' as _i321;
|
import '../../food_delivery_client.dart' as _i321;
|
||||||
|
import '../network/dio_client.dart' as _i667;
|
||||||
import '../router/app_routes.dart' as _i152;
|
import '../router/app_routes.dart' as _i152;
|
||||||
|
import '../services/request_handler_service.dart' as _i354;
|
||||||
import '../services/storage_service.dart' as _i306;
|
import '../services/storage_service.dart' as _i306;
|
||||||
|
|
||||||
extension GetItInjectableX on _i174.GetIt {
|
extension GetItInjectableX on _i174.GetIt {
|
||||||
@@ -34,6 +37,7 @@ extension GetItInjectableX on _i174.GetIt {
|
|||||||
_i526.EnvironmentFilter? environmentFilter,
|
_i526.EnvironmentFilter? environmentFilter,
|
||||||
}) {
|
}) {
|
||||||
final gh = _i526.GetItHelper(this, environment, environmentFilter);
|
final gh = _i526.GetItHelper(this, environment, environmentFilter);
|
||||||
|
final dioModule = _$DioModule();
|
||||||
gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc());
|
gh.factory<_i1007.HomeBloc>(() => _i1007.HomeBloc());
|
||||||
gh.factory<_i728.BasketBloc>(() => _i728.BasketBloc());
|
gh.factory<_i728.BasketBloc>(() => _i728.BasketBloc());
|
||||||
gh.factory<_i991.BrowseBloc>(() => _i991.BrowseBloc());
|
gh.factory<_i991.BrowseBloc>(() => _i991.BrowseBloc());
|
||||||
@@ -41,9 +45,16 @@ extension GetItInjectableX on _i174.GetIt {
|
|||||||
gh.factory<_i311.SplashBloc>(() => _i311.SplashBloc());
|
gh.factory<_i311.SplashBloc>(() => _i311.SplashBloc());
|
||||||
gh.singleton<_i306.StorageService>(() => _i306.StorageService());
|
gh.singleton<_i306.StorageService>(() => _i306.StorageService());
|
||||||
gh.singleton<_i152.AppRoutes>(() => _i152.AppRoutes());
|
gh.singleton<_i152.AppRoutes>(() => _i152.AppRoutes());
|
||||||
|
gh.lazySingleton<_i667.DioClient>(() => _i667.DioClient());
|
||||||
gh.factory<_i942.LanguageBloc>(
|
gh.factory<_i942.LanguageBloc>(
|
||||||
() => _i942.LanguageBloc(gh<_i321.StorageService>()),
|
() => _i942.LanguageBloc(gh<_i321.StorageService>()),
|
||||||
);
|
);
|
||||||
|
gh.lazySingleton<_i361.Dio>(() => dioModule.dio(gh<_i667.DioClient>()));
|
||||||
|
gh.singleton<_i354.RequestHandlerService>(
|
||||||
|
() => _i354.RequestHandlerService(gh<_i361.Dio>()),
|
||||||
|
);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _$DioModule extends _i667.DioModule {}
|
||||||
|
|||||||
32
lib/core/exceptions/exceptions.dart
Normal file
32
lib/core/exceptions/exceptions.dart
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
|
class ServerException implements Exception {
|
||||||
|
final String errorMessage;
|
||||||
|
final String errorKey;
|
||||||
|
final num statusCode;
|
||||||
|
|
||||||
|
const ServerException({
|
||||||
|
required this.statusCode,
|
||||||
|
required this.errorMessage,
|
||||||
|
required this.errorKey,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
String toString() {
|
||||||
|
return 'ServerException(statusCode: $statusCode, errorMessage: $errorMessage, errorKey: $errorKey)';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class CustomDioException implements Exception {
|
||||||
|
final String errorMessage;
|
||||||
|
final DioExceptionType type;
|
||||||
|
final int? statusCode;
|
||||||
|
|
||||||
|
CustomDioException({required this.errorMessage, required this.type, this.statusCode});
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParsingException implements Exception {
|
||||||
|
final String errorMessage;
|
||||||
|
|
||||||
|
const ParsingException({required this.errorMessage});
|
||||||
|
}
|
||||||
44
lib/core/exceptions/failure.dart
Normal file
44
lib/core/exceptions/failure.dart
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import 'package:equatable/equatable.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
|
class Failure extends Equatable {
|
||||||
|
final String? errorMessage;
|
||||||
|
final String? errorKey;
|
||||||
|
|
||||||
|
const Failure({
|
||||||
|
this.errorMessage,
|
||||||
|
this.errorKey,
|
||||||
|
}); //error key kere bomasa required qilish shartamas
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [
|
||||||
|
errorMessage,
|
||||||
|
errorKey,
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
class ServerFailure extends Failure {
|
||||||
|
final num statusCode;
|
||||||
|
|
||||||
|
const ServerFailure({
|
||||||
|
required super.errorMessage,
|
||||||
|
required this.statusCode,
|
||||||
|
required super.errorKey,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class DioFailure extends Failure {
|
||||||
|
final DioExceptionType type;
|
||||||
|
final int? statusCode;
|
||||||
|
|
||||||
|
const DioFailure({
|
||||||
|
required super.errorMessage,
|
||||||
|
this.type = DioExceptionType.badResponse,
|
||||||
|
this.statusCode,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
class ParsingFailure extends Failure {
|
||||||
|
const ParsingFailure({required super.errorMessage});
|
||||||
|
}
|
||||||
|
|
||||||
|
class CacheFailure extends Failure {}
|
||||||
44
lib/core/network/dio_client.dart
Normal file
44
lib/core/network/dio_client.dart
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
|
import 'package:food_delivery_client/core/network/header_interceptors.dart';
|
||||||
|
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||||
|
import 'error_handler_interceptor.dart';
|
||||||
|
|
||||||
|
@module
|
||||||
|
abstract class DioModule {
|
||||||
|
@lazySingleton
|
||||||
|
Dio dio(DioClient dioClient) => dioClient.dio;
|
||||||
|
}
|
||||||
|
|
||||||
|
@lazySingleton
|
||||||
|
class DioClient {
|
||||||
|
final BaseOptions _dioBaseOptions = BaseOptions(
|
||||||
|
baseUrl: ApiConst.baseUrl,
|
||||||
|
connectTimeout: TimeDelayConst.durationMill3500,
|
||||||
|
receiveTimeout: TimeDelayConst.durationMill3500,
|
||||||
|
followRedirects: false,
|
||||||
|
validateStatus: (status) => status != null && status >= 200 && status < 300,
|
||||||
|
);
|
||||||
|
|
||||||
|
Dio get dio {
|
||||||
|
final Dio dio = Dio(_dioBaseOptions);
|
||||||
|
dio.interceptors
|
||||||
|
..add(HeaderInterceptors())
|
||||||
|
..add(ErrorHandlerInterceptors())
|
||||||
|
..add(
|
||||||
|
LogInterceptor(
|
||||||
|
requestHeader: true,
|
||||||
|
requestBody: true,
|
||||||
|
responseBody: true,
|
||||||
|
error: true,
|
||||||
|
request: true,
|
||||||
|
logPrint: (object) {
|
||||||
|
if (kDebugMode) {
|
||||||
|
log('Error ${object.toString()}');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return dio;
|
||||||
|
}
|
||||||
|
}
|
||||||
41
lib/core/network/error_handler_interceptor.dart
Normal file
41
lib/core/network/error_handler_interceptor.dart
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
|
import '../../feature/common/data/models/error_model.dart';
|
||||||
|
|
||||||
|
class ErrorHandlerInterceptors extends Interceptor {
|
||||||
|
@override
|
||||||
|
void onError(DioException err, ErrorInterceptorHandler handler) {
|
||||||
|
if (err.response != null && err.response!.statusCode != null) {
|
||||||
|
if (err.response?.data is String) {
|
||||||
|
final errorMessage = err.response?.data as String?;
|
||||||
|
final error = ErrorModel(
|
||||||
|
detail: errorMessage?.replaceAll(RegExp(r'<[^>]+>'), '') ?? '',
|
||||||
|
);
|
||||||
|
handler.next(
|
||||||
|
DioException(
|
||||||
|
requestOptions: err.requestOptions,
|
||||||
|
response: Response(
|
||||||
|
requestOptions: err.requestOptions,
|
||||||
|
data: error.toJson(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
handler.next(err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const error = ErrorModel(detail: "");
|
||||||
|
handler.next(
|
||||||
|
DioException(
|
||||||
|
requestOptions: err.requestOptions,
|
||||||
|
response: Response(
|
||||||
|
requestOptions: err.requestOptions,
|
||||||
|
data: error.toJson(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
lib/core/network/header_interceptors.dart
Normal file
17
lib/core/network/header_interceptors.dart
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import 'package:dio/dio.dart';
|
||||||
|
|
||||||
|
class HeaderInterceptors extends Interceptor {
|
||||||
|
HeaderInterceptors._internal();
|
||||||
|
|
||||||
|
static final HeaderInterceptors _interceptors =
|
||||||
|
HeaderInterceptors._internal();
|
||||||
|
|
||||||
|
factory HeaderInterceptors() {
|
||||||
|
return _interceptors;
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
|
||||||
|
handler.next(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
77
lib/core/services/request_handler_service.dart
Normal file
77
lib/core/services/request_handler_service.dart
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
import 'dart:developer';
|
||||||
|
|
||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:dio/dio.dart';
|
||||||
|
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||||
|
|
||||||
|
import '../../feature/common/data/models/error_model.dart';
|
||||||
|
|
||||||
|
enum RequestMethodEnum { get, post, put, delete, patch }
|
||||||
|
|
||||||
|
@singleton
|
||||||
|
class RequestHandlerService {
|
||||||
|
final Dio dio;
|
||||||
|
|
||||||
|
const RequestHandlerService(this.dio);
|
||||||
|
|
||||||
|
Future<T> handleRequest<T>({
|
||||||
|
required Future<T> Function(Response) fromJson,
|
||||||
|
required String path,
|
||||||
|
RequestMethodEnum? method,
|
||||||
|
Options? options,
|
||||||
|
Map<String, dynamic>? queryParameters,
|
||||||
|
Object? data,
|
||||||
|
Dio? newDio,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final response = await (newDio ?? dio).request(
|
||||||
|
path,
|
||||||
|
options:
|
||||||
|
options ??
|
||||||
|
Options(method: method?.name ?? RequestMethodEnum.get.name),
|
||||||
|
queryParameters: queryParameters,
|
||||||
|
data: data,
|
||||||
|
);
|
||||||
|
final result = fromJson.call(response);
|
||||||
|
return result;
|
||||||
|
} on DioException catch (e) {
|
||||||
|
final errorResponse = ErrorModel.fromJson(e.response?.data);
|
||||||
|
throw CustomDioException(
|
||||||
|
errorMessage: errorResponse.detail,
|
||||||
|
type: e.type,
|
||||||
|
statusCode: e.response?.statusCode,
|
||||||
|
);
|
||||||
|
} on ParsingException {
|
||||||
|
rethrow;
|
||||||
|
} on Exception catch (e) {
|
||||||
|
throw ParsingException(errorMessage: e.toString());
|
||||||
|
} catch (e) {
|
||||||
|
throw ParsingException(errorMessage: e.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Either<Failure, T>> handleRequestInRepository<T>({
|
||||||
|
required Future<T> Function() onRequest,
|
||||||
|
String debugLabel = '',
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
final result = await onRequest.call();
|
||||||
|
return Right(result);
|
||||||
|
} on ParsingException catch (e) {
|
||||||
|
log("ParsingException in $debugLabel: ${e.errorMessage}");
|
||||||
|
return Left(ParsingFailure(errorMessage: e.errorMessage));
|
||||||
|
} on CustomDioException catch (e) {
|
||||||
|
log("CustomDioException in $debugLabel: ${e.errorMessage}");
|
||||||
|
return Left(
|
||||||
|
DioFailure(
|
||||||
|
errorMessage: e.errorMessage,
|
||||||
|
type: e.type,
|
||||||
|
statusCode: e.statusCode,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} on Exception catch (e) {
|
||||||
|
log("Exception in $debugLabel: ${e.toString()}");
|
||||||
|
return Left(ParsingFailure(errorMessage: e.toString()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
lib/core/usecase/usecase.dart
Normal file
15
lib/core/usecase/usecase.dart
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
import 'package:dartz/dartz.dart';
|
||||||
|
import 'package:food_delivery_client/food_delivery_client.dart';
|
||||||
|
|
||||||
|
mixin UseCase<Type, Params> {
|
||||||
|
Future<Either<Failure, Type>> call(Params params);
|
||||||
|
}
|
||||||
|
|
||||||
|
mixin StreamUseCase<Type, Params> {
|
||||||
|
Stream<Either<Failure, Type>> call(Params params);
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoParams extends Equatable {
|
||||||
|
@override
|
||||||
|
List<Object?> get props => [];
|
||||||
|
}
|
||||||
20
lib/feature/common/data/models/error_model.dart
Normal file
20
lib/feature/common/data/models/error_model.dart
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
import '../../domain/entities/error_entity.dart';
|
||||||
|
|
||||||
|
class ErrorModel extends ErrorEntity {
|
||||||
|
const ErrorModel({super.detail});
|
||||||
|
|
||||||
|
Map<String, dynamic> toJson() {
|
||||||
|
return {"detail": detail};
|
||||||
|
}
|
||||||
|
|
||||||
|
factory ErrorModel.fromJson(Map<String, dynamic> data) {
|
||||||
|
if (data.containsKey("detail")) {
|
||||||
|
if (data['detail'] is List) {
|
||||||
|
return ErrorModel(detail: data['detail'][0]["msg"]);
|
||||||
|
} else {
|
||||||
|
return ErrorModel(detail: data['detail']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ErrorModel(detail: data['message']);
|
||||||
|
}
|
||||||
|
}
|
||||||
5
lib/feature/common/domain/entities/error_entity.dart
Normal file
5
lib/feature/common/domain/entities/error_entity.dart
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
class ErrorEntity {
|
||||||
|
final String detail;
|
||||||
|
|
||||||
|
const ErrorEntity({this.detail = ''});
|
||||||
|
}
|
||||||
@@ -22,3 +22,4 @@ export 'package:carousel_slider/carousel_slider.dart';
|
|||||||
export 'package:flutter_bounceable/flutter_bounceable.dart';
|
export 'package:flutter_bounceable/flutter_bounceable.dart';
|
||||||
export 'package:food_delivery_client/feature/on_boarding/presentation/pages/splash_page/splash_page.dart';
|
export 'package:food_delivery_client/feature/on_boarding/presentation/pages/splash_page/splash_page.dart';
|
||||||
export 'package:skeletonizer/skeletonizer.dart';
|
export 'package:skeletonizer/skeletonizer.dart';
|
||||||
|
export 'package:equatable/equatable.dart';
|
||||||
|
|||||||
16
pubspec.lock
16
pubspec.lock
@@ -201,6 +201,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "3.1.2"
|
version: "3.1.2"
|
||||||
|
dartz:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: dartz
|
||||||
|
sha256: e6acf34ad2e31b1eb00948692468c30ab48ac8250e0f0df661e29f12dd252168
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "0.10.1"
|
||||||
dio:
|
dio:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@@ -217,6 +225,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.1"
|
version: "2.1.1"
|
||||||
|
equatable:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: equatable
|
||||||
|
sha256: "567c64b3cb4cf82397aac55f4f0cbd3ca20d77c6c03bedbc4ceaddc08904aef7"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.7"
|
||||||
fake_async:
|
fake_async:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ dependencies:
|
|||||||
flutter_bounceable: ^1.2.0
|
flutter_bounceable: ^1.2.0
|
||||||
cached_network_image: ^3.4.1
|
cached_network_image: ^3.4.1
|
||||||
carousel_slider: ^5.1.1
|
carousel_slider: ^5.1.1
|
||||||
|
equatable: ^2.0.7
|
||||||
|
dartz: ^0.10.1
|
||||||
|
|
||||||
#DI
|
#DI
|
||||||
get_it: ^8.2.0
|
get_it: ^8.2.0
|
||||||
@@ -29,6 +31,8 @@ dependencies:
|
|||||||
#network
|
#network
|
||||||
dio: ^5.9.0
|
dio: ^5.9.0
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#to use svgs
|
#to use svgs
|
||||||
flutter_svg: ^2.2.1
|
flutter_svg: ^2.2.1
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user