ура 1 этап работает, спааать

This commit is contained in:
Timourka 2024-10-27 01:34:35 +04:00
parent ce3ed67612
commit 192c7f6472
8 changed files with 175 additions and 60 deletions

View File

@ -1,6 +1,10 @@
import 'package:flutter/material.dart'; 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 'package:laba1/presentation/home_page/home_page.dart';
import 'data/repositories/potter_repository.dart';
void main() { void main() {
runApp(const MyApp()); runApp(const MyApp());
} }
@ -15,7 +19,15 @@ class MyApp extends StatelessWidget {
theme: ThemeData( theme: ThemeData(
primarySwatch: Colors.amber, primarySwatch: Colors.amber,
), ),
home: const MyHomePage(title: 'Кувшинов Тимур Александрович'), home: RepositoryProvider<PotterRepository>(
lazy: true,
create: (_) => PotterRepository(),
child: BlocProvider<HomeBloc>(
lazy: false,
create: (context) => HomeBloc(context.read<PotterRepository>()),
child: const MyHomePage(title: 'Кувшинов Тимур Александрович'),
),
),
); );
} }
} }

View File

@ -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<HomeEvent, HomeState> {
final PotterRepository repo;
HomeBloc(this.repo) : super(const HomeState()) {
on<HomeLoadDataEvent>(_onLoadData);
}
void _onLoadData(HomeLoadDataEvent event, Emitter<HomeState> emit) {
emit(state.copyWith(data: repo.loadData()));
}
}

View File

@ -0,0 +1,6 @@
abstract class HomeEvent {
const HomeEvent();
}
class HomeLoadDataEvent extends HomeEvent {
const HomeLoadDataEvent();
}

View File

@ -0,0 +1,11 @@
import 'package:equatable/equatable.dart';
import '../../../domain/models/card.dart';
class HomeState extends Equatable {
final Future<List<CardData>?>? data;
const HomeState({this.data});
HomeState copyWith({Future<List<CardData>?>? data}) => HomeState(data: data ?? this.data);
@override
List<Object?> get props => [data];
}

View File

