diff --git a/lec4/lib/view/home_page/card.dart b/lec4/lib/view/home_page/card.dart index 5e4766e..3c13ec8 100644 --- a/lec4/lib/view/home_page/card.dart +++ b/lec4/lib/view/home_page/card.dart @@ -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)?; -class _Card extends StatefulWidget { +class HomeCard extends StatelessWidget { final String text; final String descriptionText; final IconData icon; @@ -10,21 +15,22 @@ class _Card extends StatefulWidget { final OnLikeCallback onLike; final VoidCallback? onTap; - const _Card( + const HomeCard( this.text, { this.icon = Icons.ac_unit_outlined, required this.descriptionText, this.imageUrl, this.onLike, this.onTap, + super.key, }); - factory _Card.fromData( + factory HomeCard.fromData( CardData data, { OnLikeCallback? onLike, VoidCallback? onTap, }) => - _Card( + HomeCard( data.text, descriptionText: data.descriptionText, icon: data.icon, @@ -33,17 +39,10 @@ class _Card extends StatefulWidget { onTap: onTap, ); - @override - State<_Card> createState() => _CardState(); -} - -class _CardState extends State<_Card> { - bool _isLiked = false; - @override Widget build(BuildContext context) { return GestureDetector( - onTap: widget.onTap, + onTap: onTap, child: Container( margin: const EdgeInsets.only(top: 8, bottom: 8), constraints: const BoxConstraints(minHeight: 140), @@ -63,94 +62,14 @@ class _CardState extends State<_Card> { child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ - 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( - 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), - ), - ), - ) - ], - ), - ), + _CardImage(imageUrl ?? ''), + _CardText( + text, + descriptionText: descriptionText, ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 8), - 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), - ), - ), - ), - ), + _CardLike( + onLike, + text: text, ) ], ), diff --git a/lec4/lib/view/home_page/card_image.dart b/lec4/lib/view/home_page/card_image.dart new file mode 100644 index 0000000..2956442 --- /dev/null +++ b/lec4/lib/view/home_page/card_image.dart @@ -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), + ), + ), + ) + ], + ), + ), + ); + } +} diff --git a/lec4/lib/view/home_page/card_like.dart b/lec4/lib/view/home_page/card_like.dart new file mode 100644 index 0000000..bb7da19 --- /dev/null +++ b/lec4/lib/view/home_page/card_like.dart @@ -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), + ), + ), + ), + ), + ); + } +} diff --git a/lec4/lib/view/home_page/card_text.dart b/lec4/lib/view/home_page/card_text.dart new file mode 100644 index 0000000..0dafc8f --- /dev/null +++ b/lec4/lib/view/home_page/card_text.dart @@ -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, + ) + ], + ), + ), + ); + } +} diff --git a/lec4/lib/view/home_page/home_page.dart b/lec4/lib/view/home_page/home_page.dart index 70e8532..ab4bcbb 100644 --- a/lec4/lib/view/home_page/home_page.dart +++ b/lec4/lib/view/home_page/home_page.dart @@ -1,8 +1,7 @@ import 'package:flutter/material.dart'; import 'package:test_app/domain/card.dart'; import 'package:test_app/view/details_page/details_page.dart'; - -part 'card.dart'; +import 'package:test_app/view/home_page/card.dart'; class MyHomePage extends StatefulWidget { const MyHomePage({super.key, required this.title}); @@ -62,7 +61,7 @@ class Body extends StatelessWidget { child: Column( mainAxisAlignment: MainAxisAlignment.center, children: data - .map((data) => _Card.fromData( + .map((data) => HomeCard.fromData( data, onLike: (String title, bool isLiked) => _showSnackBar(context, title, isLiked),