diff --git a/lib/Components/resources.g.dart b/lib/Components/resources.g.dart deleted file mode 100644 index 41f3155..0000000 --- a/lib/Components/resources.g.dart +++ /dev/null @@ -1,12 +0,0 @@ -/// Generate by [asset_generator](https://github.com/fluttercandies/flutter_asset_generator) library. -/// PLEASE DO NOT EDIT MANUALLY. -// ignore_for_file: constant_identifier_names -class R { - const R._(); - - /// ![preview](file://C:\Users\89176\StudioProjects\first_project\assets\svg\gb.svg) - static const String ASSETS_SVG_GB_SVG = 'assets/svg/gb.svg'; - - /// ![preview](file://C:\Users\89176\StudioProjects\first_project\assets\svg\ru.svg) - static const String ASSETS_SVG_RU_SVG = 'assets/svg/ru.svg'; -} diff --git a/lib/Components/screens/hero_detail_screen.dart b/lib/Components/screens/hero_detail_screen.dart index 6008d64..6715d29 100644 --- a/lib/Components/screens/hero_detail_screen.dart +++ b/lib/Components/screens/hero_detail_screen.dart @@ -23,7 +23,8 @@ class HeroDetailScreen extends StatelessWidget { return const Center(child: CircularProgressIndicator()); } else if (state is HeroDetailLoaded) { final hero = state.hero; - return SingleChildScrollView( // Добавляем прокрутку + return SingleChildScrollView( + // Добавляем прокрутку child: Padding( padding: const EdgeInsets.all(16.0), child: Column( diff --git a/lib/data/dtos/anime_dto.dart b/lib/data/dtos/anime_dto.dart deleted file mode 100644 index 01da857..0000000 --- a/lib/data/dtos/anime_dto.dart +++ /dev/null @@ -1,62 +0,0 @@ -import 'package:json_annotation/json_annotation.dart'; - -part 'anime_dto.g.dart'; - -@JsonSerializable(createToJson: false) -class AnimesDto { - final List? data; - final PaginationDto? pagination; - - const AnimesDto({this.data, this.pagination}); - - factory AnimesDto.fromJson(Map json) => _$AnimesDtoFromJson(json); -} - -@JsonSerializable(createToJson: false) -class AnimeDataDto { - @JsonKey(name: 'mal_id') - final int? id; - final String? title; - final String? synopsis; - final double? score; - final AnimeImagesDto? images; - - const AnimeDataDto(this.id, this.title, this.synopsis, this.images, this.score); - factory AnimeDataDto.fromJson(Map json) => _$AnimeDataDtoFromJson(json); -} - -@JsonSerializable(createToJson: false) -class AnimeImagesDto { - final AnimeImagesJpgDto? jpg; - - const AnimeImagesDto({this.jpg}); - - factory AnimeImagesDto.fromJson(Map json) => _$AnimeImagesDtoFromJson(json); -} - -@JsonSerializable(createToJson: false) -class AnimeImagesJpgDto { - @JsonKey(name: 'image_url') - final String? image; - @JsonKey(name: 'small_image_url') - final String? smallImage; - @JsonKey(name: 'large_image_url') - final String? largeImage; - - const AnimeImagesJpgDto(this.image, this.smallImage, this.largeImage); - factory AnimeImagesJpgDto.fromJson(Map json) => - _$AnimeImagesJpgDtoFromJson(json); -} - -@JsonSerializable(createToJson: false) -class PaginationDto { - @JsonKey(name: "last_visible_page") - final int? last; - @JsonKey(name: "current_page") - final int? current; - @JsonKey(name: "has_next_page") - final bool? next; - - const PaginationDto({this.current, this.last, this.next}); - factory PaginationDto.fromJson(Map json) => _$PaginationDtoFromJson(json); -} diff --git a/lib/data/dtos/anime_dto.g.dart b/lib/data/dtos/anime_dto.g.dart deleted file mode 100644 index eb908b0..0000000 --- a/lib/data/dtos/anime_dto.g.dart +++ /dev/null @@ -1,44 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'anime_dto.dart'; - -// ************************************************************************** -// JsonSerializableGenerator -// ************************************************************************** - -AnimesDto _$AnimesDtoFromJson(Map json) => AnimesDto( - data: (json['data'] as List?) - ?.map((e) => AnimeDataDto.fromJson(e as Map)) - .toList(), - pagination: json['pagination'] == null - ? null - : PaginationDto.fromJson(json['pagination'] as Map), - ); - -AnimeDataDto _$AnimeDataDtoFromJson(Map json) => AnimeDataDto( - (json['mal_id'] as num?)?.toInt(), - json['title'] as String?, - json['synopsis'] as String?, - json['images'] == null - ? null - : AnimeImagesDto.fromJson(json['images'] as Map), - (json['score'] as num?)?.toDouble(), - ); - -AnimeImagesDto _$AnimeImagesDtoFromJson(Map json) => AnimeImagesDto( - jpg: json['jpg'] == null - ? null - : AnimeImagesJpgDto.fromJson(json['jpg'] as Map), - ); - -AnimeImagesJpgDto _$AnimeImagesJpgDtoFromJson(Map json) => AnimeImagesJpgDto( - json['image_url'] as String?, - json['small_image_url'] as String?, - json['large_image_url'] as String?, - ); - -PaginationDto _$PaginationDtoFromJson(Map json) => PaginationDto( - current: (json['current_page'] as num?)?.toInt(), - last: (json['last_visible_page'] as num?)?.toInt(), - next: json['has_next_page'] as bool?, - ); diff --git a/lib/data/mappers/anime_mapper.dart b/lib/data/mappers/anime_mapper.dart deleted file mode 100644 index a67f30e..0000000 --- a/lib/data/mappers/anime_mapper.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:first_project/data/dtos/anime_dto.dart'; -import 'package:first_project/domain/models/home.dart'; -import 'package:first_project/presentation/home_page/home_page.dart'; - -extension AnimeDataDtoToModel on AnimeDataDto { - CardData toDomain() => CardData( - title ?? 'NOT', - imageUrl: images?.jpg?.image ?? "NONE", - score: score ?? 0, - description: synopsis == null - ? "NONE" - : synopsis!.split('\n').sublist(0, synopsis!.split('\n').length - 1).join('\n'), - id: id.toString(), - ); -} - -extension AnimesDataDtoToModel on AnimesDto { - HomeData toDomain() => HomeData( - data: data?.map((e) => e.toDomain()).toList(), - nextPage: pagination!.next! ? pagination!.current! + 1 : 0, - ); -} diff --git a/lib/data/repositories/anime_repository.dart b/lib/data/repositories/anime_repository.dart deleted file mode 100644 index 88c07bc..0000000 --- a/lib/data/repositories/anime_repository.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:dio/dio.dart'; -import 'package:first_project/data/dtos/anime_dto.dart'; -import 'package:first_project/data/mappers/anime_mapper.dart'; -import 'package:first_project/data/repositories/api_interface.dart'; -import 'package:first_project/domain/models/home.dart'; -import 'package:first_project/presentation/home_page/home_page.dart'; -import 'package:pretty_dio_logger/pretty_dio_logger.dart'; - -class AnimeRepository extends ApiInterface { - static final Dio _dio = Dio() - ..interceptors.add(PrettyDioLogger( - requestHeader: true, - requestBody: true, - )); - - static const String _baseUrl = 'https://api.jikan.moe'; - - @override - Future loadData( - {OnErrorCallback? onError, String? q, int page = 1, int pageSize = 25}) async { - try { - const String url = '$_baseUrl/v4/anime'; - Map query = {'q': q, 'page': page, 'limit': pageSize}; - final Response response = await _dio.get>( - url, - queryParameters: query, - ); - final AnimesDto dto = AnimesDto.fromJson(response.data as Map); - final HomeData data = dto.toDomain(); - return data; - } on DioException catch (e) { - onError?.call(e.error?.toString()); - return null; - } - } -} diff --git a/lib/data/repositories/api_interface.dart b/lib/data/repositories/api_interface.dart deleted file mode 100644 index f80ffb7..0000000 --- a/lib/data/repositories/api_interface.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:first_project/domain/models/home.dart'; -import 'package:first_project/presentation/home_page/home_page.dart'; - -typedef OnErrorCallback = void Function(String? error); - -abstract class ApiInterface { - Future loadData({OnErrorCallback? onError}); -} diff --git a/lib/data/repositories/hero_repository.dart b/lib/data/repositories/hero_repository.dart index 103e7de..9bac377 100644 --- a/lib/data/repositories/hero_repository.dart +++ b/lib/data/repositories/hero_repository.dart @@ -15,4 +15,4 @@ class HeroRepository { final hero = await apiService.fetchHeroDetails(id); return HeroDto.fromJson(hero); } -} \ No newline at end of file +} diff --git a/lib/data/repositories/mock_repository.dart b/lib/data/repositories/mock_repository.dart deleted file mode 100644 index 913b308..0000000 --- a/lib/data/repositories/mock_repository.dart +++ /dev/null @@ -1,30 +0,0 @@ -import 'package:first_project/data/repositories/api_interface.dart'; -import 'package:first_project/domain/models/home.dart'; -import 'package:first_project/presentation/home_page/home_page.dart'; -import 'package:flutter/material.dart'; - -class MockRepository extends ApiInterface { - @override - Future loadData({OnErrorCallback? onError}) async { - return HomeData(data: [ - const CardData( - "First", - score: 5, - description: "SomeText", - ), - const CardData( - "Second", - score: 8, - icon: Icons.gamepad, - description: "ManyText", - imageUrl: "https://i.pinimg.com/originals/21/73/24/217324138d1bbc91663d4943ebe5de60.jpg", - ), - const CardData( - "Third", - score: 9, - icon: Icons.offline_bolt_outlined, - description: "Wow >_<", - ), - ]); - } -} diff --git a/lib/domain/models/card.dart b/lib/domain/models/card.dart deleted file mode 100644 index e64da91..0000000 --- a/lib/domain/models/card.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:first_project/presentation/home_page/home_page.dart'; -import 'package:flutter/material.dart'; - -class DetailsPage extends StatelessWidget { - final CardData data; - - const DetailsPage(this.data, {super.key}); - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar(), - body: SingleChildScrollView( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(bottom: 16), - child: Image.network( - data.imageUrl, - ), - ), - Padding( - padding: const EdgeInsets.only(bottom: 4), - child: Text( - data.text, - style: Theme.of(context).textTheme.headlineLarge, - )), - Text( - data.description, - style: Theme.of(context).textTheme.bodyLarge, - ) - ], - ), - ), - ); - } -} diff --git a/lib/domain/models/home.dart b/lib/domain/models/home.dart deleted file mode 100644 index 520097d..0000000 --- a/lib/domain/models/home.dart +++ /dev/null @@ -1,8 +0,0 @@ -import 'package:first_project/presentation/home_page/home_page.dart'; - -class HomeData { - final List? data; - final int? nextPage; - - HomeData({this.data, this.nextPage}); -} diff --git a/lib/main.dart b/lib/main.dart index e6615d8..7aca35a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -21,8 +21,7 @@ class LocaleNotifier with ChangeNotifier { Locale get currentLocale => _currentLocale; void toggleLocale() { - _currentLocale = - _currentLocale.languageCode == 'en' ? const Locale('ru') : const Locale('en'); + _currentLocale = _currentLocale.languageCode == 'en' ? const Locale('ru') : const Locale('en'); notifyListeners(); } } @@ -55,8 +54,7 @@ class MyApp extends StatelessWidget { return MultiBlocProvider( providers: [ BlocProvider( - create: (_) => - HeroSearchBloc(allHeroes: state.heroes), + create: (_) => HeroSearchBloc(allHeroes: state.heroes), ), ], child: const HeroListScreen(), diff --git a/lib/presentation/common/svg_objects.dart b/lib/presentation/common/svg_objects.dart deleted file mode 100644 index dbad5c4..0000000 --- a/lib/presentation/common/svg_objects.dart +++ /dev/null @@ -1,34 +0,0 @@ -import 'package:flutter/cupertino.dart'; -import 'package:flutter_svg/flutter_svg.dart'; -import 'package:first_project/Components/resources.g.dart'; - -abstract class SvgObjects { - static void init() { - final pics = [ - R.ASSETS_SVG_RU_SVG, - R.ASSETS_SVG_GB_SVG, - ]; - for (final String p in pics) { - final loader = SvgAssetLoader(p); - svg.cache.putIfAbsent(loader.cacheKey(null), () => loader.loadBytes(null)); - } - } -} - -class SvgRu extends StatelessWidget { - const SvgRu({super.key}); - - @override - Widget build(BuildContext context) { - return SvgPicture.asset(R.ASSETS_SVG_RU_SVG); - } -} - -class SvgGb extends StatelessWidget { - const SvgGb({super.key}); - - @override - Widget build(BuildContext context) { - return SvgPicture.asset(R.ASSETS_SVG_GB_SVG); - } -} diff --git a/lib/presentation/details_page/details_page.dart b/lib/presentation/details_page/details_page.dart deleted file mode 100644 index 8b13789..0000000 --- a/lib/presentation/details_page/details_page.dart +++ /dev/null @@ -1 +0,0 @@ - diff --git a/lib/presentation/home_page/bloc/bloc.dart b/lib/presentation/home_page/bloc/bloc.dart deleted file mode 100644 index ee6cc77..0000000 --- a/lib/presentation/home_page/bloc/bloc.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:first_project/data/repositories/anime_repository.dart'; -import 'package:first_project/presentation/home_page/bloc/events.dart'; -import 'package:first_project/presentation/home_page/bloc/state.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -class HomeBloc extends Bloc { - final AnimeRepository repo; - - HomeBloc(this.repo) : super(const HomeState()) { - on(_onLoadData); - } - - Future _onLoadData(HomeLoadDataEvent event, Emitter emit) async { - if (event.nextPage == null) { - emit(state.copyWith(isLoading: true)); - } else { - emit(state.copyWith(isPaginationLoading: true)); - } - - String? error; - - final data = await repo.loadData( - q: event.search, - page: event.nextPage ?? 1, - onError: (e) => error = e, - ); - - if (event.nextPage != null) { - data?.data?.insertAll(0, state.data?.data ?? []); - } - emit(state.copyWith( - data: data, - isLoading: false, - isPaginationLoading: false, - error: error, - )); - } -} diff --git a/lib/presentation/home_page/bloc/events.dart b/lib/presentation/home_page/bloc/events.dart deleted file mode 100644 index cefba70..0000000 --- a/lib/presentation/home_page/bloc/events.dart +++ /dev/null @@ -1,10 +0,0 @@ -abstract class HomeEvent { - const HomeEvent(); -} - -class HomeLoadDataEvent extends HomeEvent { - final String? search; - final int? nextPage; - - const HomeLoadDataEvent({this.search, this.nextPage}); -} diff --git a/lib/presentation/home_page/bloc/state.dart b/lib/presentation/home_page/bloc/state.dart deleted file mode 100644 index f74ef71..0000000 --- a/lib/presentation/home_page/bloc/state.dart +++ /dev/null @@ -1,38 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:first_project/domain/models/card.dart'; -import 'package:first_project/domain/models/home.dart'; -import 'package:first_project/presentation/home_page/home_page.dart'; -import 'package:copy_with_extension/copy_with_extension.dart'; - -part 'state.g.dart'; - -@CopyWith() -class HomeState extends Equatable { - final HomeData? data; - final bool isLoading; - final bool isPaginationLoading; - final String? error; - - const HomeState({ - this.data, - this.isLoading = false, - this.isPaginationLoading = false, - this.error, - }); - - HomeState copyWith({HomeData? data, bool? isLoading, bool? isPaginationLoading, String? error}) => - HomeState( - data: data ?? this.data, - isLoading: isLoading ?? this.isLoading, - isPaginationLoading: isPaginationLoading ?? this.isPaginationLoading, - error: error ?? this.error, - ); - - @override - List get props => [ - data, - isLoading, - isPaginationLoading, - error, - ]; -} diff --git a/lib/presentation/home_page/bloc/state.g.dart b/lib/presentation/home_page/bloc/state.g.dart deleted file mode 100644 index 258a914..0000000 --- a/lib/presentation/home_page/bloc/state.g.dart +++ /dev/null @@ -1,91 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'state.dart'; - -// ************************************************************************** -// CopyWithGenerator -// ************************************************************************** - -abstract class _$HomeStateCWProxy { - HomeState data(HomeData? data); - - HomeState isLoading(bool isLoading); - - HomeState isPaginationLoading(bool isPaginationLoading); - - HomeState error(String? error); - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `HomeState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// HomeState(...).copyWith(id: 12, name: "My name") - /// ```` - HomeState call({ - HomeData? data, - bool? isLoading, - bool? isPaginationLoading, - String? error, - }); -} - -/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfHomeState.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfHomeState.copyWith.fieldName(...)` -class _$HomeStateCWProxyImpl implements _$HomeStateCWProxy { - const _$HomeStateCWProxyImpl(this._value); - - final HomeState _value; - - @override - HomeState data(HomeData? data) => this(data: data); - - @override - HomeState isLoading(bool isLoading) => this(isLoading: isLoading); - - @override - HomeState isPaginationLoading(bool isPaginationLoading) => - this(isPaginationLoading: isPaginationLoading); - - @override - HomeState error(String? error) => this(error: error); - - @override - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `HomeState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// HomeState(...).copyWith(id: 12, name: "My name") - /// ```` - HomeState call({ - Object? data = const $CopyWithPlaceholder(), - Object? isLoading = const $CopyWithPlaceholder(), - Object? isPaginationLoading = const $CopyWithPlaceholder(), - Object? error = const $CopyWithPlaceholder(), - }) { - return HomeState( - data: data == const $CopyWithPlaceholder() - ? _value.data - // ignore: cast_nullable_to_non_nullable - : data as HomeData?, - isLoading: isLoading == const $CopyWithPlaceholder() || isLoading == null - ? _value.isLoading - // ignore: cast_nullable_to_non_nullable - : isLoading as bool, - isPaginationLoading: - isPaginationLoading == const $CopyWithPlaceholder() || isPaginationLoading == null - ? _value.isPaginationLoading - // ignore: cast_nullable_to_non_nullable - : isPaginationLoading as bool, - error: error == const $CopyWithPlaceholder() - ? _value.error - // ignore: cast_nullable_to_non_nullable - : error as String?, - ); - } -} - -extension $HomeStateCopyWith on HomeState { - /// Returns a callable class that can be used as follows: `instanceOfHomeState.copyWith(...)` or like so:`instanceOfHomeState.copyWith.fieldName(...)`. - // ignore: library_private_types_in_public_api - _$HomeStateCWProxy get copyWith => _$HomeStateCWProxyImpl(this); -} diff --git a/lib/presentation/home_page/card.dart b/lib/presentation/home_page/card.dart deleted file mode 100644 index 6915bef..0000000 --- a/lib/presentation/home_page/card.dart +++ /dev/null @@ -1,179 +0,0 @@ -part of 'home_page.dart'; - -typedef OnLikeCallback = void Function(String? id, String title, bool isLiked)?; - -class CardData { - final String text; - final String description; - final IconData icon; - final double score; - final String imageUrl; - final String? id; - - const CardData( - this.text, { - required this.description, - this.icon = Icons.add_call, - this.score = 0, - this.imageUrl = "https://i.pinimg.com/736x/5f/14/b3/5f14b3f14fcd157bc4dffa39085396cc.jpg", - this.id, - }); -} - -class _Card extends StatelessWidget { - final String text; - final String description; - final String? imageUrl; - final double score; - final OnLikeCallback onLike; - final VoidCallback? onTap; - final String? id; - final bool isLiked; - - const _Card( - this.text, { - required this.description, - required this.imageUrl, - required this.score, - this.onLike, - this.onTap, - this.id, - this.isLiked = false, - }); - - factory _Card.fromData( - CardData data, { - OnLikeCallback onLike, - VoidCallback? onTap, - bool isLiked = false, - }) => - _Card( - data.text, - description: data.description, - imageUrl: data.imageUrl, - score: data.score, - onLike: onLike, - onTap: onTap, - id: data.id, - isLiked: isLiked, - ); - - @override - Widget build(BuildContext context) { - List desc = description.split("\n"); - - return GestureDetector( - onTap: onTap, - child: Container( - margin: const EdgeInsets.all(10), - constraints: const BoxConstraints(minHeight: 140), - decoration: BoxDecoration( - color: Colors.white, - borderRadius: BorderRadius.circular(20), - border: Border.all(color: Colors.green, width: 2), - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(.4), - offset: const Offset(0, 5), - blurRadius: 6, - spreadRadius: 3), - ]), - child: IntrinsicHeight( - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Stack(children: [ - ClipRRect( - borderRadius: const BorderRadius.only( - bottomLeft: Radius.circular(18), - topLeft: Radius.circular(18), - ), - child: SizedBox( - height: 300, - width: 120, - child: Image.network( - imageUrl ?? '', - fit: BoxFit.cover, - errorBuilder: (_, __, ___) => const Placeholder(), - ), - ), - ), - Align( - alignment: Alignment.bottomLeft, - child: Container( - decoration: const BoxDecoration( - color: Colors.purple, - borderRadius: BorderRadius.only( - topRight: Radius.circular(20), bottomLeft: Radius.circular(18))), - padding: const EdgeInsets.fromLTRB(8, 2, 8, 2), - child: Text(generateStars(score), - style: - Theme.of(context).textTheme.bodyMedium?.copyWith(color: Colors.white)), - ), - ), - ]), - Expanded( - child: Padding( - padding: const EdgeInsets.all(10), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.start, - children: [ - Text( - text, - style: Theme.of(context).textTheme.headlineMedium, - ), - Text( - desc[0], - style: Theme.of(context).textTheme.bodySmall, - ) - ], - ), - ), - ), - Align( - alignment: Alignment.center, - child: Padding( - padding: const EdgeInsets.only( - left: 8, - right: 8, - bottom: 8, - ), - child: GestureDetector( - onTap: () => onLike?.call(id, text, isLiked), - child: AnimatedSwitcher( - duration: const Duration(milliseconds: 300), - child: isLiked - ? const Icon( - Icons.favorite, - color: Colors.red, - key: ValueKey(0), - ) - : const Icon( - Icons.favorite_border, - key: ValueKey(1), - ), - ), - )), - ) - ], - ), - ), - ), - ); - } -} - -String generateStars(double rating) { - rating = rating / 2; - int fullStars = rating.floor(); - bool hasHalfStar = (rating - fullStars) >= 0.5; - String stars = '★' * fullStars; - if (hasHalfStar) { - stars += '✪'; - } - int emptyStars = 5 - stars.length; - stars += '☆' * emptyStars; - return stars; -} diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart deleted file mode 100644 index 757cec2..0000000 --- a/lib/presentation/home_page/home_page.dart +++ /dev/null @@ -1,208 +0,0 @@ -import 'package:first_project/Components/extensions/context_x.dart'; -import 'package:first_project/data/repositories/anime_repository.dart'; -import 'package:first_project/data/repositories/mock_repository.dart'; -import 'package:first_project/domain/models/card.dart'; -import 'package:first_project/presentation/common/svg_objects.dart'; -import 'package:first_project/presentation/home_page/bloc/bloc.dart'; -import 'package:first_project/presentation/home_page/bloc/events.dart'; -import 'package:first_project/presentation/home_page/bloc/state.dart'; -import 'package:first_project/presentation/like_bloc/like_bloc.dart'; -import 'package:first_project/presentation/like_bloc/like_event.dart'; -import 'package:first_project/presentation/like_bloc/like_state.dart'; -import 'package:first_project/presentation/locale_bloc/locale_events.dart'; -import 'package:first_project/presentation/locale_bloc/locale_state.dart'; -import 'package:flutter/cupertino.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; - -import 'package:first_project/Components/utils/debounce.dart'; - -import '../locale_bloc/locale_bloc.dart'; - -part 'card.dart'; - -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key, required this.title}); - - final String title; - - @override - State createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State { - @override - void initState() { - WidgetsBinding.instance.addPostFrameCallback((_) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text( - 'Hello', - style: Theme.of(context).textTheme.bodyMedium, - ), - backgroundColor: Colors.purple, - duration: const Duration(seconds: 1), - )); - }); - super.initState(); - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Colors.purple, - title: Text(widget.title), - ), - body: const _Body(), - ); - } -} - -class _Body extends StatefulWidget { - const _Body({super.key}); - - @override - State<_Body> createState() => _BodyState(); -} - -class _BodyState extends State<_Body> { - final searchController = TextEditingController(); - final scrollController = ScrollController(); - - @override - void initState() { - SvgObjects.init(); - - WidgetsBinding.instance.addPostFrameCallback((_) { - context.read().add(const HomeLoadDataEvent()); - context.read().add(const LoadLikesEvent()); - }); - - scrollController.addListener(_onNextPageListener); - - super.initState(); - } - - void _onNextPageListener() { - if (scrollController.offset > scrollController.position.maxScrollExtent - 50) { - final bloc = context.read(); - if (!bloc.state.isPaginationLoading) { - bloc.add(HomeLoadDataEvent( - search: searchController.text, - nextPage: bloc.state.data?.nextPage, - )); - } - } - } - - @override - void dispose() { - searchController.dispose(); - scrollController.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return BlocBuilder( - builder: (context, state) => state.error != null - ? Text( - state.error ?? '', - style: Theme.of(context).textTheme.headlineSmall?.copyWith(color: Colors.red), - ) - : state.isLoading - ? const CircularProgressIndicator() - : Column(children: [ - Row(children: [ - Expanded( - flex: 4, - child: Padding( - padding: const EdgeInsets.all(8), - child: CupertinoSearchTextField( - controller: searchController, - placeholder: context.locale.search, - onChanged: (search) { - Debouce.run(() => - context.read().add(HomeLoadDataEvent(search: search))); - }, - ), - ), - ), - GestureDetector( - onTap: () => context.read().add(const ChangeLocaleEvent()), - child: SizedBox.square( - dimension: 50, - child: Padding( - padding: const EdgeInsets.only(right: 15), - child: BlocBuilder( - builder: (context, state) { - return state.currentLocale.languageCode == 'ru' - ? const SvgRu() - : const SvgGb(); - }, - ), - ), - )), - ]), - BlocBuilder(builder: (context, likeState) { - return Expanded( - child: RefreshIndicator( - onRefresh: _onRefresh, - child: ListView.builder( - controller: scrollController, - padding: EdgeInsets.zero, - itemCount: state.data?.data?.length ?? 0, - itemBuilder: (context, index) { - final data = state.data?.data?[index]; - return data != null - ? _Card.fromData( - data, - isLiked: likeState.likedIds?.contains(data.id) == true, - onLike: _onLike, - onTap: () => _navToDetails(context, data), - ) - : const SizedBox.shrink(); - }), - ), - ); - }), - BlocBuilder( - builder: (context, state) => state.isPaginationLoading - ? const CircularProgressIndicator() - : const SizedBox.shrink(), - ) - ])); - } - - void _navToDetails(BuildContext context, CardData data) { - Navigator.push( - context, - CupertinoPageRoute(builder: (context) => DetailsPage(data)), - ); - } - - void _onLike(String? id, String title, bool isLiked) { - if (id != null) { - context.read().add(ChangeLikeEvent(id)); - _showLiked(context, title, !isLiked); - } - } - - void _showLiked(BuildContext context, String title, bool isLiked) { - WidgetsBinding.instance.addPostFrameCallback((_) { - ScaffoldMessenger.of(context).showSnackBar(SnackBar( - content: Text( - '$title ${isLiked ? context.locale.liked : context.locale.disliked}', - style: Theme.of(context).textTheme.bodyMedium, - ), - backgroundColor: Colors.purple, - duration: const Duration(seconds: 1), - )); - }); - } - - Future _onRefresh() { - context.read().add(HomeLoadDataEvent(search: searchController.text)); - return Future.value(null); - } -} diff --git a/lib/presentation/like_bloc/like_bloc.dart b/lib/presentation/like_bloc/like_bloc.dart deleted file mode 100644 index 79101b8..0000000 --- a/lib/presentation/like_bloc/like_bloc.dart +++ /dev/null @@ -1,35 +0,0 @@ -import 'package:first_project/presentation/like_bloc/like_event.dart'; -import 'package:first_project/presentation/like_bloc/like_state.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:shared_preferences/shared_preferences.dart'; - -const String _likedPrefsKey = 'liked'; - -class LikeBloc extends Bloc { - LikeBloc() : super(const LikeState(likedIds: [])) { - on(_onChangeLike); - on(_onLoadLikes); - } - - Future _onLoadLikes(LoadLikesEvent event, Emitter emit) async { - final prefs = await SharedPreferences.getInstance(); - final data = prefs.getStringList(_likedPrefsKey); - - emit(state.copyWith(likedIds: data)); - } - - Future _onChangeLike(ChangeLikeEvent event, Emitter emit) async { - final updatedList = List.from(state.likedIds ?? []); - - if (updatedList.contains(event.id)) { - updatedList.remove(event.id); - } else { - updatedList.add(event.id); - } - - final prefs = await SharedPreferences.getInstance(); - prefs.setStringList(_likedPrefsKey, updatedList); - - emit(state.copyWith(likedIds: updatedList)); - } -} diff --git a/lib/presentation/like_bloc/like_event.dart b/lib/presentation/like_bloc/like_event.dart deleted file mode 100644 index d0326d8..0000000 --- a/lib/presentation/like_bloc/like_event.dart +++ /dev/null @@ -1,13 +0,0 @@ -abstract class LikeEvent { - const LikeEvent(); -} - -class LoadLikesEvent extends LikeEvent { - const LoadLikesEvent(); -} - -class ChangeLikeEvent extends LikeEvent { - final String id; - - const ChangeLikeEvent(this.id); -} diff --git a/lib/presentation/like_bloc/like_state.dart b/lib/presentation/like_bloc/like_state.dart deleted file mode 100644 index 22948d7..0000000 --- a/lib/presentation/like_bloc/like_state.dart +++ /dev/null @@ -1,14 +0,0 @@ -import 'package:equatable/equatable.dart'; -import 'package:copy_with_extension/copy_with_extension.dart'; - -part "like_state.g.dart"; - -@CopyWith() -class LikeState extends Equatable { - final List? likedIds; - - const LikeState({required this.likedIds}); - - @override - List get props => [likedIds]; -} diff --git a/lib/presentation/like_bloc/like_state.g.dart b/lib/presentation/like_bloc/like_state.g.dart deleted file mode 100644 index 0888cf2..0000000 --- a/lib/presentation/like_bloc/like_state.g.dart +++ /dev/null @@ -1,56 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'like_state.dart'; - -// ************************************************************************** -// CopyWithGenerator -// ************************************************************************** - -abstract class _$LikeStateCWProxy { - LikeState likedIds(List? likedIds); - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `LikeState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// LikeState(...).copyWith(id: 12, name: "My name") - /// ```` - LikeState call({ - List? likedIds, - }); -} - -/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfLikeState.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfLikeState.copyWith.fieldName(...)` -class _$LikeStateCWProxyImpl implements _$LikeStateCWProxy { - const _$LikeStateCWProxyImpl(this._value); - - final LikeState _value; - - @override - LikeState likedIds(List? likedIds) => this(likedIds: likedIds); - - @override - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `LikeState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// LikeState(...).copyWith(id: 12, name: "My name") - /// ```` - LikeState call({ - Object? likedIds = const $CopyWithPlaceholder(), - }) { - return LikeState( - likedIds: likedIds == const $CopyWithPlaceholder() - ? _value.likedIds - // ignore: cast_nullable_to_non_nullable - : likedIds as List?, - ); - } -} - -extension $LikeStateCopyWith on LikeState { - /// Returns a callable class that can be used as follows: `instanceOfLikeState.copyWith(...)` or like so:`instanceOfLikeState.copyWith.fieldName(...)`. - // ignore: library_private_types_in_public_api - _$LikeStateCWProxy get copyWith => _$LikeStateCWProxyImpl(this); -} diff --git a/lib/presentation/locale_bloc/locale_bloc.dart b/lib/presentation/locale_bloc/locale_bloc.dart deleted file mode 100644 index a39d2df..0000000 --- a/lib/presentation/locale_bloc/locale_bloc.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'dart:ui'; - -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:first_project/Components/locale/l10n/app_locale.dart'; -import 'package:first_project/presentation/locale_bloc/locale_events.dart'; -import 'package:first_project/presentation/locale_bloc/locale_state.dart'; - -class LocaleBloc extends Bloc { - LocaleBloc(Locale defaultLocale) : super(LocaleState(currentLocale: defaultLocale)) { - on(_onChangeLocale); - } - - Future _onChangeLocale(ChangeLocaleEvent event, Emitter emit) async { - final toChange = AppLocale.supportedLocales - .firstWhere((e) => e.languageCode != state.currentLocale.languageCode); - emit(state.copyWith(currentLocale: toChange)); - } -} diff --git a/lib/presentation/locale_bloc/locale_events.dart b/lib/presentation/locale_bloc/locale_events.dart deleted file mode 100644 index c08cd1b..0000000 --- a/lib/presentation/locale_bloc/locale_events.dart +++ /dev/null @@ -1,7 +0,0 @@ -abstract class LocaleEvent { - const LocaleEvent(); -} - -class ChangeLocaleEvent extends LocaleEvent { - const ChangeLocaleEvent(); -} diff --git a/lib/presentation/locale_bloc/locale_state.dart b/lib/presentation/locale_bloc/locale_state.dart deleted file mode 100644 index 84f261c..0000000 --- a/lib/presentation/locale_bloc/locale_state.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'dart:ui'; -import 'package:equatable/equatable.dart'; -import 'package:copy_with_extension/copy_with_extension.dart'; - -part 'locale_state.g.dart'; - -@CopyWith() -class LocaleState extends Equatable { - final Locale currentLocale; - - const LocaleState({required this.currentLocale}); - - @override - List get props => [currentLocale]; -} diff --git a/lib/presentation/locale_bloc/locale_state.g.dart b/lib/presentation/locale_bloc/locale_state.g.dart deleted file mode 100644 index 23ee063..0000000 --- a/lib/presentation/locale_bloc/locale_state.g.dart +++ /dev/null @@ -1,56 +0,0 @@ -// GENERATED CODE - DO NOT MODIFY BY HAND - -part of 'locale_state.dart'; - -// ************************************************************************** -// CopyWithGenerator -// ************************************************************************** - -abstract class _$LocaleStateCWProxy { - LocaleState currentLocale(Locale currentLocale); - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `LocaleState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// LocaleState(...).copyWith(id: 12, name: "My name") - /// ```` - LocaleState call({ - Locale? currentLocale, - }); -} - -/// Proxy class for `copyWith` functionality. This is a callable class and can be used as follows: `instanceOfLocaleState.copyWith(...)`. Additionally contains functions for specific fields e.g. `instanceOfLocaleState.copyWith.fieldName(...)` -class _$LocaleStateCWProxyImpl implements _$LocaleStateCWProxy { - const _$LocaleStateCWProxyImpl(this._value); - - final LocaleState _value; - - @override - LocaleState currentLocale(Locale currentLocale) => this(currentLocale: currentLocale); - - @override - - /// This function **does support** nullification of nullable fields. All `null` values passed to `non-nullable` fields will be ignored. You can also use `LocaleState(...).copyWith.fieldName(...)` to override fields one at a time with nullification support. - /// - /// Usage - /// ```dart - /// LocaleState(...).copyWith(id: 12, name: "My name") - /// ```` - LocaleState call({ - Object? currentLocale = const $CopyWithPlaceholder(), - }) { - return LocaleState( - currentLocale: currentLocale == const $CopyWithPlaceholder() || currentLocale == null - ? _value.currentLocale - // ignore: cast_nullable_to_non_nullable - : currentLocale as Locale, - ); - } -} - -extension $LocaleStateCopyWith on LocaleState { - /// Returns a callable class that can be used as follows: `instanceOfLocaleState.copyWith(...)` or like so:`instanceOfLocaleState.copyWith.fieldName(...)`. - // ignore: library_private_types_in_public_api - _$LocaleStateCWProxy get copyWith => _$LocaleStateCWProxyImpl(this); -} diff --git a/lib/widgets/hero_card.dart b/lib/widgets/hero_card.dart index 658ff43..50dbddd 100644 --- a/lib/widgets/hero_card.dart +++ b/lib/widgets/hero_card.dart @@ -46,7 +46,7 @@ class _HeroCardState extends State { _isLiked = !_isLiked; }); - // Отображение Snackbar с локализованным сообщением + // Отображение Snackbar ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(message),