From dab4485d2043cc26b883d792485c0e82473111ac Mon Sep 17 00:00:00 2001 From: gg12 darfren Date: Sun, 22 Sep 2024 22:10:59 +0400 Subject: [PATCH] lab4 --- lib/domain/models/card.dart | 19 ++ lib/main.dart | 182 +----------------- .../details_page/details_page.dart | 48 +++++ lib/presentation/home_page/card.dart | 145 ++++++++++++++ lib/presentation/home_page/home_page.dart | 125 ++++++++++++ 5 files changed, 338 insertions(+), 181 deletions(-) create mode 100644 lib/domain/models/card.dart create mode 100644 lib/presentation/details_page/details_page.dart create mode 100644 lib/presentation/home_page/card.dart create mode 100644 lib/presentation/home_page/home_page.dart diff --git a/lib/domain/models/card.dart b/lib/domain/models/card.dart new file mode 100644 index 0000000..57a74bb --- /dev/null +++ b/lib/domain/models/card.dart @@ -0,0 +1,19 @@ +import 'package:flutter/material.dart'; + +class CardData { + final String text; + final String descriprionText; + final int weight; + final IconData icon; + final String? imageUrl; + final bool isTop; + + CardData( + this.text, { + required this.descriprionText, + required this.weight, + this.icon = Icons.hail, + this.imageUrl, + this.isTop = false, + }); +} \ No newline at end of file diff --git a/lib/main.dart b/lib/main.dart index 7bd6d47..e7907f1 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,11 +1,10 @@ import 'package:flutter/material.dart'; +import 'package:pmu_project/presentation/home_page/home_page.dart'; void main() { runApp(const MyApp()); } -const Color mainColor = Colors.deepOrangeAccent; - class MyApp extends StatelessWidget { const MyApp({super.key}); @@ -22,183 +21,4 @@ class MyApp 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( - leading: Icon(Icons.abc_rounded), - backgroundColor: mainColor, - title: Text(widget.title), - ), - body: const MyWidget(), - ); - } -} - -class MyWidget extends StatelessWidget { - const MyWidget({super.key}); - - @override - Widget build(BuildContext context) { - final data = [ - _CardData( - 'Рулет из баклажанов', - descriprionText: 'рулет из баклажанов, чеснока и сыра', - weight: 300, - imageUrl: - 'https://kolyda.ru/d/baklazhanchiki_farshirovannye_orehami.jpg', - ), - _CardData( - 'Лагман', - descriprionText: 'Суп из говядины и овощей', - isTop: true, - weight: 250, - imageUrl: 'https://avatars.mds.yandex.net/get-altay/5257938/2' - 'a0000018aa4c0859fe7c036bfa6312e4732/XXL_height', - ), - _CardData( - 'Манты', - descriprionText: 'Это пельмени. Большие.', - weight: 250, - imageUrl: - 'https://chaihana-zamzam.ru/wp-content/uploads/2022/10/Mantu.jpg', - ), - _CardData( - 'Свиной шашлык', - descriprionText: 'Осторожно ! Свинина !', - isTop: true, - weight: 300, - imageUrl: - 'https://avatars.mds.yandex.net/get-altay/9686455/2a0000018a4892e137bca9e41256a79d2c7a/orig', - icon: Icons.warning, - ), - _CardData( - 'Куриный шашлык', - descriprionText: 'Халяль', - weight: 300, - imageUrl: - 'https://i.pinimg.com/originals/2f/b5/7e/2fb57efeac571775d423ad995e5c1e1d.jpg', - ), - ]; - - return Center( - child: SingleChildScrollView( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - children: data.map((e) => _Card.fromData(e)).toList(), - ), - ), - ); - } -} - -class _CardData { - final String text; - final String descriprionText; - final int weight; - final IconData icon; - final String? imageUrl; - final bool isTop; - - _CardData( - this.text, { - required this.descriprionText, - required this.weight, - this.icon = Icons.hail, - this.imageUrl, - this.isTop = false, - }); -} - -class _Card extends StatelessWidget { - final String text; - final IconData icon; - final String descriptionText; - final String? imageUrl; - final Color color; - - const _Card( - this.text, { - this.icon = Icons.ac_unit_outlined, - required this.descriptionText, - this.imageUrl, - this.color = Colors.white70, - }); - - factory _Card.fromData(_CardData data) => _Card( - data.text, - descriptionText: data.descriprionText, - icon: data.icon, - imageUrl: data.imageUrl, - color: (data.isTop ? mainColor : Colors.white70), - ); - - @override - Widget build(BuildContext context) { - return Container( - margin: const EdgeInsets.only(top: 8, bottom: 8), - padding: const EdgeInsets.all(16), - decoration: BoxDecoration( - color: color, - borderRadius: BorderRadius.circular(20), - border: Border.all( - color: Colors.black, - width: 3, - ), - boxShadow: [ - BoxShadow(color: Colors.grey, spreadRadius: 4, blurRadius: 8) - ]), - child: Row( - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(20), - child: SizedBox( - height: 140, - width: 120, - child: Image.network( - fit: BoxFit.cover, - imageUrl ?? '', - errorBuilder: (_, __, ___) => const Placeholder(), - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - text, - style: Theme.of(context).textTheme.headlineLarge, - ), - Text( - descriptionText, - style: Theme.of(context).textTheme.bodyLarge, - ), - ], - ), - ), - ), - Padding( - padding: const EdgeInsets.all(8.0), - child: Icon(icon), - ), - - ], - ), - ); - } -} diff --git a/lib/presentation/details_page/details_page.dart b/lib/presentation/details_page/details_page.dart new file mode 100644 index 0000000..0c1dfd7 --- /dev/null +++ b/lib/presentation/details_page/details_page.dart @@ -0,0 +1,48 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; + +import '../../domain/models/card.dart'; + +class DetailsPage extends StatelessWidget { + final CardData data; + + const DetailsPage(this.data, {super.key}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar(), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(bottom: 16.0), + child: Image.network(data.imageUrl ?? '',), + ), + Padding( + padding: const EdgeInsets.only(bottom: 4.0, left: 4.0, right: 4.0), + child: Text( + data.text, + style: Theme + .of(context) + .textTheme + .headlineLarge, + ), + ), + Padding( + padding: const EdgeInsets.only(bottom: 4.0, left: 4.0, right: 4.0), + child: Text( + data.descriprionText, + style: Theme + .of(context) + .textTheme + .bodyMedium, + ), + ), + ], + ) + + ); + } + +} \ No newline at end of file diff --git a/lib/presentation/home_page/card.dart b/lib/presentation/home_page/card.dart new file mode 100644 index 0000000..c309467 --- /dev/null +++ b/lib/presentation/home_page/card.dart @@ -0,0 +1,145 @@ +part of 'home_page.dart'; + +typedef OnLikeCall = void Function(String Title, bool isLiked); + +class _Card extends StatefulWidget { + final String text; + final IconData icon; + final String descriptionText; + final String? imageUrl; + final Color color; + final OnLikeCall? onLike; + final VoidCallback? onTap; + + const _Card(this.text, + {this.icon = Icons.ac_unit_outlined, + required this.descriptionText, + this.imageUrl, + this.color = Colors.white70, + this.onLike, + this.onTap}); + + factory _Card.fromData( + CardData data, { + OnLikeCall? onLike, + VoidCallback? onTap, + }) => + _Card( + data.text, + descriptionText: data.descriprionText, + icon: data.icon, + imageUrl: data.imageUrl, + color: (data.isTop ? mainColor : Colors.white70), + onLike: onLike, + 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, + child: Container( + margin: const EdgeInsets.only(top: 8, bottom: 8), + constraints: const BoxConstraints(minHeight: 140), + decoration: BoxDecoration( + color: widget.color, + borderRadius: BorderRadius.circular(20), + border: Border.all( + color: Colors.black, + width: 3, + ), + boxShadow: [ + BoxShadow(color: Colors.grey, spreadRadius: 4, blurRadius: 8) + ]), + child: IntrinsicHeight( + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + ClipRRect( + borderRadius: const BorderRadius.only( + bottomLeft: Radius.circular(18), + topLeft: Radius.circular(18), + ), + 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('блюдо сезона', + style: Theme.of(context) + .textTheme + .bodyMedium + ?.copyWith(color: Colors.black))), + ) + ], + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.all(8.0), + 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.0, right: 16, bottom: 16), + child: GestureDetector( + onTap: () { + setState(() { + isLiked = !isLiked; + }); + widget.onLike?.call(widget.text, isLiked); + }, + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 150), + child: isLiked + ? const Icon( + Icons.favorite, + key: ValueKey(0), + ) + : const Icon(Icons.favorite_border), + key: ValueKey(1)), + ), + ), + ) + ], + ), + ), + ), + ); + } +} diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart new file mode 100644 index 0000000..d967582 --- /dev/null +++ b/lib/presentation/home_page/home_page.dart @@ -0,0 +1,125 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:pmu_project/presentation/details_page/details_page.dart'; + +import '../../domain/models/card.dart'; + +part 'card.dart'; + +const Color mainColor = Colors.deepOrangeAccent; + +class MyHomePage extends StatefulWidget { + const MyHomePage({super.key, required this.title}); + + final String title; + + @override + State createState() => _MyHomePageState(); +} + +void _showSnackBar(BuildContext context, String title, bool isLiked) { + WidgetsBinding.instance.addPostFrameCallback((_) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + isLiked ? "Вкусно" : "Невкусно", + style: Theme.of(context).textTheme.bodyLarge, + ), + backgroundColor: Colors.orangeAccent, + duration: const Duration(seconds: 1), + )); + }); +} + +class _MyHomePageState extends State { + final Color _color = Colors.orangeAccent; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + leading: Icon(Icons.abc_rounded), + backgroundColor: mainColor, + title: Text(widget.title), + ), + body: const Body(), + ); + } +} + +class Body extends StatelessWidget { + const Body({super.key}); + + @override + Widget build(BuildContext context) { + final data = [ + CardData( + 'Рулет из баклажанов', + descriprionText: 'рулет из баклажанов, чеснока и сыра', + weight: 300, + imageUrl: + 'https://kolyda.ru/d/baklazhanchiki_farshirovannye_orehami.jpg', + ), + CardData( + 'Лагман', + descriprionText: 'Суп из говядины и овощей', + isTop: true, + weight: 250, + imageUrl: 'https://avatars.mds.yandex.net/get-altay/5257938/2' + 'a0000018aa4c0859fe7c036bfa6312e4732/XXL_height', + ), + CardData( + 'Манты', + descriprionText: 'Это пельмени. Большие.', + weight: 250, + imageUrl: + 'https://chaihana-zamzam.ru/wp-content/uploads/2022/10/Mantu.jpg', + ), + CardData( + 'Свиной шашлык', + descriprionText: 'Осторожно ! Свинина !', + isTop: true, + weight: 300, + imageUrl: + 'https://avatars.mds.yandex.net/get-altay/9686455/2a0000018a4892e137bca9e41256a79d2c7a/orig', + icon: Icons.warning, + ), + CardData( + 'Куриный шашлык', + descriprionText: 'Халяль', + weight: 300, + imageUrl: + 'https://i.pinimg.com/originals/2f/b5/7e/2fb57efeac571775d423ad995e5c1e1d.jpg', + ), + ]; + + return Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: data + .map( + (e) => _Card.fromData( + e, + onLike: (String title, bool isLiked) => + _showSnackBar(context, title, isLiked), + onTap: () => _navToDetails(context, e), + ), + ) + .toList(), + ), + ), + ); + } +} + +void _navToDetails(BuildContext context, CardData data) { + Navigator.push( + context, + CupertinoPageRoute(builder: (context) => DetailsPage(data)), + ); +}