Data: API connection, API interface implementation and mapping implementation,dto addition

This commit is contained in:
nikbel2004@outlook.com 2024-12-18 17:14:14 +04:00
parent 0dfeb6c20a
commit f57f4aa7e8
4 changed files with 152 additions and 0 deletions

View File

@ -0,0 +1,66 @@
import 'package:json_annotation/json_annotation.dart';
part 'candies_dto.g.dart';
@JsonSerializable(createToJson: false)
class CandiesResponseDto {
// Для пагинации
final int? totalCount;
final int? pageSize;
final int? currentPage;
final int? totalPages;
// Сами данные сущности
final List<CandyItemDto>? items;
const CandiesResponseDto(
{this.totalCount, this.pageSize, this.currentPage, this.totalPages, this.items});
factory CandiesResponseDto.fromJson(Map<String, dynamic> json) =>
_$CandiesResponseDtoFromJson(json);
}
@JsonSerializable(createToJson: false)
class CandyItemDto {
final int? beanId;
final List<String>? groupName;
final List<String>? ingredients;
final String? flavorName;
final String? description;
final String? colorGroup;
final String? backgroundColor;
final String? imageUrl;
final bool? glutenFree;
final bool? sugarFree;
final bool? seasonal;
final bool? kosher;
const CandyItemDto(
{this.beanId,
this.groupName,
this.ingredients,
this.flavorName,
this.description,
this.colorGroup,
this.backgroundColor,
this.imageUrl,
this.glutenFree,
this.sugarFree,
this.seasonal,
this.kosher});
factory CandyItemDto.fromJson(Map<String, dynamic> json) => _$CandyItemDtoFromJson(json);
}
extension CandiesResponseDtoExtensions on CandiesResponseDto {
CandiesResponseDto copyWithFilteredItems(List<CandyItemDto>? items) {
return CandiesResponseDto(
totalCount: items?.length,
pageSize: pageSize,
currentPage: currentPage,
totalPages: totalPages,
items: items,
);
}
}

View File

@ -0,0 +1,24 @@
import 'package:candystore/data/dtos/candies_dto.dart';
import 'package:candystore/models/card_data.dart';
import 'package:candystore/models/candy_data.dart';
extension CandyItemDtoToModel on CandyItemDto {
CardData toDomain() => CardData(
flavorName: flavorName ?? "UNKNOWN",
imageUrl: imageUrl ??
"https://upload.wikimedia.org/wikipedia/commons/a/a2/Person_Image_Placeholder.png",
description: description ?? "UNKNOWN",
groupName: groupName ?? ["UNKNOWN"],
beanId: beanId);
}
extension CandiesDtoToModel on CandiesResponseDto {
CandyData toDomain() => CandyData(
data: items?.map((e) => e.toDomain()).toList(),
nextPage: currentPage != null && totalPages != null && currentPage! < totalPages!
? currentPage! + 1
: null,
currentPage: currentPage,
totalPages: totalPages,
);
}

View File

@ -0,0 +1,7 @@
import 'package:candystore/models/candy_data.dart';
typedef OnErrorCallback = void Function(String? error);
abstract class ApiInterface {
Future<CandyData?> loadData({OnErrorCallback? onError});
}

View File

@ -0,0 +1,55 @@
import 'dart:developer';
import 'package:dio/dio.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
import 'package:candystore/data/dtos/candies_dto.dart';
import 'package:candystore/data/mapper/candies_mapper.dart';
import 'package:candystore/data/repositories/api_interface.dart';
import 'package:candystore/models/candy_data.dart';
class CandyRepository extends ApiInterface {
static final Dio _dio = Dio(BaseOptions(connectTimeout: const Duration(seconds: 10)))
..interceptors.add(PrettyDioLogger(request: true, requestHeader: true, requestBody: true));
static const String _baseUrl = "https://jellybellywikiapi.onrender.com/api";
@override
Future<CandyData?> loadData(
{OnErrorCallback? onError, String? q, int page = 1, int pageSize = 10}) async {
try {
const String url = '$_baseUrl/Beans?';
final Response<dynamic> response = await _dio.get<Map<dynamic, dynamic>>(
url,
queryParameters: {
'pageIndex': page,
'pageSize': pageSize},
);
final CandiesResponseDto dto =
CandiesResponseDto.fromJson(response.data as Map<String, dynamic>);
// Если `q` указан, фильтруем данные
List<CandyItemDto>? filteredItems;
if (q != null && q.isNotEmpty) {
final query = q.toLowerCase();
filteredItems = dto.items?.where((item) {
final flavorName = item.flavorName?.toLowerCase() ?? '';
return flavorName.contains(query); // Динамическое совпадение
}).toList();
}
// Создаём новый объект с отфильтрованными элементами (или возвращаем полный список)
final filteredDto = dto.copyWithFilteredItems(filteredItems ?? dto.items);
return filteredDto.toDomain();
} on DioException catch (e) {
log("DioException: $e");
onError?.call(e.error?.toString());
return null;
} catch (e) {
log('Unknown error: $e');
return null;
}
}
}