ура 1 этап работает, спааать
This commit is contained in:
parent
ce3ed67612
commit
192c7f6472
@ -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: 'Кувшинов Тимур Александрович'),
|
||||||
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
16
lib/presentation/home_page/bloc/bloc.dart
Normal file
16
lib/presentation/home_page/bloc/bloc.dart
Normal 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()));
|
||||||
|
}
|
||||||
|
}
|
6
lib/presentation/home_page/bloc/events.dart
Normal file
6
lib/presentation/home_page/bloc/events.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
abstract class HomeEvent {
|
||||||
|
const HomeEvent();
|
||||||
|
}
|
||||||
|
class HomeLoadDataEvent extends HomeEvent {
|
||||||
|
const HomeLoadDataEvent();
|
||||||
|
}
|
11
lib/presentation/home_page/bloc/state.dart
Normal file
11
lib/presentation/home_page/bloc/state.dart
Normal 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];
|
||||||
|
}
|
@ -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),
|
||||||
|
@ -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),
|
||||||
|
56
pubspec.lock
56
pubspec.lock
@ -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:
|
||||||
|
10
pubspec.yaml
10
pubspec.yaml
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user