@ -1,6 +1,6 @@
part of 'home_page.dart'; part of 'home_page.dart';
typedef OnLikeCallback = void Function(bool isLiked)?; typedef OnLikeCallback = void Function(String title, bool isLiked)?;
class _Card extends StatefulWidget { class _Card extends StatefulWidget {
final String _text; final String _text;
@ -100,7 +100,7 @@ class _CardState extends State<_Card> {
onTap: () { onTap: () {
isLiked = !isLiked; isLiked = !isLiked;
setState(() {}); setState(() {});
widget.onLike?.call(isLiked); widget.onLike?.call(widget._text, isLiked);
}, },
child: AnimatedSwitcher( child: AnimatedSwitcher(
duration: const Duration(milliseconds: 100), duration: const Duration(milliseconds: 100),

View File

@ -1,62 +1,74 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:laba1/data/repositories/potter_repository.dart'; import 'package:laba1/data/repositories/potter_repository.dart';
import 'package:laba1/presentation/details_page/details_page.dart'; import 'package:laba1/presentation/details_page/details_page.dart';
import '../../data/repositories/mock_repository.dart'; import '../../data/repositories/mock_repository.dart';
import '../../domain/models/card.dart'; import '../../domain/models/card.dart';
import '../dialogs/show_dialog.dart'; import '../dialogs/show_dialog.dart';
import 'bloc/bloc.dart';
import 'bloc/events.dart';
import 'bloc/state.dart';
part 'card.dart'; part 'card.dart';
class MyHomePage extends StatelessWidget { class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title}); const MyHomePage({super.key, required this.title});
final String title; final String title;
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
appBar: AppBar( appBar: AppBar(
title: Text(title), title: Text(widget.title),
backgroundColor: Colors.amber, backgroundColor: Colors.amber,
), ),
backgroundColor: Colors.yellow, backgroundColor: Colors.yellow,
body: const Body()); body: const _Body());
} }
} }
class Body extends StatefulWidget { class _Body extends StatefulWidget {
const Body({Key? key}) : super(key: key); const _Body({Key? key}) : super(key: key);
@override @override
State<Body> createState() => _BodyState(); State<_Body> createState() => _BodyState();
} }
class _BodyState extends State<Body> { class _BodyState extends State<_Body> {
final searchController = TextEditingController(); final searchController = TextEditingController();
late Future<List<CardData>?> data;
final repo = PotterRepository();
bool isLoading = false;
@override @override
void initState() { void initState() {
data = repo.loadData(onError: (e) => showErrorDialog(context, error: e)); WidgetsBinding.instance.addPostFrameCallback((_) {
isLoading = true; context.read<HomeBloc>().add(const HomeLoadDataEvent());
data.then((_) => setState(() { });
isLoading = false; // Остановить индикатор при завершении загрузки
}));
super.initState(); super.initState();
} }
@override
void dispose() {
searchController.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Center( return Center(
child: Stack( child: Stack(
children: [ children: [
Positioned.fill( Positioned.fill(
child: FutureBuilder<List<CardData>?>( child: BlocBuilder<HomeBloc, HomeState > (
future: data, builder: (context, state) =>
FutureBuilder<List<CardData>?>(
future: state.data,
builder: (context, snapshot) { builder: (context, snapshot) {
var cards = Column( var cards = Column(
children: [], children: [],
@ -73,53 +85,42 @@ class _BodyState extends State<Body> {
)); ));
cards.children.addAll( cards.children.addAll(
snapshot.data snapshot.data
?.map((e) => _Card.fromData( ?.map((e) =>
e, _Card.fromData(
onLike: (bool isLiked) { e,
_showSnackBar(context, isLiked); onLike: (String title, bool isLiked) {
}, _showSnackBar(context, title, isLiked);
onTap: () => _navToDetails(context, e), },
)) onTap: () => _navToDetails(context, e),
.toList() ?? ))
.toList() ??
[], [],
); );
return !isLoading return snapshot.hasData
? SingleChildScrollView( ? SingleChildScrollView(
child: cards, child: cards,
) )
: Center(child: CircularProgressIndicator()); : Center(child: CircularProgressIndicator());
}, },
), ),
), ),),
Align( Align(
alignment: Alignment.topCenter, alignment: Alignment.topCenter,
child: Padding( child: Padding(
padding: const EdgeInsets.only(left: 8.0, right: 8), padding: const EdgeInsets.only(left: 8.0, right: 8),
child: CupertinoSearchTextField( child: CupertinoSearchTextField(
borderRadius: BorderRadius.only( borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(20), bottomLeft: Radius.circular(20),
bottomRight: 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; // Остановить индикатор при завершении загрузки
}));
});
},
), ),
backgroundColor: Colors.amberAccent,
controller: searchController,
onChanged: (search) {
//TODO
},
), ),
), ),
),
], ],
), ),
); );
@ -132,12 +133,15 @@ class _BodyState extends State<Body> {
); );
} }
void _showSnackBar(BuildContext context, bool isLiked) { void _showSnackBar(BuildContext context, String title, bool isLiked) {
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
ScaffoldMessenger.of(context).showSnackBar(SnackBar( ScaffoldMessenger.of(context).showSnackBar(SnackBar(
content: Text( content: Text(
'Card ${isLiked ? 'liked' : 'unliked'}', '$title ${isLiked ? 'liked' : 'unliked'}',
style: Theme.of(context).textTheme.bodyLarge, style: Theme
.of(context)
.textTheme
.bodyLarge,
), ),
backgroundColor: Colors.orangeAccent, backgroundColor: Colors.orangeAccent,
duration: const Duration(seconds: 1), duration: const Duration(seconds: 1),

View File

@ -38,6 +38,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.11.0" version: "2.11.0"
bloc:
dependency: transitive
description:
name: bloc
sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e"
url: "https://pub.dev"
source: hosted
version: "8.1.4"
boolean_selector: boolean_selector:
dependency: transitive dependency: transitive
description: description:
@ -158,6 +166,22 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "3.1.1" 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: crypto:
dependency: transitive dependency: transitive
description: description:
@ -198,6 +222,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" 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: fake_async:
dependency: transitive dependency: transitive
description: description:
@ -227,6 +259,14 @@ packages:
description: flutter description: flutter
source: sdk source: sdk
version: "0.0.0" 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: flutter_lints:
dependency: "direct dev" dependency: "direct dev"
description: description:
@ -392,6 +432,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "2.0.0" version: "2.0.0"
nested:
dependency: transitive
description:
name: nested
sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20"
url: "https://pub.dev"
source: hosted
version: "1.0.0"
package_config: package_config:
dependency: transitive dependency: transitive
description: description:
@ -424,6 +472,14 @@ packages:
url: "https://pub.dev" url: "https://pub.dev"
source: hosted source: hosted
version: "1.4.0" version: "1.4.0"
provider:
dependency: transitive
description:
name: provider
sha256: c8a055ee5ce3fd98d6fc872478b03823ffdb448699c6ebdbbc71d59b596fd48c
url: "https://pub.dev"
source: hosted
version: "6.1.2"
pub_semver: pub_semver:
dependency: transitive dependency: transitive
description: description:

View File

@ -36,15 +36,25 @@ dependencies:
# The following adds the Cupertino Icons font to your application. # The following adds the Cupertino Icons font to your application.
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
# Сетевое взаимодействие
json_annotation: ^4.8.1 json_annotation: ^4.8.1
dio: ^5.4.2+1 dio: ^5.4.2+1
pretty_dio_logger: ^1.3.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: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
# Сетевое взаимодействие
build_runner: ^2.4.9 build_runner: ^2.4.9
json_serializable: ^6.7.1 json_serializable: ^6.7.1
# The "flutter_lints" package below contains a set of recommended lints to # The "flutter_lints" package below contains a set of recommended lints to
# encourage good coding practices. The lint set provided by the package is # 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 # activated in the `analysis_options.yaml` file located at the root of your