refactor(http): удалить интерфейс IHttpClient и упростить реализацию AppHttpClient (#42)

* refactor(http): удалить интерфейс IHttpClient и упростить реализацию AppHttpClient

- Удален интерфейс IHttpClient, что упростило структуру кода.
- AppHttpClient теперь напрямую использует Dio без промежуточного интерфейса.
- Обновлены зависимости в репозиториях для использования нового HTTP клиента.

* refactor(code):  dart format

* chore(pr-template): удалить отключения markdownlint из шаблона PR

* docs(copilot-instructions): добавить правила проведения Code Review

---------

Co-authored-by: petrovyuri <petrovyuri@example.com>
This commit is contained in:
Yuri Petrov
2025-12-11 10:27:19 +03:00
committed by GitHub
parent ab64fb9246
commit 4a49083ef3
15 changed files with 54 additions and 258 deletions

View File

@@ -6,6 +6,11 @@
---
# Правила проведения Code Review
## Основные правила проведения Code Review
- Комментарии и описание Pull Request должны быть на русском языке.
# Стиль кода
## Именование

View File

@@ -1,5 +1,3 @@
<!-- markdownlint-disable MD033 -->
<!-- markdownlint-disable MD041 -->
## Ссылка на задачу или issue (обязательно)
<!--- https://tracker.yandex.ru/XXX -->

View File

@@ -1,13 +1,12 @@
import 'package:dio/dio.dart';
import 'package:friflex_starter/app/app_config/app_config.dart';
import 'package:friflex_starter/app/http/i_http_client.dart';
import 'package:friflex_starter/features/debug/i_debug_service.dart';
/// {@template app_http_client}
/// Класс для реализации HTTP-клиента для управления запросами
/// {@endtemplate}
final class AppHttpClient implements IHttpClient {
final class AppHttpClient {
/// Создает HTTP клиент
///
/// Принимает:
@@ -18,7 +17,6 @@ final class AppHttpClient implements IHttpClient {
required IAppConfig appConfig,
}) {
_httpClient = Dio();
_appConfig = appConfig;
_httpClient.options
..baseUrl = appConfig.baseUrl
@@ -30,111 +28,8 @@ final class AppHttpClient implements IHttpClient {
_httpClient.interceptors.add(debugService.dioLogger);
}
/// Конфигурация приложения
late final IAppConfig _appConfig;
/// Экземпляр HTTP клиента
late final Dio _httpClient;
@override
Future<Response> get(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
_httpClient.options.baseUrl = _appConfig.baseUrl;
return _httpClient.get(
path,
data: data,
queryParameters: queryParameters,
options: options,
);
}
@override
Future<Response> post(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
_httpClient.options.baseUrl = _appConfig.baseUrl;
return _httpClient.post(
path,
data: data,
queryParameters: queryParameters,
options: options,
);
}
@override
Future<Response> patch(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
_httpClient.options.baseUrl = _appConfig.baseUrl;
return _httpClient.patch(
path,
data: data,
queryParameters: queryParameters,
options: options,
);
}
@override
Future<Response> put(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
_httpClient.options.baseUrl = _appConfig.baseUrl;
return _httpClient.put(
path,
data: data,
queryParameters: queryParameters,
options: options,
);
}
@override
Future<Response> delete(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
_httpClient.options.baseUrl = _appConfig.baseUrl;
return _httpClient.delete(
path,
data: data,
queryParameters: queryParameters,
options: options,
);
}
@override
Future<Response> head(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
}) async {
_httpClient.options.baseUrl = _appConfig.baseUrl;
return _httpClient.head(
path,
data: data,
queryParameters: queryParameters,
options: options,
);
}
Dio get client => _httpClient;
}

View File

@@ -1,94 +0,0 @@
import 'package:dio/dio.dart';
/// Класс для описания интерфейса сервиса по управлению HTTP запросами
abstract interface class IHttpClient {
/// Описывает поля HTTP клиента
const IHttpClient();
/// Наименование сервиса
static const name = 'IHttpClient';
/// Метод для реализации запроса GET
///
/// Принимает:
/// - [path] - путь к ресурсу
/// - [data] - тело запроса
/// - [queryParameters] - параметры запроса
/// - [options] - конфигурация запроса
Future<Response> get(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
});
/// Метод для реализации запроса POST
///
/// Принимает:
/// - [path] - путь к ресурсу
/// - [data] - тело запроса
/// - [queryParameters] - параметры запроса
/// - [options] - конфигурация запроса
Future<Response> post(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
});
/// Метод для реализации запроса PATCH
///
/// Принимает:
/// - [path] - путь к ресурсу
/// - [data] - тело запроса
/// - [queryParameters] - параметры запроса
/// - [options] - конфигурация запроса
Future<Response> patch(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
});
/// Метод для реализации запроса PUT
///
/// Принимает:
/// - [path] - путь к ресурсу
/// - [data] - тело запроса
/// - [queryParameters] - параметры запроса
/// - [options] - конфигурация запроса
Future<Response> put(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
});
/// Метод для реализации запроса DELETE
///
/// Принимает:
/// - [path] - путь к ресурсу
/// - [data] - тело запроса
/// - [queryParameters] - параметры запроса
/// - [options] - конфигурация запроса
Future<Response> delete(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
});
/// Метод для реализации запроса POST
///
/// Принимает:
/// - [path] - путь к ресурсу
/// - [data] - тело запроса
/// - [queryParameters] - параметры запроса
/// - [options] - конфигурация запроса
Future<Response> head(
String path, {
Object? data,
Map<String, dynamic>? queryParameters,
Options? options,
});
}

