From 192c7f6472f15831710f85f1caa3cd9d6033aab2 Mon Sep 17 00:00:00 2001 From: Timourka Date: Sun, 27 Oct 2024 01:34:35 +0400 Subject: [PATCH] =?UTF-8?q?=D1=83=D1=80=D0=B0=201=20=D1=8D=D1=82=D0=B0?= =?UTF-8?q?=D0=BF=20=D1=80=D0=B0=D0=B1=D0=BE=D1=82=D0=B0=D0=B5=D1=82,=20?= =?UTF-8?q?=D1=81=D0=BF=D0=B0=D0=B0=D0=B0=D1=82=D1=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/main.dart | 14 ++- lib/presentation/home_page/bloc/bloc.dart | 16 +++ lib/presentation/home_page/bloc/events.dart | 6 + lib/presentation/home_page/bloc/state.dart | 11 ++ lib/presentation/home_page/card.dart | 4 +- lib/presentation/home_page/home_page.dart | 118 ++++++++++---------- pubspec.lock | 56 ++++++++++ pubspec.yaml | 10 ++ 8 files changed, 175 insertions(+), 60 deletions(-) create mode 100644 lib/presentation/home_page/bloc/bloc.dart create mode 100644 lib/presentation/home_page/bloc/events.dart create mode 100644 lib/presentation/home_page/bloc/state.dart diff --git a/lib/main.dart b/lib/main.dart index db572bf..f165aa0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,6 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:laba1/presentation/home_page/bloc/bloc.dart'; import 'package:laba1/presentation/home_page/home_page.dart'; +import 'data/repositories/potter_repository.dart'; + void main() { runApp(const MyApp()); } @@ -15,7 +19,15 @@ class MyApp extends StatelessWidget { theme: ThemeData( primarySwatch: Colors.amber, ), - home: const MyHomePage(title: 'Кувшинов Тимур Александрович'), + home: RepositoryProvider( + lazy: true, + create: (_) => PotterRepository(), + child: BlocProvider( + lazy: false, + create: (context) => HomeBloc(context.read()), + child: const MyHomePage(title: 'Кувшинов Тимур Александрович'), + ), + ), ); } } diff --git a/lib/presentation/home_page/bloc/bloc.dart b/lib/presentation/home_page/bloc/bloc.dart new file mode 100644 index 0000000..6e6960a --- /dev/null +++ b/lib/presentation/home_page/bloc/bloc.dart @@ -0,0 +1,16 @@ +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:laba1/data/repositories/mock_repository.dart'; +import 'package:laba1/presentation/home_page/bloc/state.dart'; + +import '../../../data/repositories/potter_repository.dart'; +import 'events.dart'; + +class HomeBloc extends Bloc { + final PotterRepository repo; + HomeBloc(this.repo) : super(const HomeState()) { + on(_onLoadData); + } + void _onLoadData(HomeLoadDataEvent event, Emitter emit) { + emit(state.copyWith(data: repo.loadData())); + } +} \ No newline at end of file diff --git a/lib/presentation/home_page/bloc/events.dart b/lib/presentation/home_page/bloc/events.dart new file mode 100644 index 0000000..c565592 --- /dev/null +++ b/lib/presentation/home_page/bloc/events.dart @@ -0,0 +1,6 @@ +abstract class HomeEvent { + const HomeEvent(); +} +class HomeLoadDataEvent extends HomeEvent { + const HomeLoadDataEvent(); +} \ No newline at end of file diff --git a/lib/presentation/home_page/bloc/state.dart b/lib/presentation/home_page/bloc/state.dart new file mode 100644 index 0000000..ff3a706 --- /dev/null +++ b/lib/presentation/home_page/bloc/state.dart @@ -0,0 +1,11 @@ +import 'package:equatable/equatable.dart'; + +import '../../../domain/models/card.dart'; + +class HomeState extends Equatable { + final Future?>? data; + const HomeState({this.data}); + HomeState copyWith({Future?>? data}) => HomeState(data: data ?? this.data); + @override + List get props => [data]; +} \ No newline at end of file diff --git a/lib/presentation/home_page/card.dart b/lib/presentation/home_page/card.dart index b3263e8..b8277bd 100644 --- a/lib/presentation/home_page/card.dart +++ b/lib/presentation/home_page/card.dart @@ -1,6 +1,6 @@ part of 'home_page.dart'; -typedef OnLikeCallback = void Function(bool isLiked)?; +typedef OnLikeCallback = void Function(String title, bool isLiked)?; class _Card extends StatefulWidget { final String _text; @@ -100,7 +100,7 @@ class _CardState extends State<_Card> { onTap: () { isLiked = !isLiked; setState(() {}); - widget.onLike?.call(isLiked); + widget.onLike?.call(widget._text, isLiked); }, child: AnimatedSwitcher( duration: const Duration(milliseconds: 100), diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart index 1560e81..e6dca77 100644 --- a/lib/presentation/home_page/home_page.dart +++ b/lib/presentation/home_page/home_page.dart @@ -1,62 +1,74 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:laba1/data/repositories/potter_repository.dart'; import 'package:laba1/presentation/details_page/details_page.dart'; import '../../data/repositories/mock_repository.dart'; import '../../domain/models/card.dart'; import '../dialogs/show_dialog.dart'; +import 'bloc/bloc.dart'; +import 'bloc/events.dart'; +import 'bloc/state.dart'; part 'card.dart'; -class MyHomePage extends StatelessWidget { +class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); final String title; + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( - title: Text(title), + title: Text(widget.title), backgroundColor: Colors.amber, ), backgroundColor: Colors.yellow, - body: const Body()); + body: const _Body()); } } -class Body extends StatefulWidget { - const Body({Key? key}) : super(key: key); +class _Body extends StatefulWidget { + const _Body({Key? key}) : super(key: key); @override - State createState() => _BodyState(); + State<_Body> createState() => _BodyState(); } -class _BodyState extends State { +class _BodyState extends State<_Body> { final searchController = TextEditingController(); - late Future?> data; - final repo = PotterRepository(); - bool isLoading = false; @override void initState() { - data = repo.loadData(onError: (e) => showErrorDialog(context, error: e)); - isLoading = true; - data.then((_) => setState(() { - isLoading = false; // Остановить индикатор при завершении загрузки - })); + WidgetsBinding.instance.addPostFrameCallback((_) { + context.read().add(const HomeLoadDataEvent()); + }); super.initState(); } + @override + void dispose() { + searchController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { return Center( child: Stack( children: [ - Positioned.fill( - child: FutureBuilder?>( - future: data, + Positioned.fill( + child: BlocBuilder ( + builder: (context, state) => + FutureBuilder?>( + future: state.data, builder: (context, snapshot) { var cards = Column( children: [], @@ -73,53 +85,42 @@ class _BodyState extends State { )); cards.children.addAll( snapshot.data - ?.map((e) => _Card.fromData( - e, - onLike: (bool isLiked) { - _showSnackBar(context, isLiked); - }, - onTap: () => _navToDetails(context, e), - )) - .toList() ?? + ?.map((e) => + _Card.fromData( + e, + onLike: (String title, bool isLiked) { + _showSnackBar(context, title, isLiked); + }, + onTap: () => _navToDetails(context, e), + )) + .toList() ?? [], ); - return !isLoading + return snapshot.hasData ? SingleChildScrollView( child: cards, ) : Center(child: CircularProgressIndicator()); }, ), - ), - Align( - alignment: Alignment.topCenter, - child: Padding( - padding: const EdgeInsets.only(left: 8.0, right: 8), - child: CupertinoSearchTextField( - borderRadius: BorderRadius.only( - bottomLeft: Radius.circular(20), - bottomRight: Radius.circular(20), - ), - backgroundColor: Colors.amberAccent, - controller: searchController, - onChanged: (search) { - setState(() { - isLoading = true; - }); - setState(() { - data = repo.loadData( - q: search, - onError: (e) => showErrorDialog(context, error: e), - ); - data.then((_) => setState(() { - isLoading = - false; // Остановить индикатор при завершении загрузки - })); - }); - }, + ),), + Align( + alignment: Alignment.topCenter, + child: Padding( + padding: const EdgeInsets.only(left: 8.0, right: 8), + child: CupertinoSearchTextField( + borderRadius: BorderRadius.only( + bottomLeft: Radius.circular(20), + bottomRight: Radius.circular(20), ), + backgroundColor: Colors.amberAccent, + controller: searchController, + onChanged: (search) { + //TODO + }, ), ), + ), ], ), ); @@ -132,12 +133,15 @@ class _BodyState extends State { ); } - void _showSnackBar(BuildContext context, bool isLiked) { + void _showSnackBar(BuildContext context, String title, bool isLiked) { WidgetsBinding.instance.addPostFrameCallback((_) { ScaffoldMessenger.of(context).showSnackBar(SnackBar( content: Text( - 'Card ${isLiked ? 'liked' : 'unliked'}', - style: Theme.of(context).textTheme.bodyLarge, + '$title ${isLiked ? 'liked' : 'unliked'}', + style: Theme + .of(context) + .textTheme + .bodyLarge, ), backgroundColor: Colors.orangeAccent, duration: const Duration(seconds: 1), diff --git a/pubspec.lock b/pubspec.lock index 3bee088..3dcf6ce 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -38,6 +38,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.11.0" + bloc: + dependency: transitive + description: + name: bloc + sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e" + url: "https://pub.dev" + source: hosted + version: "8.1.4" boolean_selector: dependency: transitive description: @@ -158,6 +166,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.1" + copy_with_extension: + dependency: transitive + description: + name: copy_with_extension + sha256: fbcf890b0c34aedf0894f91a11a579994b61b4e04080204656b582708b5b1125 + url: "https://pub.dev" + source: hosted + version: "5.0.4" + copy_with_extension_gen: + dependency: "direct main" + description: + name: copy_with_extension_gen + sha256: "51cd11094096d40824c8da629ca7f16f3b7cea5fc44132b679617483d43346b0" + url: "https://pub.dev" + source: hosted + version: "5.0.4" crypto: dependency: transitive description: @@ -198,6 +222,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + equatable: + dependency: "direct main" + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" fake_async: dependency: transitive description: @@ -227,6 +259,14 @@ packages: description: flutter source: sdk version: "0.0.0" + flutter_bloc: + dependency: "direct main" + description: + name: flutter_bloc + sha256: b594505eac31a0518bdcb4b5b79573b8d9117b193cc80cc12e17d639b10aa27a + url: "https://pub.dev" + source: hosted + version: "8.1.6" flutter_lints: dependency: "direct dev" description: @@ -392,6 +432,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + nested: + dependency: transitive + description: + name: nested + sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" + url: "https://pub.dev" + source: hosted + version: "1.0.0" package_config: dependency: transitive description: @@ -424,6 +472,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.0" + provider: + dependency: transitive + description: + name: provider + sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c + url: "https://pub.dev" + source: hosted + version: "6.1.2" pub_semver: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 551764d..4db5bd3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -36,15 +36,25 @@ dependencies: # The following adds the Cupertino Icons font to your application. # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 + + # Сетевое взаимодействие json_annotation: ^4.8.1 dio: ^5.4.2+1 pretty_dio_logger: ^1.3.1 + + # BLoC + equatable: ^2.0.5 + flutter_bloc: ^8.1.5 + copy_with_extension_gen: ^5.0.4 + dev_dependencies: flutter_test: sdk: flutter + # Сетевое взаимодействие build_runner: ^2.4.9 json_serializable: ^6.7.1 + # The "flutter_lints" package below contains a set of recommended lints to # encourage good coding practices. The lint set provided by the package is # activated in the `analysis_options.yaml` file located at the root of your