что что делается

This commit is contained in:
Полина Чубыкина 2024-10-29 14:36:44 +04:00
parent b7013f4e2a
commit 0861ab4e91
7 changed files with 135 additions and 85 deletions

View File

@ -3,62 +3,67 @@ import 'package:json_annotation/json_annotation.dart';
part 'pokemon_dto.g.dart'; part 'pokemon_dto.g.dart';
@JsonSerializable(createToJson: false) @JsonSerializable(createToJson: false)
class PokemonDto { class PokemonListDto {
final List<PokemonDataDto>? data; final int? count;
final MetaDto? meta; final String? next;
final String? previous;
final List<PokemonDto>? results;
const PokemonDto({ const PokemonListDto({
this.data, this.count,
this.meta, this.next,
this.previous,
this.results,
}); });
factory PokemonListDto.fromJson(Map<String, dynamic> json) => _$PokemonListDtoFromJson(json);
}
@JsonSerializable(createToJson: false)
class PokemonDto {
final String? name;
final String? url;
const PokemonDto({this.name, this.url});
factory PokemonDto.fromJson(Map<String, dynamic> json) => _$PokemonDtoFromJson(json); factory PokemonDto.fromJson(Map<String, dynamic> json) => _$PokemonDtoFromJson(json);
} }
@JsonSerializable(createToJson: false) @JsonSerializable(createToJson: false)
class PokemonDataDto { class PokemonDetailsDto {
@JsonKey(fromJson: _idFromJson)
final String? id; final String? id;
final String? type;
final PokemonAttributesDataDto? attributes;
const PokemonDataDto({this.id, this.type, this.attributes});
factory PokemonDataDto.fromJson(Map<String, dynamic> json) => _$PokemonDataDtoFromJson(json);
}
@JsonSerializable(createToJson: false)
class PokemonAttributesDataDto {
final String? name; final String? name;
final String? height; final int? height;
final String? weight; final int? weight;
final String? image; final SpritesDto? sprites;
const PokemonAttributesDataDto({ const PokemonDetailsDto({
this.id,
this.name, this.name,
this.height, this.height,
this.weight, this.weight,
this.image, this.sprites,
}); });
factory PokemonAttributesDataDto.fromJson(Map<String, dynamic> json) => _$PokemonAttributesDataDtoFromJson(json); factory PokemonDetailsDto.fromJson(Map<String, dynamic> 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) @JsonSerializable(createToJson: false)
class MetaDto { class SpritesDto {
final PaginationDto? pagination; final String? frontDefault;
const MetaDto({this.pagination}); const SpritesDto({this.frontDefault});
factory MetaDto.fromJson(Map<String, dynamic> json) => _$MetaDtoFromJson(json); factory SpritesDto.fromJson(Map<String, dynamic> json) => _$SpritesDtoFromJson(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<String, dynamic> json) => _$PaginationDtoFromJson(json);
} }

View File

@ -7,42 +7,32 @@ part of 'pokemon_dto.dart';
// ************************************************************************** // **************************************************************************
PokemonDto _$PokemonDtoFromJson(Map<String, dynamic> json) => PokemonDto( PokemonDto _$PokemonDtoFromJson(Map<String, dynamic> json) => PokemonDto(
data: (json['data'] as List<dynamic>?) results: (json['results'] as List<dynamic>?)
?.map((e) => PokemonDataDto.fromJson(e as Map<String, dynamic>)) ?.map((e) => PokemonDataDto.fromJson(e as Map<String, dynamic>))
.toList(), .toList(),
meta: json['meta'] == null count: (json['count'] as num?)?.toInt(),
? null next: json['next'] as String?,
: MetaDto.fromJson(json['meta'] as Map<String, dynamic>), previous: json['previous'] as String?,
); );
PokemonDataDto _$PokemonDataDtoFromJson(Map<String, dynamic> json) => PokemonDataDto _$PokemonDataDtoFromJson(Map<String, dynamic> json) =>
PokemonDataDto( PokemonDataDto(
id: json['id'] as String?, id: json['id'] as String?,
type: json['type'] as String?, name: json['name'] as String?,
attributes: json['attributes'] == null attributes: json['attributes'] == null
? null ? null
: PokemonAttributesDataDto.fromJson( : PokemonAttributesDto.fromJson(
json['attributes'] as Map<String, dynamic>), json['attributes'] as Map<String, dynamic>),
); );
PokemonAttributesDataDto _$PokemonAttributesDataDtoFromJson( PokemonAttributesDto _$PokemonAttributesDtoFromJson(
Map<String, dynamic> json) => Map<String, dynamic> json) =>
PokemonAttributesDataDto( PokemonAttributesDto(
name: json['name'] as String?, type: json['type'] as String?,
height: json['height'] as String?, height: (json['height'] as num?)?.toInt(),
weight: json['weight'] as String?, weight: (json['weight'] as num?)?.toInt(),
abilities: (json['abilities'] as List<dynamic>?)
?.map((e) => e as String)
.toList(),
image: json['image'] as String?, image: json['image'] as String?,
); );
MetaDto _$MetaDtoFromJson(Map<String, dynamic> json) => MetaDto(
pagination: json['pagination'] == null
? null
: PaginationDto.fromJson(json['pagination'] as Map<String, dynamic>),
);
PaginationDto _$PaginationDtoFromJson(Map<String, dynamic> json) =>
PaginationDto(
current: (json['current'] as num?)?.toInt(),
next: (json['next'] as num?)?.toInt(),
last: (json['last'] as num?)?.toInt(),
);

View File

@ -1,3 +1,4 @@
import 'package:flutter/material.dart';
import 'package:mobilki_lab1/data/dtos/pokemon_dto.dart'; import 'package:mobilki_lab1/data/dtos/pokemon_dto.dart';
import 'package:mobilki_lab1/domain/models/card.dart'; import 'package:mobilki_lab1/domain/models/card.dart';
import 'package:mobilki_lab1/domain/models/home.dart'; import 'package:mobilki_lab1/domain/models/home.dart';
@ -5,22 +6,33 @@ import 'package:mobilki_lab1/domain/models/home.dart';
const _imagePlaceholder = const _imagePlaceholder =
'https://upload.wikimedia.org/wikipedia/en/archive/b/b1/20210811082420%21Portrait_placeholder.png'; 'https://upload.wikimedia.org/wikipedia/en/archive/b/b1/20210811082420%21Portrait_placeholder.png';
extension PokemonDtoToModel on PokemonDto { extension PokemonListDtoToModel on PokemonListDto {
HomeData toDomain() => HomeData( HomeData toDomain() => HomeData(
data: data?.map((e) => e.toDomain()).toList(), data: results?.map((e) => e.toDomain()).toList(),
nextPage: meta?.pagination?.next, nextPage: next != null ? int.tryParse(next!.split('?')[1].split('=')[1]) : null,
); );
} }
extension PokemonDataDtoToModel on PokemonDataDto { extension PokemonDtoToModel on PokemonDto {
CardData toDomain() => CardData( CardData toDomain() => CardData(
attributes?.name ?? 'UNKNOWN', name ?? 'UNKNOWN',
imageUrl: attributes?.image ?? _imagePlaceholder, descriptionText: '', // Здесь можно добавить описание, если оно есть
descriptionText: _makeDescriptionText(attributes?.height, attributes?.weight), 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, id: id,
icon: Icons.catching_pokemon, // Используем стандартную иконку
); );
String _makeDescriptionText(String? height, String? weight) { String _makeDescriptionText(int? height, int? weight) {
return height != null && weight != null return height != null && weight != null
? 'Height: $height, Weight: $weight' ? 'Height: $height, Weight: $weight'
: height != null : height != null

View File

@ -2,12 +2,12 @@ import 'package:dio/dio.dart';
import 'package:mobilki_lab1/data/dtos/pokemon_dto.dart'; import 'package:mobilki_lab1/data/dtos/pokemon_dto.dart';
import 'package:mobilki_lab1/data/mappers/pokemon_mapper.dart'; import 'package:mobilki_lab1/data/mappers/pokemon_mapper.dart';
import 'package:mobilki_lab1/data/repositories/api_interface.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/domain/models/home.dart';
import 'package:mobilki_lab1/presentation/home_page/bloc/events.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.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() static final Dio _dio = Dio()
..interceptors.add(PrettyDioLogger( ..interceptors.add(PrettyDioLogger(
requestHeader: true, requestHeader: true,
@ -29,18 +29,61 @@ class PokemonRepository extends ApiInterface {
final Response<dynamic> response = await _dio.get<Map<dynamic, dynamic>>( final Response<dynamic> response = await _dio.get<Map<dynamic, dynamic>>(
url, url,
queryParameters: { queryParameters: {
'filter[name_cont]': q, 'offset': (page - 1) * pageSize,
'page[number]': page, 'limit': pageSize,
'page[size]': pageSize,
}, },
); );
final PokemonDto dto = PokemonDto.fromJson(response.data as Map<String, dynamic>); final PokemonListDto dto = PokemonListDto.fromJson(response.data as Map<String, dynamic>);
final HomeData data = dto.toDomain(); final List<PokemonDto>? pokemonList = dto.results;
return data;
if (pokemonList != null) {
final List<CardData> 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) { } on DioException catch (e) {
onError?.call(e.error?.toString()); onError?.call(e.error?.toString());
return null; return null;
} }
} }
Future<HomeData?> loadNextPage(String nextPageUrl, {OnErrorCallback? onError}) async {
try {
final Response<dynamic> response = await _dio.get<Map<dynamic, dynamic>>(nextPageUrl);
final PokemonListDto dto = PokemonListDto.fromJson(response.data as Map<String, dynamic>);
final List<PokemonDto>? pokemonList = dto.results;
if (pokemonList != null) {
final List<CardData> 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<PokemonDetailsDto> loadPokemonDetails(String url) async {
final Response<dynamic> response = await _dio.get<Map<dynamic, dynamic>>(url);
return PokemonDetailsDto.fromJson(response.data as Map<String, dynamic>);
}
} }

View File

@ -35,15 +35,15 @@ class MyApp extends StatelessWidget {
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
useMaterial3: true, useMaterial3: true,
), ),
home: RepositoryProvider<PokemonRepository>( home: RepositoryProvider<PokeRepository>(
lazy: true, lazy: true,
create: (_) => PokemonRepository(), create: (_) => PokeRepository(),
child: BlocProvider<LikeBloc>( child: BlocProvider<LikeBloc>(
lazy: false, lazy: false,
create: (context) => LikeBloc(), create: (context) => LikeBloc(),
child: BlocProvider<HomeBloc>( child: BlocProvider<HomeBloc>(
lazy: false, lazy: false,
create: (context) => HomeBloc(context.read<PokemonRepository>()), create: (context) => HomeBloc(context.read<PokeRepository>()),
child: const MyHomePage(title: 'Чубыкина Полина Павловна'), child: const MyHomePage(title: 'Чубыкина Полина Павловна'),
), ),
), ),

View File

@ -6,7 +6,7 @@ import 'package:mobilki_lab1/presentation/home_page/bloc/state.dart';
class HomeBloc extends Bloc<HomeEvent, HomeState> { class HomeBloc extends Bloc<HomeEvent, HomeState> {
//final PotterRepository repo; //final PotterRepository repo;
final PokemonRepository repo; final PokeRepository repo;
HomeBloc(this.repo) : super(const HomeState()) { HomeBloc(this.repo) : super(const HomeState()) {
on<HomeLoadDataEvent>(_onLoadData); on<HomeLoadDataEvent>(_onLoadData);

View File

@ -63,7 +63,7 @@ class BodyState extends State<Body> {
} }
void _onNextPageListener() { void _onNextPageListener() {
if (scrollController.offset > scrollController.position.maxScrollExtent) { if (scrollController.offset >= scrollController.position.maxScrollExtent) {
final bloc = context.read<HomeBloc>(); final bloc = context.read<HomeBloc>();
if (!bloc.state.isPaginationLoading) { if (!bloc.state.isPaginationLoading) {
bloc.add(HomeLoadDataEvent( bloc.add(HomeLoadDataEvent(