Add decomposition to lec4

This commit is contained in:
Aleksey Filippov 2024-10-04 11:59:55 +04:00
parent 58a81e14eb
commit 62b87de295
5 changed files with 155 additions and 103 deletions

View File

@ -1,8 +1,13 @@
part of 'home_page.dart'; import 'package:flutter/material.dart';
import 'package:test_app/domain/card.dart';
part 'card_image.dart';
part 'card_like.dart';
part 'card_text.dart';
typedef OnLikeCallback = void Function(String title, bool isLiked)?; typedef OnLikeCallback = void Function(String title, bool isLiked)?;
class _Card extends StatefulWidget { class HomeCard extends StatelessWidget {
final String text; final String text;
final String descriptionText; final String descriptionText;
final IconData icon; final IconData icon;
@ -10,21 +15,22 @@ class _Card extends StatefulWidget {
final OnLikeCallback onLike; final OnLikeCallback onLike;
final VoidCallback? onTap; final VoidCallback? onTap;
const _Card( const HomeCard(
this.text, { this.text, {
this.icon = Icons.ac_unit_outlined, this.icon = Icons.ac_unit_outlined,
required this.descriptionText, required this.descriptionText,
this.imageUrl, this.imageUrl,
this.onLike, this.onLike,
this.onTap, this.onTap,
super.key,
}); });
factory _Card.fromData( factory HomeCard.fromData(
CardData data, { CardData data, {
OnLikeCallback? onLike, OnLikeCallback? onLike,
VoidCallback? onTap, VoidCallback? onTap,
}) => }) =>
_Card( HomeCard(
data.text, data.text,
descriptionText: data.descriptionText, descriptionText: data.descriptionText,
icon: data.icon, icon: data.icon,
@ -33,17 +39,10 @@ class _Card extends StatefulWidget {
onTap: onTap, onTap: onTap,
); );
@override
State<_Card> createState() => _CardState();
}
class _CardState extends State<_Card> {
bool _isLiked = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return GestureDetector( return GestureDetector(
onTap: widget.onTap, onTap: onTap,
child: Container( child: Container(
margin: const EdgeInsets.only(top: 8, bottom: 8), margin: const EdgeInsets.only(top: 8, bottom: 8),
constraints: const BoxConstraints(minHeight: 140), constraints: const BoxConstraints(minHeight: 140),
@ -63,94 +62,14 @@ class _CardState extends State<_Card> {
child: Row( child: Row(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
ClipRRect( _CardImage(imageUrl ?? ''),
borderRadius: const BorderRadius.only( _CardText(
bottomLeft: Radius.circular(20), text,
topLeft: Radius.circular(20), descriptionText: descriptionText,
),
child: SizedBox(
height: double.infinity,
width: 115,
child: Stack(
children: [
Positioned.fill(
child: Image.network(
widget.imageUrl ?? '',
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => const Placeholder(),
),
),
Align(
alignment: Alignment.bottomLeft,
child: Container(
decoration: const BoxDecoration(
color: Colors.orangeAccent,
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
),
),
padding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
child: Text(
'скидка 20%',
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(color: Colors.black),
),
),
)
],
),
),
), ),
Expanded( _CardLike(
child: Padding( onLike,
padding: const EdgeInsets.only(left: 8), text: text,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.text,
style: Theme.of(context).textTheme.headlineLarge,
),
Text(
widget.descriptionText,
style: Theme.of(context).textTheme.bodyLarge,
)
],
),
),
),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(
left: 8,
right: 16,
bottom: 16,
),
child: GestureDetector(
onTap: () {
setState(() {
_isLiked = !_isLiked;
});
widget.onLike?.call(widget.text, _isLiked);
},
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: _isLiked
? const Icon(
Icons.favorite,
color: Colors.redAccent,
key: ValueKey(0),
)
: const Icon(
Icons.favorite_border,
key: ValueKey(1),
),
),
),
),
) )
], ],
), ),

View File

@ -0,0 +1,51 @@
part of 'card.dart';
class _CardImage extends StatelessWidget {
final String imageUrl;
const _CardImage(this.imageUrl);
@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: const BorderRadius.only(
bottomLeft: Radius.circular(20),
topLeft: Radius.circular(20),
),
child: SizedBox(
height: double.infinity,
width: 115,
child: Stack(
children: [
Positioned.fill(
child: Image.network(
imageUrl,
fit: BoxFit.cover,
errorBuilder: (_, __, ___) => const Placeholder(),
),
),
Align(
alignment: Alignment.bottomLeft,
child: Container(
decoration: const BoxDecoration(
color: Colors.orangeAccent,
borderRadius: BorderRadius.only(
topRight: Radius.circular(20),
),
),
padding: const EdgeInsets.fromLTRB(8, 2, 8, 2),
child: Text(
'скидка 20%',
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(color: Colors.black),
),
),
)
],
),
),
);
}
}

View File

@ -0,0 +1,50 @@
part of 'card.dart';
class _CardLike extends StatefulWidget {
final OnLikeCallback onLike;
final String text;
const _CardLike(this.onLike, {required this.text});
@override
State<_CardLike> createState() => _CardLikeState();
}
class _CardLikeState extends State<_CardLike> {
bool _isLiked = false;
@override
Widget build(BuildContext context) {
return Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.only(
left: 8,
right: 16,
bottom: 16,
),
child: GestureDetector(
onTap: () {
setState(() {
_isLiked = !_isLiked;
});
widget.onLike?.call(widget.text, _isLiked);
},
child: AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: _isLiked
? const Icon(
Icons.favorite,
color: Colors.redAccent,
key: ValueKey(0),
)
: const Icon(
Icons.favorite_border,
key: ValueKey(1),
),
),
),
),
);
}
}

View File

@ -0,0 +1,33 @@
part of 'card.dart';
class _CardText extends StatelessWidget {
final String text;
final String descriptionText;
const _CardText(
this.text, {
required this.descriptionText,
});
@override
Widget build(BuildContext context) {
return Expanded(
child: Padding(
padding: const EdgeInsets.only(left: 8),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
text,
style: Theme.of(context).textTheme.headlineLarge,
),
Text(
descriptionText,
style: Theme.of(context).textTheme.bodyLarge,
)
],
),
),
);
}
}

View File

@ -1,8 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:test_app/domain/card.dart'; import 'package:test_app/domain/card.dart';
import 'package:test_app/view/details_page/details_page.dart'; import 'package:test_app/view/details_page/details_page.dart';
import 'package:test_app/view/home_page/card.dart';
part 'card.dart';
class MyHomePage extends StatefulWidget { class MyHomePage extends StatefulWidget {
const MyHomePage({super.key, required this.title}); const MyHomePage({super.key, required this.title});
@ -62,7 +61,7 @@ class Body extends StatelessWidget {
child: Column( child: Column(
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: data children: data
.map((data) => _Card.fromData( .map((data) => HomeCard.fromData(
data, data,
onLike: (String title, bool isLiked) => onLike: (String title, bool isLiked) =>
_showSnackBar(context, title, isLiked), _showSnackBar(context, title, isLiked),