From 4eb97b0f84da2caeb0c16b882ce0d0e1a3a124ff Mon Sep 17 00:00:00 2001 From: bulatova_karina Date: Wed, 13 Nov 2024 18:12:45 +0400 Subject: [PATCH] =?UTF-8?q?=D0=B4=D0=B5=D0=BB=D0=B0=D1=8E=20=D0=BA=D1=83?= =?UTF-8?q?=D1=80=D1=81=D0=BE=D0=B2=D1=83=D1=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/data/dtos/films_dto.dart | 44 ++++++++++ lib/data/dtos/films_dto.g.dart | 27 +++++++ lib/data/mappers/films_mapper.dart | 27 +++++++ lib/data/repositories/films_repository.dart | 90 +++++++++++++++++++++ lib/main.dart | 8 +- lib/presentation/home_page/bloc/bloc.dart | 4 +- 6 files changed, 194 insertions(+), 6 deletions(-) create mode 100644 lib/data/dtos/films_dto.dart create mode 100644 lib/data/dtos/films_dto.g.dart create mode 100644 lib/data/mappers/films_mapper.dart create mode 100644 lib/data/repositories/films_repository.dart diff --git a/lib/data/dtos/films_dto.dart b/lib/data/dtos/films_dto.dart new file mode 100644 index 0000000..299f4c1 --- /dev/null +++ b/lib/data/dtos/films_dto.dart @@ -0,0 +1,44 @@ +import 'package:json_annotation/json_annotation.dart'; + +part 'films_dto.g.dart'; + +@JsonSerializable(createToJson: false) +class FilmsDto { + final int total; + final List items; + + + const FilmsDto({ + required this.total, + required this.items, + }); + + factory FilmsDto.fromJson(Map json) => _$FilmsDtoFromJson(json); +} + +@JsonSerializable(createToJson: false) +class FilmDataDto { + final String nameRu; + final int year; + final List genres; + final String posterUrl; + + const FilmDataDto({ + required this.nameRu, + required this.year, + required this.genres, + required this.posterUrl, + }); + + factory FilmDataDto.fromJson(Map json) => _$FilmDataDtoFromJson(json); +} + +@JsonSerializable(createToJson: false) +class GenreDto { + final String genre; + + const GenreDto({required this.genre}); + + factory GenreDto.fromJson(Map json) => _$GenreDtoFromJson(json); +} + diff --git a/lib/data/dtos/films_dto.g.dart b/lib/data/dtos/films_dto.g.dart new file mode 100644 index 0000000..3507b0c --- /dev/null +++ b/lib/data/dtos/films_dto.g.dart @@ -0,0 +1,27 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'films_dto.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +FilmsDto _$FilmsDtoFromJson(Map json) => FilmsDto( + total: (json['total'] as num).toInt(), + items: (json['items'] as List) + .map((e) => FilmDataDto.fromJson(e as Map)) + .toList(), + ); + +FilmDataDto _$FilmDataDtoFromJson(Map json) => FilmDataDto( + nameRu: json['nameRu'] as String, + year: (json['year'] as num).toInt(), + genres: (json['genres'] as List) + .map((e) => GenreDto.fromJson(e as Map)) + .toList(), + posterUrl: json['posterUrl'] as String, + ); + +GenreDto _$GenreDtoFromJson(Map json) => GenreDto( + genre: json['genre'] as String, + ); diff --git a/lib/data/mappers/films_mapper.dart b/lib/data/mappers/films_mapper.dart new file mode 100644 index 0000000..9c60373 --- /dev/null +++ b/lib/data/mappers/films_mapper.dart @@ -0,0 +1,27 @@ +import 'package:project1/data/dtos/films_dto.dart'; +import 'package:project1/domain/models/card.dart'; +import 'package:project1/domain/models/home.dart'; + +const _imagePlaceholder = + 'https://upload.wikimedia.org/wikipedia/en/archive/b/b1/20210811082420%21Portrait_placeholder.png'; + +extension FilmsDtoToModel on FilmsDto { + HomeData toDomain() => HomeData( + data: items.map((e) => e.toDomain()).toList(), + nextPage: null, + ); +} + +extension FilmDataDtoToModel on FilmDataDto { + CardData toDomain() => CardData( + nameRu, + imageUrl: posterUrl ?? _imagePlaceholder, + descriptionText: _makeDescriptionText(year, genres), + ); + + String _makeDescriptionText(int? year, List genres) { + final yearText = year != null ? 'Год выхода: $year\n' : ''; + final genresText = genres.isNotEmpty ? 'Жанр: ${genres.map((g) => g.genre).join(', ')}' : ''; + return [yearText, genresText].where((s) => s.isNotEmpty).join(); + } +} \ No newline at end of file diff --git a/lib/data/repositories/films_repository.dart b/lib/data/repositories/films_repository.dart new file mode 100644 index 0000000..d07bb69 --- /dev/null +++ b/lib/data/repositories/films_repository.dart @@ -0,0 +1,90 @@ +import 'package:dio/dio.dart'; +import 'package:pretty_dio_logger/pretty_dio_logger.dart'; +import 'package:project1/data/dtos/films_dto.dart'; +import 'package:project1/data/mappers/films_mapper.dart'; +import 'package:project1/domain/models/home.dart'; + +import 'api_interface.dart'; + +class FilmsRepository extends ApiInterface { + static final Dio _dio = Dio() + ..interceptors.add(PrettyDioLogger( + requestHeader: true, + requestBody: true, + )); + + static const String _baseUrl = 'https://kinopoiskapiunofficial.tech'; + static const String _apiKey = '67c830e4-b979-48ba-903d-a00c8f96fd4b'; + + @override + Future loadData({ + OnErrorCallback? onError, + String? q, + int page = 1, + int pageSize = 7, + }) async { + try { + const String url = '$_baseUrl/api/v2.2/films/premieres'; + + final List months = [ + 'JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', + 'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER' + ]; + + final List allFilms = []; + + for (final month in months) { + final Response response = await _dio.get>( + url, + queryParameters: { + 'year': DateTime.now().year, // Используем текущий год + 'month': month, + 'page': page, + 'pageSize': pageSize, + }, + options: Options( + headers: { + 'X-API-KEY': _apiKey, + 'Content-Type': 'application/json', + }, + ), + ); + + final FilmsDto dto = FilmsDto.fromJson(response.data as Map); + allFilms.addAll(dto.items); + } + + final HomeData data = HomeData( + data: allFilms.map((e) => e.toDomain()).toList(), + nextPage: null, // Если нужно добавить поддержку пагинации, нужно будет добавить соответствующие поля в HomeData + ); + + return data; + } on DioException catch (e) { + onError?.call(e.error?.toString()); + return null; + } + } + + Future getFilmById(int filmId) async { + try { + final String url = '$_baseUrl/api/v2.2/films/$filmId'; + + final Response response = await _dio.get>( + url, + options: Options( + headers: { + 'X-API-KEY': _apiKey, + 'Content-Type': 'application/json', + }, + ), + ); + + final FilmDataDto dto = FilmDataDto.fromJson(response.data as Map); + return dto; + } on DioException catch (e) { + print('Request failed with error: ${e.error}'); + return null; + } + } +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index eb59499..5c0f5f1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:project1/presentation/home_page/home_page.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:project1/presentation/home_page/bloc/bloc.dart'; -import 'data/repositories/potter_repository.dart'; +import 'data/repositories/films_repository.dart'; void main() { runApp(const MyApp()); @@ -20,12 +20,12 @@ class MyApp extends StatelessWidget { colorScheme: ColorScheme.fromSeed(seedColor: Colors.pink), useMaterial3: true, ), - home: RepositoryProvider( + home: RepositoryProvider( lazy: true, - create: (_) => PotterRepository(), + create: (_) => FilmsRepository(), child: BlocProvider( lazy: false, - create: (context) => HomeBloc(context.read()), + create: (context) => HomeBloc(context.read()), child: const MyHomePage(title: 'Булатова Каринa Раилевна'), ), ), diff --git a/lib/presentation/home_page/bloc/bloc.dart b/lib/presentation/home_page/bloc/bloc.dart index 8462858..69790d3 100644 --- a/lib/presentation/home_page/bloc/bloc.dart +++ b/lib/presentation/home_page/bloc/bloc.dart @@ -1,10 +1,10 @@ import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:project1/data/repositories/potter_repository.dart'; +import 'package:project1/data/repositories/films_repository.dart'; import 'package:project1/presentation/home_page/bloc/events.dart'; import 'package:project1/presentation/home_page/bloc/state.dart'; class HomeBloc extends Bloc { - final PotterRepository repo; + final FilmsRepository repo; HomeBloc(this.repo) : super(const HomeState()) { on(_onLoadData);