View File

@@ -55,7 +55,7 @@ class AppColors extends ThemeExtension<AppColors> with _$AppColorsTailorMixin {
);
/// Цвета тёмной темы
static const AppColors dark = AppColors(
static const AppColors dark = AppColors(
testColor: Colors.green,
errorSnackbarBackground: Color(0xFF638B8B),
successSnackbarBackground: Color(0xFF93C499),

View File

@@ -290,21 +290,9 @@ class _Icon extends StatelessWidget {
@override
Widget build(BuildContext context) {
return switch (type) {
.success => const Icon(
Icons.check_circle,
color: Colors.white,
size: 32,
),
.error => const Icon(
Icons.error,
color: Colors.white,
size: 32,
),
.info => const Icon(
Icons.info,
color: Colors.white,
size: 32,
),
.success => const Icon(Icons.check_circle, color: Colors.white, size: 32),
.error => const Icon(Icons.error, color: Colors.white, size: 32),
.info => const Icon(Icons.info, color: Colors.white, size: 32),
};
}
}

View File

@@ -1,7 +1,6 @@
import 'package:friflex_starter/app/app_config/app_config.dart';
import 'package:friflex_starter/app/app_env.dart';
import 'package:friflex_starter/app/http/app_http_client.dart';
import 'package:friflex_starter/app/http/i_http_client.dart';
import 'package:friflex_starter/di/di_repositories.dart';
import 'package:friflex_starter/di/di_services.dart';
import 'package:friflex_starter/di/di_typedefs.dart';
@@ -25,7 +24,7 @@ final class DiContainer {
late final IAppConfig appConfig;
/// Сервис для работы с HTTP запросами
late final IHttpClient Function(IDebugService, IAppConfig) httpClientFactory;
late final AppHttpClient httpClient;
/// Репозитории приложения
late final DiRepositories repositories;
@@ -47,8 +46,10 @@ final class DiContainer {
};
// Инициализация HTTP клиента
httpClientFactory = (debugService, appConfig) =>
AppHttpClient(debugService: debugService, appConfig: appConfig);
httpClient = AppHttpClient(
debugService: debugService,
appConfig: appConfig,
);
// Инициализация сервисов
services = DiServices()

View File

@@ -77,8 +77,8 @@ final class DiRepositories {
// Инициализация репозитория обновлений
updatesRepository = _lazyInitRepo<IUpdateRepository>(
mockFactory: UpdateMockRepository.new,
mainFactory: UpdateRepository.new,
mockFactory: () => const UpdateMockRepository(),
mainFactory: () => UpdateRepository(httpClient: diContainer.httpClient),
onProgress: onProgress,
onError: onError,
environment: diContainer.env,
@@ -86,13 +86,8 @@ final class DiRepositories {
// Инициализация репозитория авторизации
authRepository = _lazyInitRepo<IAuthRepository>(
mockFactory: AuthMockRepository.new,
mainFactory: () => AuthRepository(
httpClient: diContainer.httpClientFactory(
diContainer.debugService,
diContainer.appConfig,
),
),
mockFactory: () => const AuthMockRepository(),
mainFactory: () => AuthRepository(httpClient: diContainer.httpClient),
onProgress: onProgress,
onError: onError,
environment: diContainer.env,
@@ -100,13 +95,8 @@ final class DiRepositories {
// Инициализация репозитория сервиса управления токеном доступа
mainRepository = _lazyInitRepo<IMainRepository>(
mockFactory: MainMockRepository.new,
mainFactory: () => MainRepository(
httpClient: diContainer.httpClientFactory(
diContainer.debugService,
diContainer.appConfig,
),
),
mockFactory: () => const MainMockRepository(),
mainFactory: () => MainRepository(httpClient: diContainer.httpClient),
onProgress: onProgress,
onError: onError,
environment: diContainer.env,
@@ -114,13 +104,8 @@ final class DiRepositories {
// Инициализация репозитория профиля
profileRepository = _lazyInitRepo<IProfileRepository>(
mockFactory: ProfileMockRepository.new,
mainFactory: () => ProfileRepository(
httpClient: diContainer.httpClientFactory(
diContainer.debugService,
diContainer.appConfig,
),
),
mockFactory: () => const ProfileMockRepository(),
mainFactory: () => ProfileRepository(httpClient: diContainer.httpClient),
onProgress: onProgress,
onError: onError,
environment: diContainer.env,

View File

@@ -4,6 +4,9 @@ import 'package:friflex_starter/features/auth/domain/repository/i_auth_repositor
/// Mock реализация репозитория авторизации
/// {@endtemplate}
final class AuthMockRepository implements IAuthRepository {
/// {@macro AuthMockRepository}
const AuthMockRepository();
@override
String get name => 'AuthMockRepository';
}

View File

@@ -1,4 +1,4 @@
import 'package:friflex_starter/app/http/i_http_client.dart';
import 'package:friflex_starter/app/http/app_http_client.dart';
import 'package:friflex_starter/features/auth/domain/repository/i_auth_repository.dart';
@@ -7,7 +7,9 @@ import 'package:friflex_starter/features/auth/domain/repository/i_auth_repositor
/// {@endtemplate}
final class AuthRepository implements IAuthRepository {
AuthRepository({required this.httpClient});
final IHttpClient httpClient;
/// Экземпляр HTTP клиента для взаимодействия с сервером
final AppHttpClient httpClient;
@override
String get name => 'AuthRepository';

View File

@@ -1,9 +1,12 @@
import 'package:friflex_starter/features/main/domain/repository/i_main_repository.dart';
/// {@template MainMockRepository}
///
/// Мок реализация репозитория главного сервиса
/// {@endtemplate}
final class MainMockRepository implements IMainRepository {
/// {@macro MainMockRepository}
const MainMockRepository();
@override
String get name => 'MainMockRepository';
}

View File

@@ -1,13 +1,14 @@
import 'package:friflex_starter/app/http/i_http_client.dart';
import 'package:friflex_starter/app/http/app_http_client.dart';
import 'package:friflex_starter/features/main/domain/repository/i_main_repository.dart';
/// {@template MainRepository}
///
/// Реализация репозитория главного сервиса
/// {@endtemplate}
final class MainRepository implements IMainRepository {
MainRepository({required this.httpClient});
final IHttpClient httpClient;
/// Экземпляр HTTP клиента для взаимодействия с сервером
final AppHttpClient httpClient;
@override
String get name => 'MainRepository';

View File

@@ -1,9 +1,12 @@
import 'package:friflex_starter/features/profile/domain/repository/i_profile_repository.dart';
/// {@template ProfileMockRepository}
///
/// Мок реализация репозитория профиля пользователя
/// {@endtemplate}
final class ProfileMockRepository implements IProfileRepository {
/// {@macro ProfileMockRepository}
const ProfileMockRepository();
@override
String get name => 'ProfileMockRepository';

View File

@@ -1,13 +1,15 @@
import 'package:friflex_starter/app/http/i_http_client.dart';
import 'package:friflex_starter/app/http/app_http_client.dart';
import 'package:friflex_starter/features/profile/domain/repository/i_profile_repository.dart';
/// {@template ProfileRepository}
///
/// Реализация репозитория профиля пользователя
/// {@endtemplate}
final class ProfileRepository implements IProfileRepository {
ProfileRepository({required this.httpClient});
final IHttpClient httpClient;
/// Экземпляр HTTP клиента для взаимодействия с сервером
final AppHttpClient httpClient;
@override
String get name => 'ProfileRepository';

View File

@@ -1,3 +1,4 @@
import 'package:friflex_starter/app/http/app_http_client.dart';
import 'package:friflex_starter/features/update/domain/entity/update_entity.dart';
import 'package:friflex_starter/features/update/domain/repository/i_update_repository.dart';
@@ -6,7 +7,10 @@ import 'package:friflex_starter/features/update/domain/repository/i_update_repos
/// {@endtemplate}
final class UpdateRepository implements IUpdateRepository {
/// {@macro UpdateRepository}
const UpdateRepository();
UpdateRepository({required this.httpClient});
/// Экземпляр HTTP клиента для взаимодействия с сервером
final AppHttpClient httpClient;
@override
Future<UpdateEntity> checkForUpdates({