lab7 done :)

This commit is contained in:
Алексей Тихоненков 2024-12-19 02:27:13 +04:00
parent 2d49ce9f8c
commit 5c9ef6476c
15 changed files with 172 additions and 76 deletions

View File

@ -1,13 +1,13 @@
{ {
"@@locale": "en", "@@locale": "en",
"title": "Quotes" "title": "Quotes",
"search_word": "Search by word", "search_word": "Search by word",
"search_author": "Search by author", "search_author": "Search by author",
"liked": "Like :)", "liked": "Like :)",
"disliked": "Dislike :(", "disliked": "Dislike :(",
"error": "Error :C" "error": "Error :C",
"details": "Details of quote" "details": "Details of quote",
"arbEnding": "" "arbEnding": ""
} }

View File

@ -1,9 +1,13 @@
{ {
"@@locale": "ru", "@@locale": "ru",
"search": "Поиск", "title": "Цитаты",
"liked": "Круто :)", "search_word": "Поиск по слову",
"disliked": "Не круто :с", "search_author": "Поиск по автору",
"liked": "Лайк :)",
"disliked": "Дизлайк :(",
"error": "Ошибка :C",
"details": "Детали цитаты",
"arbEnding": "" "arbEnding": ""
} }

View File

@ -95,24 +95,48 @@ abstract class AppLocale {
Locale('ru') Locale('ru')
]; ];
/// No description provided for @search. /// No description provided for @title.
/// ///
/// In ru, this message translates to: /// In ru, this message translates to:
/// **'Поиск'** /// **'Цитаты'**
String get search; String get title;
/// No description provided for @search_word.
///
/// In ru, this message translates to:
/// **'Поиск по слову'**
String get search_word;
/// No description provided for @search_author.
///
/// In ru, this message translates to:
/// **'Поиск по автору'**
String get search_author;
/// No description provided for @liked. /// No description provided for @liked.
/// ///
/// In ru, this message translates to: /// In ru, this message translates to:
/// **'Круто :)'** /// **'Лайк :)'**
String get liked; String get liked;
/// No description provided for @disliked. /// No description provided for @disliked.
/// ///
/// In ru, this message translates to: /// In ru, this message translates to:
/// **'Не круто :с'** /// **'Дизлайк :('**
String get disliked; String get disliked;
/// No description provided for @error.
///
/// In ru, this message translates to:
/// **'Ошибка :C'**
String get error;
/// No description provided for @details.
///
/// In ru, this message translates to:
/// **'Детали цитаты'**
String get details;
/// No description provided for @arbEnding. /// No description provided for @arbEnding.
/// ///
/// In ru, this message translates to: /// In ru, this message translates to:

View File

@ -7,7 +7,13 @@ class AppLocaleEn extends AppLocale {
AppLocaleEn([String locale = 'en']) : super(locale); AppLocaleEn([String locale = 'en']) : super(locale);
@override @override
String get search => 'Поиск'; String get title => 'Quotes';
@override
String get search_word => 'Search by word';
@override
String get search_author => 'Search by author';
@override @override
String get liked => 'Like :)'; String get liked => 'Like :)';
@ -15,6 +21,12 @@ class AppLocaleEn extends AppLocale {
@override @override
String get disliked => 'Dislike :('; String get disliked => 'Dislike :(';
@override
String get error => 'Error :C';
@override
String get details => 'Details of quote';
@override @override
String get arbEnding => ''; String get arbEnding => '';
} }

View File

