поломала пагинацию

This commit is contained in:
Полина Чубыкина 2024-11-16 13:37:18 +04:00
parent 98c063ed2f
commit 97cbcba226
9 changed files with 199 additions and 77 deletions

View File

@ -82,8 +82,7 @@ abstract class AppLocale {
/// Additional delegates can be added by appending to this list in /// Additional delegates can be added by appending to this list in
/// MaterialApp. This list does not have to be used at all if a custom list /// MaterialApp. This list does not have to be used at all if a custom list
/// of delegates is preferred or required. /// of delegates is preferred or required.
static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = static const List<LocalizationsDelegate<dynamic>> localizationsDelegates = <LocalizationsDelegate<dynamic>>[
<LocalizationsDelegate<dynamic>>[
delegate, delegate,
GlobalMaterialLocalizations.delegate, GlobalMaterialLocalizations.delegate,
GlobalCupertinoLocalizations.delegate, GlobalCupertinoLocalizations.delegate,
@ -91,7 +90,10 @@ abstract class AppLocale {
]; ];
/// A list of this localizations delegate's supported locales. /// A list of this localizations delegate's supported locales.
static const List<Locale> supportedLocales = <Locale>[Locale('en'), Locale('ru')]; static const List<Locale> supportedLocales = <Locale>[
Locale('en'),
Locale('ru')
];
/// No description provided for @search. /// No description provided for @search.
/// ///
@ -134,17 +136,18 @@ class _AppLocaleDelegate extends LocalizationsDelegate<AppLocale> {
} }
AppLocale lookupAppLocale(Locale locale) { AppLocale lookupAppLocale(Locale locale) {
// Lookup logic when only language code is specified. // Lookup logic when only language code is specified.
switch (locale.languageCode) { switch (locale.languageCode) {
case 'en': case 'en': return AppLocaleEn();
return AppLocaleEn(); case 'ru': return AppLocaleRu();
case 'ru':
return AppLocaleRu();
} }
throw FlutterError( throw FlutterError(
'AppLocale.delegate failed to load unsupported locale "$locale". This is likely ' 'AppLocale.delegate failed to load unsupported locale "$locale". This is likely '
'an issue with the localizations generation tool. Please file an issue ' 'an issue with the localizations generation tool. Please file an issue '
'on GitHub with a reproducible sample app and the gen-l10n configuration ' 'on GitHub with a reproducible sample app and the gen-l10n configuration '
'that was used.'); 'that was used.'
);
} }

View File

@ -6,22 +6,28 @@ part of 'characters_dto.dart';
// JsonSerializableGenerator // JsonSerializableGenerator
// ************************************************************************** // **************************************************************************
CharactersDto _$CharactersDtoFromJson(Map<String, dynamic> json) => CharactersDto( CharactersDto _$CharactersDtoFromJson(Map<String, dynamic> json) =>
CharactersDto(
data: (json['data'] as List<dynamic>?) data: (json['data'] as List<dynamic>?)
?.map((e) => CharacterDataDto.fromJson(e as Map<String, dynamic>)) ?.map((e) => CharacterDataDto.fromJson(e as Map<String, dynamic>))
.toList(), .toList(),
meta: json['meta'] == null ? null : MetaDto.fromJson(json['meta'] as Map<String, dynamic>), meta: json['meta'] == null
? null
: MetaDto.fromJson(json['meta'] as Map<String, dynamic>),
); );
CharacterDataDto _$CharacterDataDtoFromJson(Map<String, dynamic> json) => CharacterDataDto( CharacterDataDto _$CharacterDataDtoFromJson(Map<String, dynamic> json) =>
CharacterDataDto(
id: json['id'] as String?, id: json['id'] as String?,
type: json['type'] as String?, type: json['type'] as String?,
attributes: json['attributes'] == null attributes: json['attributes'] == null
? null ? null
: CharacterAttributesDataDto.fromJson(json['attributes'] as Map<String, dynamic>), : CharacterAttributesDataDto.fromJson(
json['attributes'] as Map<String, dynamic>),
); );
CharacterAttributesDataDto _$CharacterAttributesDataDtoFromJson(Map<String, dynamic> json) => CharacterAttributesDataDto _$CharacterAttributesDataDtoFromJson(
Map<String, dynamic> json) =>
CharacterAttributesDataDto( CharacterAttributesDataDto(
name: json['name'] as String?, name: json['name'] as String?,
born: json['born'] as String?, born: json['born'] as String?,
@ -35,7 +41,8 @@ MetaDto _$MetaDtoFromJson(Map<String, dynamic> json) => MetaDto(
: PaginationDto.fromJson(json['pagination'] as Map<String, dynamic>), : PaginationDto.fromJson(json['pagination'] as Map<String, dynamic>),
); );
PaginationDto _$PaginationDtoFromJson(Map<String, dynamic> json) => PaginationDto( PaginationDto _$PaginationDtoFromJson(Map<String, dynamic> json) =>
PaginationDto(
current: (json['current'] as num?)?.toInt(), current: (json['current'] as num?)?.toInt(),
next: (json['next'] as num?)?.toInt(), next: (json['next'] as num?)?.toInt(),
last: (json['last'] as num?)?.toInt(), last: (json['last'] as num?)?.toInt(),

View File

@ -4,56 +4,63 @@ part 'pokemon_dto.g.dart';
@JsonSerializable(createToJson: false) @JsonSerializable(createToJson: false)
class PokemonDto { class PokemonDto {
final int id; final List<PokemonDataDto>? results;
final String name; final int? count;
final List<PokemonTypeDto> types; final String? next;
final PokemonSpritesDto sprites; final String? previous;
const PokemonDto({ const PokemonDto({
required this.id, this.results,
required this.name, this.count,
required this.types, this.next,
required this.sprites, this.previous,
}); });
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 PokemonTypeDto { class PokemonDataDto {
final int slot; final String? name;
final PokemonTypeDetailDto type; final String? url;
const PokemonTypeDto({ const PokemonDataDto({
required this.slot, this.name,
required this.type, this.url,
}); });
factory PokemonTypeDto.fromJson(Map<String, dynamic> json) => _$PokemonTypeDtoFromJson(json); factory PokemonDataDto.fromJson(Map<String, dynamic> json) => _$PokemonDataDtoFromJson(json);
} }
@JsonSerializable(createToJson: false) @JsonSerializable(createToJson: false)
class PokemonTypeDetailDto { class PokemonDetailsDto {
final String name; final int? height;
final String url; final int? weight;
final List<AbilityDto>? abilities;
const PokemonTypeDetailDto({ const PokemonDetailsDto({
required this.name, this.height,
required this.url, this.weight,
this.abilities,
}); });
factory PokemonTypeDetailDto.fromJson(Map<String, dynamic> json) => factory PokemonDetailsDto.fromJson(Map<String, dynamic> json) => _$PokemonDetailsDtoFromJson(json);
_$PokemonTypeDetailDtoFromJson(json);
} }
@JsonSerializable(createToJson: false) @JsonSerializable(createToJson: false)
class PokemonSpritesDto { class AbilityDto {
final String front_default; final AbilityDetailDto? ability;
const PokemonSpritesDto({ const AbilityDto({this.ability});
required this.front_default,
});
factory PokemonSpritesDto.fromJson(Map<String, dynamic> json) => factory AbilityDto.fromJson(Map<String, dynamic> json) => _$AbilityDtoFromJson(json);
_$PokemonSpritesDtoFromJson(json);
} }
@JsonSerializable(createToJson: false)
class AbilityDetailDto {
final String? name;
const AbilityDetailDto({this.name});
factory AbilityDetailDto.fromJson(Map<String, dynamic> json) => _$AbilityDetailDtoFromJson(json);
}

View File

@ -7,25 +7,36 @@ part of 'pokemon_dto.dart';
// ************************************************************************** // **************************************************************************
PokemonDto _$PokemonDtoFromJson(Map<String, dynamic> json) => PokemonDto( PokemonDto _$PokemonDtoFromJson(Map<String, dynamic> json) => PokemonDto(
id: (json['id'] as num).toInt(), results: (json['results'] as List<dynamic>?)
name: json['name'] as String, ?.map((e) => PokemonDataDto.fromJson(e as Map<String, dynamic>))
types: (json['types'] as List<dynamic>)
.map((e) => PokemonTypeDto.fromJson(e as Map<String, dynamic>))
.toList(), .toList(),
sprites: PokemonSpritesDto.fromJson(json['sprites'] as Map<String, dynamic>), count: (json['count'] as num?)?.toInt(),
next: json['next'] as String?,
previous: json['previous'] as String?,
); );
PokemonTypeDto _$PokemonTypeDtoFromJson(Map<String, dynamic> json) => PokemonTypeDto( PokemonDataDto _$PokemonDataDtoFromJson(Map<String, dynamic> json) =>
slot: (json['slot'] as num).toInt(), PokemonDataDto(
type: PokemonTypeDetailDto.fromJson(json['type'] as Map<String, dynamic>), name: json['name'] as String?,
url: json['url'] as String?,
); );
PokemonTypeDetailDto _$PokemonTypeDetailDtoFromJson(Map<String, dynamic> json) => PokemonDetailsDto _$PokemonDetailsDtoFromJson(Map<String, dynamic> json) =>
PokemonTypeDetailDto( PokemonDetailsDto(
name: json['name'] as String, height: (json['height'] as num?)?.toInt(),
url: json['url'] as String, weight: (json['weight'] as num?)?.toInt(),
abilities: (json['abilities'] as List<dynamic>?)
?.map((e) => AbilityDto.fromJson(e as Map<String, dynamic>))
.toList(),
); );
PokemonSpritesDto _$PokemonSpritesDtoFromJson(Map<String, dynamic> json) => PokemonSpritesDto( AbilityDto _$AbilityDtoFromJson(Map<String, dynamic> json) => AbilityDto(
front_default: json['front_default'] as String, ability: json['ability'] == null
? null
: AbilityDetailDto.fromJson(json['ability'] as Map<String, dynamic>),
);
AbilityDetailDto _$AbilityDetailDtoFromJson(Map<String, dynamic> json) =>
AbilityDetailDto(
name: json['name'] as String?,
); );

View File

@ -1,17 +1,34 @@
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';
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 PokemonDtoToModel on PokemonDto {
CardData toDomain() => CardData( HomeData toDomain() => HomeData(
name, data: results?.map((e) => e.toDomain()).toList(),
imageUrl: sprites.front_default ?? _imagePlaceholder, nextPage: next != null ? int.tryParse(next!.split('=')[1].split('&')[0]) : null,
descriptionText: _makeDescriptionText(types), );
); }
String _makeDescriptionText(List<PokemonTypeDto> types) { extension PokemonDataDtoToModel on PokemonDataDto {
return 'Types: ${types.map((type) => type.type.name).join(', ')}'; CardData toDomain() {
final id = url?.split('/')[6] ?? 'UNKNOWN';
final imageUrl = 'https://raw.githubusercontent.com/PokeAPI/sprites/master/sprites/pokemon/$id.png';
return CardData(
name ?? 'UNKNOWN',
imageUrl: imageUrl,
descriptionText: 'ID: $id',
id: id,
);
} }
} }
extension PokemonDetailsDtoToModel on PokemonDetailsDto {
String toDescriptionText() {
final abilitiesText = abilities?.map((ability) => ability.ability?.name ?? 'UNKNOWN').join(', ') ?? 'UNKNOWN';
return 'Height: ${height ?? 'UNKNOWN'} cm, Weight: ${weight ?? 'UNKNOWN'} kg, Abilities: $abilitiesText';
}
}

View File

@ -1 +1,72 @@
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/home.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';
class PokeRepository extends ApiInterface {
static final Dio _dio = Dio()
..interceptors.add(PrettyDioLogger(
requestHeader: true,
requestBody: true,
));
static const String _baseUrl = 'https://pokeapi.co/api/v2';
List<PokemonDataDto> _allPokemon = [];
bool _isAllPokemonLoaded = false;
@override
Future<HomeData?> loadData({
OnErrorCallback? onError,
String? q,
int page = 1,
int pageSize = 25,
}) async {
try {
if (!_isAllPokemonLoaded) {
final String url = '$_baseUrl/pokemon';
final Response<dynamic> response = await _dio.get<Map<dynamic, dynamic>>(
url,
queryParameters: {
'offset': (page - 1) * pageSize,
'limit': pageSize,
},
);
final PokemonDto dto = PokemonDto.fromJson(response.data as Map<String, dynamic>);
_allPokemon = dto.results ?? [];
_isAllPokemonLoaded = true;
}
final List<PokemonDataDto> filteredPokemon = q != null && q.isNotEmpty
? _allPokemon.where((pokemon) => pokemon.name!.contains(q)).toList()
: _allPokemon;
final int startIndex = (page - 1) * pageSize;
final int endIndex = startIndex + pageSize;
if (startIndex >= filteredPokemon.length) {
return HomeData(
data: [],
nextPage: null,
);
}
final List<PokemonDataDto> paginatedPokemon = filteredPokemon.sublist(
startIndex,
endIndex > filteredPokemon.length ? filteredPokemon.length : endIndex,
);
final HomeData data = HomeData(
data: paginatedPokemon.map((e) => e.toDomain()).toList(),
nextPage: endIndex < filteredPokemon.length ? page + 1 : null,
);
return data;
} on DioException catch (e) {
onError?.call(e.error?.toString());
return null;
}
}
}

View File

@ -2,6 +2,7 @@ import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:mobilki_lab1/data/repositories/pokemon_repository.dart';
import 'package:mobilki_lab1/presentation/home_page/bloc/bloc.dart'; import 'package:mobilki_lab1/presentation/home_page/bloc/bloc.dart';
import 'package:mobilki_lab1/presentation/home_page/home_page.dart'; import 'package:mobilki_lab1/presentation/home_page/home_page.dart';
import 'package:mobilki_lab1/presentation/like_bloc/like_bloc.dart'; import 'package:mobilki_lab1/presentation/like_bloc/like_bloc.dart';
@ -34,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<PotterRepository>( home: RepositoryProvider<PokeRepository>(
lazy: true, lazy: true,
create: (_) => PotterRepository(), 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<PotterRepository>()), create: (context) => HomeBloc(context.read<PokeRepository>()),
child: const MyHomePage(title: 'Чубыкина Полина Павловна'), child: const MyHomePage(title: 'Чубыкина Полина Павловна'),
), ),
), ),

View File

@ -3,8 +3,11 @@ import 'package:mobilki_lab1/data/repositories/potter_repository.dart';
import 'package:mobilki_lab1/presentation/home_page/bloc/events.dart'; import 'package:mobilki_lab1/presentation/home_page/bloc/events.dart';
import 'package:mobilki_lab1/presentation/home_page/bloc/state.dart'; import 'package:mobilki_lab1/presentation/home_page/bloc/state.dart';
import '../../../data/repositories/pokemon_repository.dart';
class HomeBloc extends Bloc<HomeEvent, HomeState> { class HomeBloc extends Bloc<HomeEvent, HomeState> {
final PotterRepository repo; // final PotterRepository repo;
final PokeRepository repo;
HomeBloc(this.repo) : super(const HomeState()) { HomeBloc(this.repo) : super(const HomeState()) {
on<HomeLoadDataEvent>(_onLoadData); on<HomeLoadDataEvent>(_onLoadData);

View File

@ -27,7 +27,8 @@ class _$LocaleStateCWProxyImpl implements _$LocaleStateCWProxy {
final LocaleState _value; final LocaleState _value;
@override @override
LocaleState currentLocale(Locale currentLocale) => this(currentLocale: currentLocale); LocaleState currentLocale(Locale currentLocale) =>
this(currentLocale: currentLocale);
@override @override
@ -41,10 +42,11 @@ class _$LocaleStateCWProxyImpl implements _$LocaleStateCWProxy {
Object? currentLocale = const $CopyWithPlaceholder(), Object? currentLocale = const $CopyWithPlaceholder(),
}) { }) {
return LocaleState( return LocaleState(
currentLocale: currentLocale == const $CopyWithPlaceholder() || currentLocale == null currentLocale:
? _value.currentLocale currentLocale == const $CopyWithPlaceholder() || currentLocale == null
// ignore: cast_nullable_to_non_nullable ? _value.currentLocale
: currentLocale as Locale, // ignore: cast_nullable_to_non_nullable
: currentLocale as Locale,
); );
} }
} }