From 0861ab4e917f1c09b1cb85c31fb007c3a0762df5 Mon Sep 17 00:00:00 2001 From: ohwhylin Date: Tue, 29 Oct 2024 14:36:44 +0400 Subject: [PATCH] =?UTF-8?q?=D1=87=D1=82=D0=BE=20=D1=87=D1=82=D0=BE=20?= =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B0=D0=B5=D1=82=D1=81=D1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/dtos/pokemon_dto.dart | 81 ++++++++++--------- lib/data/dtos/pokemon_dto.g.dart | 38 ++++----- lib/data/mappers/pokemon_mapper.dart | 28 +++++-- lib/data/repositories/pokemon_repository.dart | 63 ++++++++++++--- lib/main.dart | 6 +- lib/presentation/home_page/bloc/bloc.dart | 2 +- lib/presentation/home_page/home_page.dart | 2 +- 7 files changed, 135 insertions(+), 85 deletions(-) diff --git a/lib/data/dtos/pokemon_dto.dart b/lib/data/dtos/pokemon_dto.dart index 1feb7c8..cb42d5a 100644 --- a/lib/data/dtos/pokemon_dto.dart +++ b/lib/data/dtos/pokemon_dto.dart @@ -3,62 +3,67 @@ import 'package:json_annotation/json_annotation.dart'; part 'pokemon_dto.g.dart'; @JsonSerializable(createToJson: false) -class PokemonDto { - final List? data; - final MetaDto? meta; +class PokemonListDto { + final int? count; + final String? next; + final String? previous; + final List? results; - const PokemonDto({ - this.data, - this.meta, + const PokemonListDto({ + this.count, + this.next, + this.previous, + this.results, }); + factory PokemonListDto.fromJson(Map json) => _$PokemonListDtoFromJson(json); +} + +@JsonSerializable(createToJson: false) +class PokemonDto { + final String? name; + final String? url; + + const PokemonDto({this.name, this.url}); + factory PokemonDto.fromJson(Map json) => _$PokemonDtoFromJson(json); } @JsonSerializable(createToJson: false) -class PokemonDataDto { +class PokemonDetailsDto { + @JsonKey(fromJson: _idFromJson) final String? id; - final String? type; - final PokemonAttributesDataDto? attributes; - - const PokemonDataDto({this.id, this.type, this.attributes}); - - factory PokemonDataDto.fromJson(Map json) => _$PokemonDataDtoFromJson(json); -} - -@JsonSerializable(createToJson: false) -class PokemonAttributesDataDto { final String? name; - final String? height; - final String? weight; - final String? image; + final int? height; + final int? weight; + final SpritesDto? sprites; - const PokemonAttributesDataDto({ + const PokemonDetailsDto({ + this.id, this.name, this.height, this.weight, - this.image, + this.sprites, }); - factory PokemonAttributesDataDto.fromJson(Map json) => _$PokemonAttributesDataDtoFromJson(json); + factory PokemonDetailsDto.fromJson(Map json) => _$PokemonDetailsDtoFromJson(json); + + static String? _idFromJson(dynamic id) { + if (id is int) { + return id.toString(); + } else if (id is String) { + return id; + } else { + return null; + } + } } @JsonSerializable(createToJson: false) -class MetaDto { - final PaginationDto? pagination; +class SpritesDto { + final String? frontDefault; - const MetaDto({this.pagination}); + const SpritesDto({this.frontDefault}); - factory MetaDto.fromJson(Map json) => _$MetaDtoFromJson(json); -} - -@JsonSerializable(createToJson: false) -class PaginationDto { - final int? current; - final int? next; - final int? last; - - const PaginationDto({this.current, this.next, this.last}); - - factory PaginationDto.fromJson(Map json) => _$PaginationDtoFromJson(json); + factory SpritesDto.fromJson(Map json) => _$SpritesDtoFromJson(json); } \ No newline at end of file diff --git a/lib/data/dtos/pokemon_dto.g.dart b/lib/data/dtos/pokemon_dto.g.dart index 4a71cdc..476073f 100644 --- a/lib/data/dtos/pokemon_dto.g.dart +++ b/lib/data/dtos/pokemon_dto.g.dart @@ -7,42 +7,32 @@ part of 'pokemon_dto.dart'; // ************************************************************************** PokemonDto _$PokemonDtoFromJson(Map json) => PokemonDto( - data: (json['data'] as List?) + results: (json['results'] as List?) ?.map((e) => PokemonDataDto.fromJson(e as Map)) .toList(), - meta: json['meta'] == null - ? null - : MetaDto.fromJson(json['meta'] as Map), + count: (json['count'] as num?)?.toInt(), + next: json['next'] as String?, + previous: json['previous'] as String?, ); PokemonDataDto _$PokemonDataDtoFromJson(Map json) => PokemonDataDto( id: json['id'] as String?, - type: json['type'] as String?, + name: json['name'] as String?, attributes: json['attributes'] == null ? null - : PokemonAttributesDataDto.fromJson( + : PokemonAttributesDto.fromJson( json['attributes'] as Map), ); -PokemonAttributesDataDto _$PokemonAttributesDataDtoFromJson( +PokemonAttributesDto _$PokemonAttributesDtoFromJson( Map json) => - PokemonAttributesDataDto( - name: json['name'] as String?, - height: json['height'] as String?, - weight: json['weight'] as String?, + PokemonAttributesDto( + type: json['type'] as String?, + height: (json['height'] as num?)?.toInt(), + weight: (json['weight'] as num?)?.toInt(), + abilities: (json['abilities'] as List?) + ?.map((e) => e as String) + .toList(), image: json['image'] as String?, ); - -MetaDto _$MetaDtoFromJson(Map json) => MetaDto( - pagination: json['pagination'] == null - ? null - : PaginationDto.fromJson(json['pagination'] as Map), - ); - -PaginationDto _$PaginationDtoFromJson(Map json) => - PaginationDto( - current: (json['current'] as num?)?.toInt(), - next: (json['next'] as num?)?.toInt(), - last: (json['last'] as num?)?.toInt(), - ); diff --git a/lib/data/mappers/pokemon_mapper.dart b/lib/data/mappers/pokemon_mapper.dart index 0d4ad3d..ff3ec43 100644 --- a/lib/data/mappers/pokemon_mapper.dart +++ b/lib/data/mappers/pokemon_mapper.dart @@ -1,3 +1,4 @@ +import 'package:flutter/material.dart'; import 'package:mobilki_lab1/data/dtos/pokemon_dto.dart'; import 'package:mobilki_lab1/domain/models/card.dart'; import 'package:mobilki_lab1/domain/models/home.dart'; @@ -5,22 +6,33 @@ import 'package:mobilki_lab1/domain/models/home.dart'; const _imagePlaceholder = 'https://upload.wikimedia.org/wikipedia/en/archive/b/b1/20210811082420%21Portrait_placeholder.png'; -extension PokemonDtoToModel on PokemonDto { +extension PokemonListDtoToModel on PokemonListDto { HomeData toDomain() => HomeData( - data: data?.map((e) => e.toDomain()).toList(), - nextPage: meta?.pagination?.next, + data: results?.map((e) => e.toDomain()).toList(), + nextPage: next != null ? int.tryParse(next!.split('?')[1].split('=')[1]) : null, ); } -extension PokemonDataDtoToModel on PokemonDataDto { +extension PokemonDtoToModel on PokemonDto { CardData toDomain() => CardData( - attributes?.name ?? 'UNKNOWN', - imageUrl: attributes?.image ?? _imagePlaceholder, - descriptionText: _makeDescriptionText(attributes?.height, attributes?.weight), + name ?? 'UNKNOWN', + descriptionText: '', // Здесь можно добавить описание, если оно есть + imageUrl: _imagePlaceholder, // Здесь нужно добавить логику для получения URL изображения + id: null, // Здесь можно добавить логику для получения ID + icon: Icons.catching_pokemon, // Используем стандартную иконку + ); +} + +extension PokemonDetailsDtoToModel on PokemonDetailsDto { + CardData toDomain() => CardData( + name ?? 'UNKNOWN', + descriptionText: _makeDescriptionText(height, weight), + imageUrl: sprites?.frontDefault ?? _imagePlaceholder, id: id, + icon: Icons.catching_pokemon, // Используем стандартную иконку ); - String _makeDescriptionText(String? height, String? weight) { + String _makeDescriptionText(int? height, int? weight) { return height != null && weight != null ? 'Height: $height, Weight: $weight' : height != null diff --git a/lib/data/repositories/pokemon_repository.dart b/lib/data/repositories/pokemon_repository.dart index 05b164c..81a7c10 100644 --- a/lib/data/repositories/pokemon_repository.dart +++ b/lib/data/repositories/pokemon_repository.dart @@ -2,12 +2,12 @@ import 'package:dio/dio.dart'; import 'package:mobilki_lab1/data/dtos/pokemon_dto.dart'; import 'package:mobilki_lab1/data/mappers/pokemon_mapper.dart'; import 'package:mobilki_lab1/data/repositories/api_interface.dart'; -import 'package:mobilki_lab1/domain/models/card.dart'; import 'package:mobilki_lab1/domain/models/home.dart'; -import 'package:mobilki_lab1/presentation/home_page/bloc/events.dart'; import 'package:pretty_dio_logger/pretty_dio_logger.dart'; -class PokemonRepository extends ApiInterface { +import '../../domain/models/card.dart'; + +class PokeRepository extends ApiInterface { static final Dio _dio = Dio() ..interceptors.add(PrettyDioLogger( requestHeader: true, @@ -29,18 +29,61 @@ class PokemonRepository extends ApiInterface { final Response response = await _dio.get>( url, queryParameters: { - 'filter[name_cont]': q, - 'page[number]': page, - 'page[size]': pageSize, + 'offset': (page - 1) * pageSize, + 'limit': pageSize, }, ); - final PokemonDto dto = PokemonDto.fromJson(response.data as Map); - final HomeData data = dto.toDomain(); - return data; + final PokemonListDto dto = PokemonListDto.fromJson(response.data as Map); + final List? pokemonList = dto.results; + + if (pokemonList != null) { + final List cards = await Future.wait(pokemonList.map((pokemon) async { + final PokemonDetailsDto detailsDto = await loadPokemonDetails(pokemon.url!); + return detailsDto.toDomain(); + })); + + return HomeData( + data: cards, + nextPage: dto.next, + ); + } + + return null; } on DioException catch (e) { onError?.call(e.error?.toString()); return null; } } -} + + Future loadNextPage(String nextPageUrl, {OnErrorCallback? onError}) async { + try { + final Response response = await _dio.get>(nextPageUrl); + + final PokemonListDto dto = PokemonListDto.fromJson(response.data as Map); + final List? pokemonList = dto.results; + + if (pokemonList != null) { + final List cards = await Future.wait(pokemonList.map((pokemon) async { + final PokemonDetailsDto detailsDto = await loadPokemonDetails(pokemon.url!); + return detailsDto.toDomain(); + })); + + return HomeData( + data: cards, + nextPage: dto.next, + ); + } + + return null; + } on DioException catch (e) { + onError?.call(e.error?.toString()); + return null; + } + } + + Future loadPokemonDetails(String url) async { + final Response response = await _dio.get>(url); + return PokemonDetailsDto.fromJson(response.data as Map); + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 5d57e04..1335ded 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -35,15 +35,15 @@ class MyApp extends StatelessWidget { colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), useMaterial3: true, ), - home: RepositoryProvider( + home: RepositoryProvider( lazy: true, - create: (_) => PokemonRepository(), + create: (_) => PokeRepository(), child: BlocProvider( lazy: false, create: (context) => LikeBloc(), child: BlocProvider( lazy: false, - create: (context) => HomeBloc(context.read()), + create: (context) => HomeBloc(context.read()), child: const MyHomePage(title: 'Чубыкина Полина Павловна'), ), ), diff --git a/lib/presentation/home_page/bloc/bloc.dart b/lib/presentation/home_page/bloc/bloc.dart index 9749a7b..da6968a 100644 --- a/lib/presentation/home_page/bloc/bloc.dart +++ b/lib/presentation/home_page/bloc/bloc.dart @@ -6,7 +6,7 @@ import 'package:mobilki_lab1/presentation/home_page/bloc/state.dart'; class HomeBloc extends Bloc { //final PotterRepository repo; - final PokemonRepository repo; + final PokeRepository repo; HomeBloc(this.repo) : super(const HomeState()) { on(_onLoadData); diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart index e4beb06..70c0183 100644 --- a/lib/presentation/home_page/home_page.dart +++ b/lib/presentation/home_page/home_page.dart @@ -63,7 +63,7 @@ class BodyState extends State { } void _onNextPageListener() { - if (scrollController.offset > scrollController.position.maxScrollExtent) { + if (scrollController.offset >= scrollController.position.maxScrollExtent) { final bloc = context.read(); if (!bloc.state.isPaginationLoading) { bloc.add(HomeLoadDataEvent(