Data: API connection, API interface implementation and mapping implementation,dto addition
This commit is contained in:
parent
0dfeb6c20a
commit
f57f4aa7e8
66
lib/data/dtos/candies_dto.dart
Normal file
66
lib/data/dtos/candies_dto.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
24
lib/data/mapper/candies_mapper.dart
Normal file
24
lib/data/mapper/candies_mapper.dart
Normal 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,
|
||||
);
|
||||
}
|
7
lib/data/repositories/api_interface.dart
Normal file
7
lib/data/repositories/api_interface.dart
Normal 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});
|
||||
}
|
55
lib/data/repositories/candy_repository.dart
Normal file
55
lib/data/repositories/candy_repository.dart
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user