@ -7,13 +7,25 @@ class AppLocaleRu extends AppLocale {
AppLocaleRu([String locale = 'ru']) : super(locale); AppLocaleRu([String locale = 'ru']) : super(locale);
@override @override
String get search => 'Поиск'; String get title => 'Цитаты';
@override @override
String get liked => 'Круто :)'; String get search_word => 'Поиск по слову';
@override @override
String get disliked => 'Не круто :с'; String get search_author => 'Поиск по автору';
@override
String get liked => 'Лайк :)';
@override
String get disliked => 'Дизлайк :(';
@override
String get error => 'Ошибка :C';
@override
String get details => 'Детали цитаты';
@override @override
String get arbEnding => ''; String get arbEnding => '';

View File

@ -10,6 +10,7 @@ import 'components/locale/l10n/app_locale.dart';
import 'data/repositories/quotes_repository.dart'; import 'data/repositories/quotes_repository.dart';
import '/presentation/home_page/bloc/bloc.dart'; import '/presentation/home_page/bloc/bloc.dart';
import '/presentation/home_page/home_page.dart'; import '/presentation/home_page/home_page.dart';
void main() { void main() {
runApp(const MyApp()); runApp(const MyApp());
} }
@ -21,35 +22,32 @@ class MyApp extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider<LocaleBloc>( return BlocProvider<LocaleBloc>(
lazy: false, lazy: false,
create:(context) => LocaleBloc(Locale(Platform.localeName)), create: (context) => LocaleBloc(Locale(Platform.localeName)),
child: BlocBuilder<LocaleBloc, LocaleState>( child: BlocBuilder<LocaleBloc, LocaleState>(builder: (context, state) {
builder: (context, state) { return MaterialApp(
return MaterialApp( title: 'Цитаты',
title: 'Цитаты', locale: state.currentLocale,
locale: state.currentLocale, localizationsDelegates: AppLocale.localizationsDelegates,
localizationsDelegates: AppLocale.localizationsDelegates, supportedLocales: AppLocale.supportedLocales,
supportedLocales: AppLocale.supportedLocales, theme: ThemeData(
theme: ThemeData( colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo),
colorScheme: ColorScheme.fromSeed(seedColor: Colors.indigo), useMaterial3: true,
useMaterial3: true, ),
), home: RepositoryProvider<QuotesRepository>(
home: RepositoryProvider<QuotesRepository>( lazy: true,
lazy: true, create: (_) => QuotesRepository(),
create: (_) => QuotesRepository(), child: BlocProvider<LikeBloc>(
child: BlocProvider<LikeBloc>( lazy: false,
create: (context) => LikeBloc(), // Add LikeBloc here
child: BlocProvider<HomeBloc>(
lazy: false, lazy: false,
create: (context) => LikeBloc(), // Add LikeBloc here create: (context) => HomeBloc(context.read<QuotesRepository>()),
child: BlocProvider<HomeBloc>( child: const MyHomePage(title: '',),
lazy: false,
create: (context) => HomeBloc(context.read<QuotesRepository>()),
child: const MyHomePage(title: "Цитаты"),
),
), ),
), ),
); ),
} );
), }),
); );
} }
} }

View File

@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:pmu_flutter_labs/components/extensions/context_x.dart';
import '../../domain/quote.dart'; import '../../domain/quote.dart';
import 'home_page.dart'; import 'home_page.dart';
@ -28,8 +29,7 @@ class QuoteCard extends StatelessWidget {
child: Image.network( child: Image.network(
quote.imagePath, quote.imagePath,
fit: BoxFit.cover, fit: BoxFit.cover,
errorBuilder: (_, __, ___) => errorBuilder: (_, __, ___) => const Icon(Icons.error, color: Colors.red),
const Icon(Icons.error, color: Colors.red),
), ),
), ),
title: Text( title: Text(
@ -57,7 +57,6 @@ class QuoteCard extends StatelessWidget {
} }
} }
class QuoteDetailScreen extends StatelessWidget { class QuoteDetailScreen extends StatelessWidget {
final Quote quote; final Quote quote;
@ -67,7 +66,7 @@ class QuoteDetailScreen extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: const Text('Детали цитаты'), title: Text(context.locale.details),
), ),
body: Center( body: Center(
child: Padding( child: Padding(
@ -78,8 +77,7 @@ class QuoteDetailScreen extends StatelessWidget {
Image.network( Image.network(
quote.imagePath, quote.imagePath,
height: 150, height: 150,
errorBuilder: (_, __, ___) => errorBuilder: (_, __, ___) => const Icon(Icons.error, color: Colors.red),
const Icon(Icons.error, color: Colors.red),
), ),
const SizedBox(height: 20), const SizedBox(height: 20),
Text( Text(
@ -98,4 +96,4 @@ class QuoteDetailScreen extends StatelessWidget {
), ),
); );
} }
} }

View File

@ -27,17 +27,15 @@ class MyHomePage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(
create: (context) => create: (context) => HomeBloc(QuotesRepository())..add(const HomeLoadDataEvent()),
HomeBloc(QuotesRepository())..add(const HomeLoadDataEvent()),
child: Scaffold( child: Scaffold(
appBar: AppBar( appBar: AppBar(
title: Row( title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Text(title), Text(context.locale.title),
GestureDetector( GestureDetector(
onTap: () => onTap: () => context.read<LocaleBloc>().add(const ChangeLocaleEvent()),
context.read<LocaleBloc>().add(const ChangeLocaleEvent()),
child: SizedBox.square( child: SizedBox.square(
dimension: 50, dimension: 50,
child: Padding( child: Padding(
@ -125,7 +123,7 @@ class _HomePageBodyState extends State<_HomePageBody> {
child: TextField( child: TextField(
controller: searchController, controller: searchController,
decoration: InputDecoration( decoration: InputDecoration(
labelText: context.locale.search, labelText: context.locale.search_word,
prefixIcon: const Icon(Icons.search), prefixIcon: const Icon(Icons.search),
), ),
), ),
@ -135,7 +133,7 @@ class _HomePageBodyState extends State<_HomePageBody> {
child: TextField( child: TextField(
controller: authorController, controller: authorController,
decoration: InputDecoration( decoration: InputDecoration(
labelText: context.locale.search, labelText: context.locale.search_author,
prefixIcon: const Icon(Icons.person), prefixIcon: const Icon(Icons.person),
), ),
), ),
@ -148,22 +146,17 @@ class _HomePageBodyState extends State<_HomePageBody> {
: FutureBuilder<List<Quote>?>( : FutureBuilder<List<Quote>?>(
future: state.data, future: state.data,
builder: (context, snapshot) { builder: (context, snapshot) {
if (snapshot.connectionState == if (snapshot.connectionState == ConnectionState.waiting) {
ConnectionState.waiting) { return const Center(child: CircularProgressIndicator());
return const Center(
child: CircularProgressIndicator());
} }
if (snapshot.hasError) { if (snapshot.hasError) {
return Center( return Center(child: Text('${context.locale.error}: ${snapshot.error}'));
child: Text('Ошибка: ${snapshot.error}'));
} }
if (snapshot.data == null || if (snapshot.data == null || snapshot.data!.isEmpty) {
snapshot.data!.isEmpty) { return Center(
return const Center(
child: Text( child: Text(
'Нет цитат для отображения.', context.locale.error,
style: TextStyle( style: const TextStyle(fontSize: 18, color: Colors.grey),
fontSize: 18, color: Colors.grey),
), ),
); );
} }
@ -188,9 +181,8 @@ class _HomePageBodyState extends State<_HomePageBody> {
quote: quote, quote: quote,
isLiked: isLiked, isLiked: isLiked,
onFavoriteToggle: () { onFavoriteToggle: () {
context context.read<LikeBloc>().add(ChangeLikeEvent(quote.id));
.read<LikeBloc>() _showSnackbar(context, !isLiked);
.add(ChangeLikeEvent(quote.id));
}, },
); );
}, },

View File

@ -33,4 +33,4 @@ class LikeBloc extends Bloc<LikeEvent, LikeState> {
emit(state.copyWith(likedIds: updatedList)); emit(state.copyWith(likedIds: updatedList));
} }
} }

View File

@ -9,4 +9,4 @@ class LoadLikesEvent extends LikeEvent {
class ChangeLikeEvent extends LikeEvent { class ChangeLikeEvent extends LikeEvent {
final String id; final String id;
const ChangeLikeEvent(this.id); const ChangeLikeEvent(this.id);
} }

View File

@ -11,4 +11,4 @@ class LikeState extends Equatable {
@override @override
List<Object?> get props => [likedIds]; List<Object?> get props => [likedIds];
} }

View File

@ -14,4 +14,4 @@ class LocaleBloc extends Bloc<LocaleEvent, LocaleState> {
.firstWhere((e) => e.languageCode != state.currentLocale.languageCode); .firstWhere((e) => e.languageCode != state.currentLocale.languageCode);
emit(state.copyWith(currentLocale: toChange)); emit(state.copyWith(currentLocale: toChange));
} }
} }

View File

@ -4,4 +4,4 @@ abstract class LocaleEvent {
class ChangeLocaleEvent extends LocaleEvent { class ChangeLocaleEvent extends LocaleEvent {
const ChangeLocaleEvent(); const ChangeLocaleEvent();
} }

View File

@ -12,4 +12,4 @@ class LocaleState extends Equatable {
@override @override
List<Object?> get props => [currentLocale]; List<Object?> get props => [currentLocale];
} }

View File

@ -0,0 +1,56 @@
// 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()
? _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);
}