diff --git a/Makefile b/Makefile index b7e451a..440356a 100644 --- a/Makefile +++ b/Makefile @@ -1,2 +1,17 @@ gen: - flutter pub run build_runner build --delete-conflicting-outputs \ No newline at end of file + dart pub run build_runner build --delete-conflicting-outputs + +icon: + dart pub run flutter_launcher_icons:main + +init_res: + dart pub global activate flutter_asset_generator + +format: + dart format . --line-length 100 + +res: + fgen --output lib/components/resourses.g.dart --no-watch --no-preview + +loc: + flutter gen-l10n \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml new file mode 100644 index 0000000..345888d --- /dev/null +++ b/android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png index db77bb4..10dd1e1 100644 Binary files a/android/app/src/main/res/mipmap-hdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png new file mode 100644 index 0000000..42abb71 Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..2bfdb0b Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..26d8e0c Binary files /dev/null and b/android/app/src/main/res/mipmap-hdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png index 17987b7..2e12b31 100644 Binary files a/android/app/src/main/res/mipmap-mdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png new file mode 100644 index 0000000..a493a5c Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..8ca9cc5 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..28a1d46 Binary files /dev/null and b/android/app/src/main/res/mipmap-mdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png index 09d4391..fed48f9 100644 Binary files a/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png new file mode 100644 index 0000000..83059ea Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..2f14565 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..4adf323 Binary files /dev/null and b/android/app/src/main/res/mipmap-xhdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png index d5f1c8d..e5362fe 100644 Binary files a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..bd79dd6 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..13f571d Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..9645828 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxhdpi/ic_launcher_monochrome.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png index 4d6372e..32047fe 100644 Binary files a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png new file mode 100644 index 0000000..fa7a66b Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png new file mode 100644 index 0000000..2fcccf9 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png differ diff --git a/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png new file mode 100644 index 0000000..5d1f477 Binary files /dev/null and b/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_monochrome.png 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/l10n.yaml b/l10n.yaml new file mode 100644 index 0000000..8bda731 --- /dev/null +++ b/l10n.yaml @@ -0,0 +1,6 @@ +arb-dir: l10n +template-arb-file: app_ru.arb +output-localization: app_locale.dart +output-dir: lib/components/locale/l10n +output-class: AppLocale +synthetic-package: false \ No newline at end of file diff --git a/l10n/app_en.arb b/l10n/app_en.arb new file mode 100644 index 0000000..f768f1b --- /dev/null +++ b/l10n/app_en.arb @@ -0,0 +1,12 @@ +{ + "@@locale": "en", + + "search": "Search", + "liked": "You liked", + "unliked": "Like removed from", + "errorOccured": "Error occured", + "noErrorMsg": "No message provided", + "retry": "Retry", + + "arbEnding": "t" +} \ No newline at end of file diff --git a/l10n/app_ru.arb b/l10n/app_ru.arb new file mode 100644 index 0000000..c06aac4 --- /dev/null +++ b/l10n/app_ru.arb @@ -0,0 +1,12 @@ +{ + "@@locale": "ru", + + "search": "Поиск", + "liked": "Вы лайкнули", + "unliked": "Лайк снят с", + "errorOccured": "Произошла ошибка", + "noErrorMsg": "Нет сообщения", + "retry": "Повторить", + + "arbEnding": "t" +} \ No newline at end of file diff --git a/lib/components/extensions/context_x.dart b/lib/components/extensions/context_x.dart new file mode 100644 index 0000000..79738ef --- /dev/null +++ b/lib/components/extensions/context_x.dart @@ -0,0 +1,6 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_project/components/locale/l10n/app_localizations.dart'; + +extension LocalContextX on BuildContext { + AppLocale get locale => AppLocale.of(this)!; +} diff --git a/lib/components/locale/l10n/app_localizations.dart b/lib/components/locale/l10n/app_localizations.dart new file mode 100644 index 0000000..a3dc4af --- /dev/null +++ b/lib/components/locale/l10n/app_localizations.dart @@ -0,0 +1,171 @@ +import 'dart:async'; + +import 'package:flutter/foundation.dart'; +import 'package:flutter/widgets.dart'; +import 'package:flutter_localizations/flutter_localizations.dart'; +import 'package:intl/intl.dart' as intl; + +import 'app_localizations_en.dart'; +import 'app_localizations_ru.dart'; + +// ignore_for_file: type=lint + +/// Callers can lookup localized strings with an instance of AppLocale +/// returned by `AppLocale.of(context)`. +/// +/// Applications need to include `AppLocale.delegate()` in their app's +/// `localizationDelegates` list, and the locales they support in the app's +/// `supportedLocales` list. For example: +/// +/// ```dart +/// import 'l10n/app_localizations.dart'; +/// +/// return MaterialApp( +/// localizationsDelegates: AppLocale.localizationsDelegates, +/// supportedLocales: AppLocale.supportedLocales, +/// home: MyApplicationHome(), +/// ); +/// ``` +/// +/// ## Update pubspec.yaml +/// +/// Please make sure to update your pubspec.yaml to include the following +/// packages: +/// +/// ```yaml +/// dependencies: +/// # Internationalization support. +/// flutter_localizations: +/// sdk: flutter +/// intl: any # Use the pinned version from flutter_localizations +/// +/// # Rest of dependencies +/// ``` +/// +/// ## iOS Applications +/// +/// iOS applications define key application metadata, including supported +/// locales, in an Info.plist file that is built into the application bundle. +/// To configure the locales supported by your app, you’ll need to edit this +/// file. +/// +/// First, open your project’s ios/Runner.xcworkspace Xcode workspace file. +/// Then, in the Project Navigator, open the Info.plist file under the Runner +/// project’s Runner folder. +/// +/// Next, select the Information Property List item, select Add Item from the +/// Editor menu, then select Localizations from the pop-up menu. +/// +/// Select and expand the newly-created Localizations item then, for each +/// locale your application supports, add a new item and select the locale +/// you wish to add from the pop-up menu in the Value field. This list should +/// be consistent with the languages listed in the AppLocale.supportedLocales +/// property. +abstract class AppLocale { + AppLocale(String locale) : localeName = intl.Intl.canonicalizedLocale(locale.toString()); + + final String localeName; + + static AppLocale? of(BuildContext context) { + return Localizations.of(context, AppLocale); + } + + static const LocalizationsDelegate delegate = _AppLocaleDelegate(); + + /// A list of this localizations delegate along with the default localizations + /// delegates. + /// + /// Returns a list of localizations delegates containing this delegate along with + /// GlobalMaterialLocalizations.delegate, GlobalCupertinoLocalizations.delegate, + /// and GlobalWidgetsLocalizations.delegate. + /// + /// 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 = >[ + delegate, + GlobalMaterialLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + ]; + + /// A list of this localizations delegate's supported locales. + static const List supportedLocales = [ + Locale('en'), + Locale('ru') + ]; + + /// No description provided for @search. + /// + /// In ru, this message translates to: + /// **'Поиск'** + String get search; + + /// No description provided for @liked. + /// + /// In ru, this message translates to: + /// **'Вы лайкнули'** + String get liked; + + /// No description provided for @unliked. + /// + /// In ru, this message translates to: + /// **'Лайк снят с'** + String get unliked; + + /// No description provided for @errorOccured. + /// + /// In ru, this message translates to: + /// **'Произошла ошибка'** + String get errorOccured; + + /// No description provided for @noErrorMsg. + /// + /// In ru, this message translates to: + /// **'Нет сообщения'** + String get noErrorMsg; + + /// No description provided for @retry. + /// + /// In ru, this message translates to: + /// **'Повторить'** + String get retry; + + /// No description provided for @arbEnding. + /// + /// In ru, this message translates to: + /// **'t'** + String get arbEnding; +} + +class _AppLocaleDelegate extends LocalizationsDelegate { + const _AppLocaleDelegate(); + + @override + Future load(Locale locale) { + return SynchronousFuture(lookupAppLocale(locale)); + } + + @override + bool isSupported(Locale locale) => ['en', 'ru'].contains(locale.languageCode); + + @override + bool shouldReload(_AppLocaleDelegate old) => false; +} + +AppLocale lookupAppLocale(Locale locale) { + + + // Lookup logic when only language code is specified. + switch (locale.languageCode) { + 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.' + ); +} diff --git a/lib/components/locale/l10n/app_localizations_en.dart b/lib/components/locale/l10n/app_localizations_en.dart new file mode 100644 index 0000000..6f2d449 --- /dev/null +++ b/lib/components/locale/l10n/app_localizations_en.dart @@ -0,0 +1,29 @@ +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for English (`en`). +class AppLocaleEn extends AppLocale { + AppLocaleEn([String locale = 'en']) : super(locale); + + @override + String get search => 'Search'; + + @override + String get liked => 'You liked'; + + @override + String get unliked => 'Like removed from'; + + @override + String get errorOccured => 'Error occured'; + + @override + String get noErrorMsg => 'No message provided'; + + @override + String get retry => 'Retry'; + + @override + String get arbEnding => 't'; +} diff --git a/lib/components/locale/l10n/app_localizations_ru.dart b/lib/components/locale/l10n/app_localizations_ru.dart new file mode 100644 index 0000000..e148138 --- /dev/null +++ b/lib/components/locale/l10n/app_localizations_ru.dart @@ -0,0 +1,29 @@ +import 'app_localizations.dart'; + +// ignore_for_file: type=lint + +/// The translations for Russian (`ru`). +class AppLocaleRu extends AppLocale { + AppLocaleRu([String locale = 'ru']) : super(locale); + + @override + String get search => 'Поиск'; + + @override + String get liked => 'Вы лайкнули'; + + @override + String get unliked => 'Лайк снят с'; + + @override + String get errorOccured => 'Произошла ошибка'; + + @override + String get noErrorMsg => 'Нет сообщения'; + + @override + String get retry => 'Повторить'; + + @override + String get arbEnding => 't'; +} diff --git a/lib/components/resourses.g.dart b/lib/components/resourses.g.dart new file mode 100644 index 0000000..915a8d9 --- /dev/null +++ b/lib/components/resourses.g.dart @@ -0,0 +1,10 @@ +/// 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._(); + + static const String ASSETS_SVG_RU_SVG = 'assets/svg/ru.svg'; + + static const String ASSETS_SVG_US_SVG = 'assets/svg/us.svg'; +} diff --git a/lib/components/utils/debounce.dart b/lib/components/utils/debounce.dart index dda6999..9642c10 100644 --- a/lib/components/utils/debounce.dart +++ b/lib/components/utils/debounce.dart @@ -10,8 +10,7 @@ class Debounce { static Timer? _timer; - static void run(VoidCallback action, - {Duration delay = const Duration(milliseconds: 500)}) { + static void run(VoidCallback action, {Duration delay = const Duration(milliseconds: 500)}) { _timer?.cancel(); _timer = Timer(delay, action); } diff --git a/lib/data/dtos/animes_dto.dart b/lib/data/dtos/animes_dto.dart index f2a6736..64fd5c9 100644 --- a/lib/data/dtos/animes_dto.dart +++ b/lib/data/dtos/animes_dto.dart @@ -8,8 +8,7 @@ class AnimesDto { final PaginationDto? pagination; const AnimesDto({this.data, this.pagination}); - factory AnimesDto.fromJson(Map json) => - _$AnimesDtoFromJson(json); + factory AnimesDto.fromJson(Map json) => _$AnimesDtoFromJson(json); } @JsonSerializable(createToJson: false) @@ -23,8 +22,7 @@ class PaginationDto { const PaginationDto({this.currentPage, this.hasNextPage, this.lastPage}); - factory PaginationDto.fromJson(Map json) => - _$PaginationDtoFromJson(json); + factory PaginationDto.fromJson(Map json) => _$PaginationDtoFromJson(json); } @JsonSerializable(createToJson: false) @@ -36,16 +34,9 @@ class AnimeDto { final String? rating; final ImagesDto? images; - const AnimeDto( - {this.title, - this.rating, - this.synopsis, - this.type, - this.year, - this.images}); + const AnimeDto({this.title, this.rating, this.synopsis, this.type, this.year, this.images}); - factory AnimeDto.fromJson(Map json) => - _$AnimeDtoFromJson(json); + factory AnimeDto.fromJson(Map json) => _$AnimeDtoFromJson(json); } @JsonSerializable(createToJson: false) @@ -54,8 +45,7 @@ class ImagesDto { const ImagesDto({this.jpg}); - factory ImagesDto.fromJson(Map json) => - _$ImagesDtoFromJson(json); + factory ImagesDto.fromJson(Map json) => _$ImagesDtoFromJson(json); } @JsonSerializable(createToJson: false) @@ -65,6 +55,5 @@ class ImageDto { const ImageDto({this.imageUrl}); - factory ImageDto.fromJson(Map json) => - _$ImageDtoFromJson(json); + factory ImageDto.fromJson(Map json) => _$ImageDtoFromJson(json); } diff --git a/lib/data/mappers/animes_mapper.dart b/lib/data/mappers/animes_mapper.dart index ef14b8f..d33824c 100644 --- a/lib/data/mappers/animes_mapper.dart +++ b/lib/data/mappers/animes_mapper.dart @@ -6,9 +6,7 @@ import '../dtos/animes_dto.dart'; extension AnimesMapper on AnimesDto { HomeData toDomain() => HomeData( data: data?.map((dto) => dto.toDomain()).toList(), - nextPage: (pagination?.hasNextPage ?? false) - ? ((pagination?.currentPage ?? 0) + 1) - : null); + nextPage: (pagination?.hasNextPage ?? false) ? ((pagination?.currentPage ?? 0) + 1) : null); } extension AnimeMapper on AnimeDto { diff --git a/lib/data/repositories/anime_repository.dart b/lib/data/repositories/anime_repository.dart index 9feb652..6171805 100644 --- a/lib/data/repositories/anime_repository.dart +++ b/lib/data/repositories/anime_repository.dart @@ -15,22 +15,14 @@ class AnimeRepository extends ApiInterface { @override Future loadData( - {OnErrorCallback onError, - String? q, - int page = 1, - int pageSize = 25}) async { + {OnErrorCallback onError, String? q, int page = 1, int pageSize = 25}) async { try { const String url = "$_baseUrl/v4/anime?sfw"; - final Response response = await _dio - .get>(url, queryParameters: { - 'q': q, - 'page': page, - 'limit': !(pageSize > 25) ? pageSize : 25 - }); + final Response response = await _dio.get>(url, + queryParameters: {'q': q, 'page': page, 'limit': !(pageSize > 25) ? pageSize : 25}); - final AnimesDto dto = - AnimesDto.fromJson(response.data as Map); + final AnimesDto dto = AnimesDto.fromJson(response.data as Map); final HomeData data = dto.toDomain(); diff --git a/lib/domain/models/card.dart b/lib/domain/models/card.dart index c059b4d..1642f55 100644 --- a/lib/domain/models/card.dart +++ b/lib/domain/models/card.dart @@ -5,8 +5,5 @@ class CardData { final String cuttedDescr; const CardData( - {required this.name, - required this.imageUrl, - required this.descr, - required this.cuttedDescr}); + {required this.name, required this.imageUrl, required this.descr, required this.cuttedDescr}); } diff --git a/lib/main.dart b/lib/main.dart index 935c562..ea6cd0a 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_project/components/locale/l10n/app_localizations.dart'; import 'package:flutter_project/data/repositories/anime_repository.dart'; import 'package:flutter_project/views/home_page/bloc/bloc.dart'; import 'package:flutter_project/views/home_page/home_page.dart'; @@ -21,6 +22,8 @@ class MyApp extends StatelessWidget { create: (context) => HomeBloc(context.read()), child: MaterialApp( title: 'Flutter Demo', + localizationsDelegates: AppLocale.localizationsDelegates, + supportedLocales: AppLocale.supportedLocales, theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.lightGreen), useMaterial3: true, diff --git a/lib/views/common/svg_objects.dart b/lib/views/common/svg_objects.dart new file mode 100644 index 0000000..1032ded --- /dev/null +++ b/lib/views/common/svg_objects.dart @@ -0,0 +1,32 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter_svg/flutter_svg.dart'; + +import '../../components/resourses.g.dart'; + +abstract class SvgObjects { + static void init() { + final pics = [R.ASSETS_SVG_RU_SVG, R.ASSETS_SVG_US_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 SvgUs extends StatelessWidget { + const SvgUs({super.key}); + + @override + Widget build(BuildContext context) { + return SvgPicture.asset(R.ASSETS_SVG_US_SVG); + } +} diff --git a/lib/views/home_page/bloc/bloc.dart b/lib/views/home_page/bloc/bloc.dart index c5dab10..bcc60c2 100644 --- a/lib/views/home_page/bloc/bloc.dart +++ b/lib/views/home_page/bloc/bloc.dart @@ -21,8 +21,7 @@ class HomeBloc extends Bloc { } } - Future _onLoadData( - HomeLoadDataEvent event, Emitter emit) async { + Future _onLoadData(HomeLoadDataEvent event, Emitter emit) async { if (event.hasError != null && event.hasError == true) { emit(state.copyWith(error: null)); } @@ -35,17 +34,13 @@ class HomeBloc extends Bloc { String? error; - final data = await repo.loadData( - q: event.search, page: event.nextPage ?? 1, onError: (e) => error = e); + 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)); + emit(state.copyWith(data: data, isLoading: false, isPaginationLoading: false, error: error)); } } diff --git a/lib/views/home_page/bloc/state.dart b/lib/views/home_page/bloc/state.dart index 43d801d..091b701 100644 --- a/lib/views/home_page/bloc/state.dart +++ b/lib/views/home_page/bloc/state.dart @@ -20,6 +20,5 @@ class HomeState extends Equatable { this.error}); @override - List get props => - [data, isLoading, isPaginationLoading, isButtonToTopShown, error]; + List get props => [data, isLoading, isPaginationLoading, isButtonToTopShown, error]; } diff --git a/lib/views/home_page/card.dart b/lib/views/home_page/card.dart index 4e4c3b1..6b7b43d 100644 --- a/lib/views/home_page/card.dart +++ b/lib/views/home_page/card.dart @@ -10,15 +10,9 @@ class _Card extends StatefulWidget { final VoidCallback? onTap; const _Card( - {required this.name, - required this.imageUrl, - this.onLike, - this.onTap, - required this.descr}); + {required this.name, required this.imageUrl, this.onLike, this.onTap, required this.descr}); - factory _Card.withData(CardData d, - {onLikeCallback onLike, VoidCallback? onTap}) => - _Card( + factory _Card.withData(CardData d, {onLikeCallback onLike, VoidCallback? onTap}) => _Card( name: d.name, imageUrl: d.imageUrl, onLike: onLike, @@ -57,8 +51,7 @@ class _CardState extends State<_Card> { children: [ ClipRRect( borderRadius: BorderRadius.only( - topLeft: Radius.circular(20), - bottomLeft: Radius.circular(20)), + topLeft: Radius.circular(20), bottomLeft: Radius.circular(20)), child: ConstrainedBox( constraints: BoxConstraints(minHeight: 200), child: SizedBox( diff --git a/lib/views/home_page/home_page.dart b/lib/views/home_page/home_page.dart index cb71721..bf32429 100644 --- a/lib/views/home_page/home_page.dart +++ b/lib/views/home_page/home_page.dart @@ -1,8 +1,10 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_project/components/extensions/context_x.dart'; import 'package:flutter_project/components/utils/debounce.dart'; import 'package:flutter_project/domain/models/card.dart'; +import 'package:flutter_project/views/common/svg_objects.dart'; import 'package:flutter_project/views/details_page/details_page.dart'; import 'package:flutter_project/views/home_page/bloc/events.dart'; import 'package:flutter_project/views/home_page/bloc/state.dart'; @@ -49,6 +51,8 @@ class _BodyState extends State { @override void initState() { + SvgObjects.init(); + WidgetsBinding.instance.addPostFrameCallback( (_) => context.read().add(const HomeLoadDataEvent())); scrollController.addListener(_viewListScrollListener); @@ -72,6 +76,7 @@ class _BodyState extends State { padding: EdgeInsets.only(left: 16, right: 16, top: 10, bottom: 10), child: Center( child: CupertinoSearchTextField( + placeholder: context.locale.search, controller: searchController, onChanged: (search) { Debounce.run(() => context @@ -133,8 +138,8 @@ class _BodyState extends State { showCupertinoDialog( context: context, builder: (_) => CupertinoAlertDialog( - title: Text("Error occurred"), - content: Text(state.error ?? 'No message provided'), + title: Text(context.locale.errorOccured), + content: Text(state.error ?? context.locale.noErrorMsg), actions: [ CupertinoDialogAction( onPressed: () { @@ -143,7 +148,7 @@ class _BodyState extends State { .read() .add(HomeLoadDataEvent(hasError: true)); }, - child: Text("Retry")) + child: Text(context.locale.retry)) ], )); } @@ -191,7 +196,7 @@ class _BodyState extends State { WidgetsBinding.instance.addPostFrameCallback((_) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( - isLiked ? "You liked $title" : "Like removed from $title", + "${isLiked ? context.locale.liked : context.locale.unliked} $title", style: Theme.of(context).textTheme.bodyLarge, ), backgroundColor: Theme.of(context).colorScheme.inversePrimary, diff --git a/pubspec.lock b/pubspec.lock index 6224289..8a5a5c9 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -22,6 +22,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.7.0" + archive: + dependency: transitive + description: + name: archive + sha256: cb6a278ef2dbb298455e1a713bda08524a175630ec643a242c399c932a0a1f7d + url: "https://pub.dev" + source: hosted + version: "3.6.1" args: dependency: transitive description: @@ -134,6 +142,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.3" + cli_util: + dependency: transitive + description: + name: cli_util + sha256: c05b7406fdabc7a49a3929d4af76bcaccbbffcbcdcf185b082e1ae07da323d19 + url: "https://pub.dev" + source: hosted + version: "0.4.1" clock: dependency: transitive description: @@ -238,6 +254,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.1" + ffi: + dependency: transitive + description: + name: ffi + sha256: "16ed7b077ef01ad6170a3d0c57caa4a112a38d7a2ed5602e0aca9ca6f3d98da6" + url: "https://pub.dev" + source: hosted + version: "2.1.3" file: dependency: transitive description: @@ -267,6 +291,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.6" + flutter_launcher_icons: + dependency: "direct dev" + description: + name: flutter_launcher_icons + sha256: "619817c4b65b322b5104b6bb6dfe6cda62d9729bd7ad4303ecc8b4e690a67a77" + url: "https://pub.dev" + source: hosted + version: "0.14.1" flutter_lints: dependency: "direct dev" description: @@ -275,11 +307,29 @@ packages: url: "https://pub.dev" source: hosted version: "5.0.0" + flutter_localizations: + dependency: "direct dev" + description: flutter + source: sdk + version: "0.0.0" + flutter_svg: + dependency: "direct dev" + description: + name: flutter_svg + sha256: "7b4ca6cf3304575fe9c8ec64813c8d02ee41d2afe60bcfe0678bcb5375d596a2" + url: "https://pub.dev" + source: hosted + version: "2.0.10+1" flutter_test: dependency: "direct dev" description: flutter source: sdk version: "0.0.0" + flutter_web_plugins: + dependency: transitive + description: flutter + source: sdk + version: "0.0.0" frontend_server_client: dependency: transitive description: @@ -304,6 +354,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.3.2" + http: + dependency: transitive + description: + name: http + sha256: b9c29a161230ee03d3ccf545097fccd9b87a5264228c5d348202e0f0c28f9010 + url: "https://pub.dev" + source: hosted + version: "1.2.2" http_multi_server: dependency: transitive description: @@ -320,6 +378,22 @@ packages: url: "https://pub.dev" source: hosted version: "4.0.2" + image: + dependency: transitive + description: + name: image + sha256: "2237616a36c0d69aef7549ab439b833fb7f9fb9fc861af2cc9ac3eedddd69ca8" + url: "https://pub.dev" + source: hosted + version: "4.2.0" + intl: + dependency: "direct dev" + description: + name: intl + sha256: d6f56758b7d3014a48af9701c085700aac781a92a87a62b1333b46d8879661cf + url: "https://pub.dev" + source: hosted + version: "0.19.0" io: dependency: transitive description: @@ -456,6 +530,62 @@ packages: url: "https://pub.dev" source: hosted version: "1.9.0" + path_parsing: + dependency: transitive + description: + name: path_parsing + sha256: e3e67b1629e6f7e8100b367d3db6ba6af4b1f0bb80f64db18ef1fbabd2fa9ccf + url: "https://pub.dev" + source: hosted + version: "1.0.1" + path_provider_linux: + dependency: transitive + description: + name: path_provider_linux + sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 + url: "https://pub.dev" + source: hosted + version: "2.2.1" + path_provider_platform_interface: + dependency: transitive + description: + name: path_provider_platform_interface + sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" + url: "https://pub.dev" + source: hosted + version: "2.1.2" + path_provider_windows: + dependency: transitive + description: + name: path_provider_windows + sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 + url: "https://pub.dev" + source: hosted + version: "2.3.0" + petitparser: + dependency: transitive + description: + name: petitparser + sha256: c15605cd28af66339f8eb6fbe0e541bfe2d1b72d5825efc6598f3e0a31b9ad27 + url: "https://pub.dev" + source: hosted + version: "6.0.2" + platform: + dependency: transitive + description: + name: platform + sha256: "9b71283fc13df574056616011fb138fd3b793ea47cc509c189a6c3fa5f8a1a65" + url: "https://pub.dev" + source: hosted + version: "3.1.5" + plugin_platform_interface: + dependency: transitive + description: + name: plugin_platform_interface + sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" + url: "https://pub.dev" + source: hosted + version: "2.1.8" pool: dependency: transitive description: @@ -496,6 +626,62 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.0" + shared_preferences: + dependency: "direct dev" + description: + name: shared_preferences + sha256: "746e5369a43170c25816cc472ee016d3a66bc13fcf430c0bc41ad7b4b2922051" + url: "https://pub.dev" + source: hosted + version: "2.3.2" + shared_preferences_android: + dependency: transitive + description: + name: shared_preferences_android + sha256: "3b9febd815c9ca29c9e3520d50ec32f49157711e143b7a4ca039eb87e8ade5ab" + url: "https://pub.dev" + source: hosted + version: "2.3.3" + shared_preferences_foundation: + dependency: transitive + description: + name: shared_preferences_foundation + sha256: "07e050c7cd39bad516f8d64c455f04508d09df104be326d8c02551590a0d513d" + url: "https://pub.dev" + source: hosted + version: "2.5.3" + shared_preferences_linux: + dependency: transitive + description: + name: shared_preferences_linux + sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_platform_interface: + dependency: transitive + description: + name: shared_preferences_platform_interface + sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" + url: "https://pub.dev" + source: hosted + version: "2.4.1" + shared_preferences_web: + dependency: transitive + description: + name: shared_preferences_web + sha256: d2ca4132d3946fec2184261726b355836a82c33d7d5b67af32692aff18a4684e + url: "https://pub.dev" + source: hosted + version: "2.4.2" + shared_preferences_windows: + dependency: transitive + description: + name: shared_preferences_windows + sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" + url: "https://pub.dev" + source: hosted + version: "2.4.1" shelf: dependency: transitive description: @@ -605,6 +791,30 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + vector_graphics: + dependency: transitive + description: + name: vector_graphics + sha256: "32c3c684e02f9bc0afb0ae0aa653337a2fe022e8ab064bcd7ffda27a74e288e3" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_codec: + dependency: transitive + description: + name: vector_graphics_codec + sha256: c86987475f162fadff579e7320c7ddda04cd2fdeffbe1129227a85d9ac9e03da + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" + vector_graphics_compiler: + dependency: transitive + description: + name: vector_graphics_compiler + sha256: "12faff3f73b1741a36ca7e31b292ddeb629af819ca9efe9953b70bd63fc8cd81" + url: "https://pub.dev" + source: hosted + version: "1.1.11+1" vector_math: dependency: transitive description: @@ -653,6 +863,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + xdg_directories: + dependency: transitive + description: + name: xdg_directories + sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" + url: "https://pub.dev" + source: hosted + version: "1.1.0" + xml: + dependency: transitive + description: + name: xml + sha256: b015a8ad1c488f66851d762d3090a21c600e479dc75e68328c52774040cf9226 + url: "https://pub.dev" + source: hosted + version: "6.5.0" yaml: dependency: transitive description: @@ -663,4 +889,4 @@ packages: version: "3.1.2" sdks: dart: ">=3.5.2 <4.0.0" - flutter: ">=3.18.0-18.0.pre.54" + flutter: ">=3.24.0" diff --git a/pubspec.yaml b/pubspec.yaml index 9efdab2..5fb8d71 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -21,6 +21,7 @@ version: 1.0.0+1 environment: sdk: ^3.5.2 + # Dependencies specify other packages that your package needs in order to work. # To automatically upgrade your package dependencies to the latest versions # consider running `flutter pub upgrade --major-versions`. Alternatively, @@ -52,6 +53,15 @@ dev_dependencies: # rules and activating additional ones. flutter_lints: ^5.0.0 + flutter_launcher_icons: ^0.14.1 + flutter_svg: ^2.0.10+1 + + flutter_localizations: + sdk: flutter + intl: ^0.19.0 + + + shared_preferences: ^2.3.2 copy_with_extension_gen: ^5.0.4 copy_with_extension: ^5.0.4 json_serializable: ^6.7.1 @@ -60,8 +70,16 @@ dev_dependencies: # For information on the generic Dart part of this file, see the # following page: https://dart.dev/tools/pub/pubspec +flutter_icons: + android: "ic_launcher" + image_path: "assets/icon.png" + min_sdk_android: 25 + # The following section is specific to Flutter packages. flutter: + generate: true + assets: + - assets/svg/ # The following line ensures that the Material Icons font is # included with your application, so that you can use the icons in