diff --git a/assets/icon.jpg b/assets/icon.jpg new file mode 100644 index 0000000..9d71906 Binary files /dev/null and b/assets/icon.jpg differ diff --git a/assets/svg/ru.svg b/assets/svg/ru.svg new file mode 100644 index 0000000..ae12982 --- /dev/null +++ b/assets/svg/ru.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/assets/svg/us.svg b/assets/svg/us.svg new file mode 100644 index 0000000..f5a7a01 --- /dev/null +++ b/assets/svg/us.svg @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/lib/components/locale/l10n/app_locale.dart b/lib/components/locale/l10n/app_locale.dart index 5f646e6..1c601cd 100644 --- a/lib/components/locale/l10n/app_locale.dart +++ b/lib/components/locale/l10n/app_locale.dart @@ -8,6 +8,8 @@ import 'package:intl/intl.dart' as intl; import 'app_locale_en.dart'; import 'app_locale_ru.dart'; +// ignore_for_file: type=lint + /// Callers can lookup localized strings with an instance of AppLocale /// returned by `AppLocale.of(context)`. /// @@ -80,8 +82,7 @@ abstract class AppLocale { /// 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 /// of delegates is preferred or required. - static const List> localizationsDelegates = - >[ + static const List> localizationsDelegates = >[ delegate, GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, @@ -89,7 +90,10 @@ abstract class AppLocale { ]; /// A list of this localizations delegate's supported locales. - static const List supportedLocales = [Locale('en'), Locale('ru')]; + static const List supportedLocales = [ + Locale('en'), + Locale('ru') + ]; /// No description provided for @search. /// @@ -107,7 +111,7 @@ abstract class AppLocale { /// /// In ru, this message translates to: /// **'разонравился'** - String get unliked; + String get disliked; } class _AppLocaleDelegate extends LocalizationsDelegate { @@ -126,17 +130,18 @@ class _AppLocaleDelegate extends LocalizationsDelegate { } AppLocale lookupAppLocale(Locale locale) { + + // Lookup logic when only language code is specified. switch (locale.languageCode) { - case 'en': - return AppLocaleEn(); - case 'ru': - return AppLocaleRu(); + case 'en': return AppLocaleEn(); + case 'ru': return AppLocaleRu(); } throw FlutterError( - 'AppLocale.delegate failed to load unsupported locale "$locale". This is likely ' - 'an issue with the localizations generation tool. Please file an issue ' - 'on GitHub with a reproducible sample app and the gen-l10n configuration ' - 'that was used.'); + 'AppLocale.delegate failed to load unsupported locale "$locale". This is likely ' + 'an issue with the localizations generation tool. Please file an issue ' + 'on GitHub with a reproducible sample app and the gen-l10n configuration ' + 'that was used.' + ); } diff --git a/lib/components/locale/l10n/app_locale_en.dart b/lib/components/locale/l10n/app_locale_en.dart index 90b81dd..e0f4211 100644 --- a/lib/components/locale/l10n/app_locale_en.dart +++ b/lib/components/locale/l10n/app_locale_en.dart @@ -1,5 +1,7 @@ import 'app_locale.dart'; +// ignore_for_file: type=lint + /// The translations for English (`en`). class AppLocaleEn extends AppLocale { AppLocaleEn([String locale = 'en']) : super(locale); @@ -11,6 +13,5 @@ class AppLocaleEn extends AppLocale { String get liked => 'liked!'; @override - String get unliked => 'disliked'; - + String get disliked => 'разонравился'; } diff --git a/lib/components/locale/l10n/app_locale_ru.dart b/lib/components/locale/l10n/app_locale_ru.dart index 4d78b7f..e1485c0 100644 --- a/lib/components/locale/l10n/app_locale_ru.dart +++ b/lib/components/locale/l10n/app_locale_ru.dart @@ -1,5 +1,7 @@ import 'app_locale.dart'; +// ignore_for_file: type=lint + /// The translations for Russian (`ru`). class AppLocaleRu extends AppLocale { AppLocaleRu([String locale = 'ru']) : super(locale); @@ -11,5 +13,5 @@ class AppLocaleRu extends AppLocale { String get liked => 'понравился!'; @override - String get unliked => 'разонравился'; + String get disliked => 'разонравился'; } diff --git a/lib/main.dart b/lib/main.dart index f4b01ab..5075b12 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,9 +1,16 @@ +import 'dart:io'; + import 'package:flutter/material.dart'; import 'package:flutter_app/data/repositories/manga_repository.dart'; import 'package:flutter_app/presentation/home_page/bloc/bloc.dart'; import 'package:flutter_app/presentation/home_page/home_page.dart'; +import 'package:flutter_app/presentation/like_bloc/like_bloc.dart'; +import 'package:flutter_app/presentation/locale_bloc/locale_bloc.dart'; +import 'package:flutter_app/presentation/locale_bloc/locale_state.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'components/locale/l10n/app_locale.dart'; + void main() { runApp(const MyApp()); } @@ -14,27 +21,36 @@ class MyApp extends StatelessWidget { // This widget is the root of your application. @override Widget build(BuildContext context) { - return MaterialApp( - title: 'Flutter Demo', - theme: ThemeData( - colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple), - useMaterial3: true, - ), - home: RepositoryProvider( - lazy: true, - create: (_) => MangaRepository(), - child: BlocProvider( - lazy: false, - create: (context) => HomeBloc(context.read()), - child: const HomePage(), - ), - ) - ); + return BlocProvider( + lazy: false, + create: (context) => LocaleBloc(Locale(Platform.localeName)), + child: BlocBuilder( + builder: (context, state) { + return MaterialApp( + title: 'Flutter Demo', + locale: state.currentLocale, + localizationsDelegates: AppLocale.localizationsDelegates, + supportedLocales: AppLocale.supportedLocales, + debugShowCheckedModeBanner: false, + theme: ThemeData( + colorScheme: + ColorScheme.fromSeed(seedColor: Colors.deepPurple), + useMaterial3: true, + ), + home: RepositoryProvider( + lazy: true, + create: (_) => MangaRepository(), + child: BlocProvider( + lazy: false, + create: (context) => LikeBloc(), + child: BlocProvider( + lazy: false, + create: (context) => + HomeBloc(context.read()), + child: const HomePage(), + ), + ))); + }, + )); } } - - - - - - diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart index d235b9f..9272309 100644 --- a/lib/presentation/home_page/home_page.dart +++ b/lib/presentation/home_page/home_page.dart @@ -2,7 +2,6 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_app/components/utils/debounce.dart'; import 'package:flutter_app/data/repositories/manga_repository.dart'; -import 'package:flutter_app/data/repositories/mock_repository.dart'; import 'package:flutter_app/presentation/details_page/details_page.dart'; import 'package:flutter_app/presentation/home_page/bloc/bloc.dart'; import 'package:flutter_app/presentation/home_page/bloc/events.dart'; @@ -10,6 +9,13 @@ import 'package:flutter_app/presentation/home_page/bloc/state.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import '../../domain/models/carddata.dart'; +import '../common/svg_objects.dart'; +import '../like_bloc/like_bloc.dart'; +import '../like_bloc/like_event.dart'; +import '../like_bloc/like_state.dart'; +import '../locale_bloc/locale_bloc.dart'; +import '../locale_bloc/locale_events.dart'; +import '../locale_bloc/locale_state.dart'; part 'card.dart'; @@ -45,8 +51,11 @@ class _BodyState extends State { @override void initState() { + SvgObjects.init(); + WidgetsBinding.instance.addPostFrameCallback((_) { context.read().add(const HomeLoadDataEvent()); + context.read().add(const LoadLikesEvent()); }); scrollController.addListener(_onNextPageListener); @@ -74,7 +83,14 @@ class _BodyState extends State { final MangaRepository repo = MangaRepository(); var data = MangaRepository().loadData(); - void _showSnackbar(BuildContext context, String title, bool isLiked) { + void _onLike(String? id, String title, bool isLiked) { + if (id != null) { + context.read().add(ChangeLikeEvent(id)); + _showSnackBar(context, title, !isLiked); + } + } + + void _showSnackBar(BuildContext context, String title, bool isLiked) { WidgetsBinding.instance.addPostFrameCallback((_) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( @@ -114,31 +130,47 @@ class _BodyState extends State { .read() .add(HomeLoadDataEvent(search: search))); })), + GestureDetector( + onTap: () => + context.read().add(const ChangeLocaleEvent()), + child: SizedBox.square( + dimension: 50, + child: Padding( + padding: const EdgeInsets.only(right: 12), + child: BlocBuilder( + builder: (context, state) { + return state.currentLocale.languageCode == 'ru' + ? const SvgRu() + : const SvgUk(); + }, + ), + ), + ), + ), BlocBuilder( builder: (context, state) => state.isLoading ? CircularProgressIndicator() - : 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, - onLike: (title, isLiked) => - _showSnackbar( - context, title, isLiked), - onTap: () => - _navToDetails(context, data), - ) - : const SizedBox.shrink(); - }), - ), - )), + : BlocBuilder( + builder: (context, likeState) => 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, + onLike: _onLike, + onTap: () => + _navToDetails(context, data), + ) + : const SizedBox.shrink(); + }), + ), + ))), BlocBuilder( builder: (context, state) => state.isPaginationLoading ? const CircularProgressIndicator() diff --git a/pubspec.yaml b/pubspec.yaml index 90d469f..bab3e71 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -47,7 +47,7 @@ dev_dependencies: flutter_icons: android: "ic_launcher" ios: true - image_path: "assets/launcher.jpeg" + image_path: "assets/icon.jpeg" min_sdk_android: 21 flutter: