From 9b20eedc96abeaebbde7612d4f4e7552e0cc44ce Mon Sep 17 00:00:00 2001 From: Kirill <117719052+KirillFirsof@users.noreply.github.com> Date: Wed, 20 Nov 2024 13:52:33 +0400 Subject: [PATCH] lab3_4 ready --- lib/main.dart | 2 +- lib/models/card.dart | 15 ++ .../details_page/details_page.dart | 59 ++++++ lib/presentaition/home_page/card.dart | 173 ++++++++++++++++++ lib/presentaition/home_page/home_page.dart | 124 +++++++++++++ 5 files changed, 372 insertions(+), 1 deletion(-) create mode 100644 lib/presentaition/details_page/details_page.dart diff --git a/lib/main.dart b/lib/main.dart index b07de57..8806f86 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:project1/presentation/home_page/home_page.dart'; +import 'package:testlab/presentaition/home_page/home_page.dart'; void main() { runApp(const MyApp()); diff --git a/lib/models/card.dart b/lib/models/card.dart index e69de29..07f7bb9 100644 --- a/lib/models/card.dart +++ b/lib/models/card.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; + +class CardData { + final String text; + final String descriptionText; + final IconData icon; + final String? imageUrl; + + CardData( + this.text, { + required this.descriptionText, + this.icon = Icons.cake, + this.imageUrl, + }); +} \ No newline at end of file diff --git a/lib/presentaition/details_page/details_page.dart b/lib/presentaition/details_page/details_page.dart new file mode 100644 index 0000000..d59df1a --- /dev/null +++ b/lib/presentaition/details_page/details_page.dart @@ -0,0 +1,59 @@ +import 'package:flutter/material.dart'; +import 'package:testlab/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( + backgroundColor: Colors.grey.shade600, + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.all( 16.0), + child: ClipRRect( + borderRadius: BorderRadius.circular(15), + child: Image.network( + data.imageUrl ?? '', + width: double.infinity, + fit: BoxFit.cover, + ), + ), + ), + Padding( + padding: const EdgeInsets.all(5.0), + child: Center( + child: Text( + data.text, + style: const TextStyle( + color: Colors.white, + fontSize: 22, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.all(5.0), + child: Center( + child: Text( + data.descriptionText, + style: const TextStyle( + color: Colors.white, + fontSize: 18, + ), + ) + ), + ), + ], + ), + backgroundColor: Colors.black, + ); + } +} \ No newline at end of file diff --git a/lib/presentaition/home_page/card.dart b/lib/presentaition/home_page/card.dart index e69de29..c6473df 100644 --- a/lib/presentaition/home_page/card.dart +++ b/lib/presentaition/home_page/card.dart @@ -0,0 +1,173 @@ +part of 'home_page.dart'; + +typedef OnLikeCallback = void Function(String title, bool isLiked)?; + +class _Card extends StatefulWidget { + final String text; + final String descriptionText; + final IconData icon; + final String? imageUrl; + final OnLikeCallback onLike; + final VoidCallback? onTap; + + const _Card( + this.text, { + this.icon = Icons.catching_pokemon, + required this.descriptionText, + this.imageUrl, + this.onLike, + this.onTap, + }); + + factory _Card.fromData( + CardData data, { + OnLikeCallback onLike, + VoidCallback? onTap, + }) => + _Card( + data.text, + descriptionText: data.descriptionText, + icon: data.icon, + imageUrl: data.imageUrl, + onLike: onLike, + onTap: onTap, + ); + + @override + State<_Card> createState() => _CardState(); +} + +class _CardState extends State<_Card> { + bool isLiked = false; + + @override + Widget build(BuildContext context) { + return GestureDetector( + onLongPress: widget.onTap, + onDoubleTap: () { + setState(() { + isLiked = !isLiked; + }); + widget.onLike?.call(widget.text, isLiked); + }, + child: Container( + margin: const EdgeInsets.all(16), + constraints: const BoxConstraints(minHeight: 170), + decoration: BoxDecoration( + color: Colors.grey, + borderRadius: BorderRadius.circular(20), + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(.5), + spreadRadius: 4, + offset: const Offset(0, 5), + blurRadius: 8, + ), + ], + ), + child: IntrinsicHeight( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 10, + top: 10, + right: 3, + bottom: 10 + ), + child: ClipRRect( + borderRadius: BorderRadius.circular(15), + child: SizedBox( + height: double.infinity, + width: 150, + child: Image.network( + widget.imageUrl ?? '', + fit: BoxFit.cover, + errorBuilder: (_, __, ___) => const Placeholder(), + ), + ), + ), + ), + + Expanded( + child: Stack( + children: [ + Align( + alignment: Alignment.bottomLeft, + child: Padding( + padding: const EdgeInsets.only( + left: 8.0, + right: 8.0, + bottom: 16.0, + ), + child: Icon( + widget.icon, + ), + ), + ), + + Padding( + padding: const EdgeInsets.only(left: 3.0, top: 3.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.text, + style: const TextStyle( + color: Colors.white, + fontSize: 14, + fontWeight: FontWeight.bold, + ), + ), + Text( + widget.descriptionText, + style: const TextStyle( + color: Colors.white, + fontSize: 13, + ), + ), + ] + ), + ), + ], + ) + ), + Align( + alignment: Alignment.bottomRight, + child: Padding( + padding: const EdgeInsets.only( + left: 8.0, + right: 16.0, + bottom: 16.0, + ), + child: GestureDetector( + onTap: () { + setState(() { + isLiked = !isLiked; + }); + widget.onLike?.call(widget.text, isLiked); + }, + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 300), + child: isLiked + ? const Icon( + Icons.thumb_up, + color: Colors.redAccent, + key: ValueKey(0), + ) + : const Icon( + Icons.thumb_up_off_alt, + key: ValueKey(1), + ), + ), + ), + ), + ), + ], + ), + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/presentaition/home_page/home_page.dart b/lib/presentaition/home_page/home_page.dart index e69de29..9cb0037 100644 --- a/lib/presentaition/home_page/home_page.dart +++ b/lib/presentaition/home_page/home_page.dart @@ -0,0 +1,124 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:testlab/models/card.dart'; +import 'package:testlab/presentaition/details_page/details_page.dart'; + +part 'card.dart'; + +class MyHomePage extends StatefulWidget { + const MyHomePage({super.key, required this.title}); + + final String title; + + @override + State createState() => _MyHomePageState(); +} + +class _MyHomePageState extends State { + final Color _color = Colors.grey.shade600; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return Scaffold( + backgroundColor: Colors.black, + appBar: AppBar( + backgroundColor: _color, + title: Text( + widget.title, + style: const TextStyle( + color: Colors.white, + fontSize: 20, + ), + ), + ), + body: const Body(), + ); + } +} + +class Body extends StatelessWidget { + const Body({super.key}); + + @override + Widget build(BuildContext context) { + final data = [ + CardData( + 'Mobile dev', + descriptionText: 'И когда ты успел стать экспертом в мобильной разработке?', + imageUrl: + 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcQtsv2O-lLpxro9HH9CUejcymOOnGdQJwjasg&s', + ), + CardData( + 'Грустный кот', + descriptionText: 'Котик грустит, аж плачет', + icon: Icons.star, + imageUrl: + 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcT--ZMDGsa_8y9r9u0RjAn576ajsVVfsOIcDA&s', + ), + CardData( + 'Веселый кот', + descriptionText: 'Котик стал очень веселый, аж улыбается', + icon: Icons.work, + imageUrl: + 'https://img-webcalypt.ru/storage/memes/YhGTdxW7HnbmhqAd37XjsMCTj1fHUW7AADagYMDbmyU9VBEhDBbq4d3XNGDWo34FibwtjyeVsyxudpzeViSmHdJ7e6C50tLbZnkZZAP81AV7aM0R8VSi4YEnqgcZ1EtE-md.jpeg', + ), + CardData( + 'Кот накачаля', + descriptionText: 'Кот накачался, аж широкий', + icon: Icons.question_answer, + imageUrl: + 'https://s00.yaplakal.com/pics/pics_original/9/1/8/11586819.jpg', + ), + CardData( + 'Кот крутой', + descriptionText: 'Кот стал очень крутым, аж в очках', + icon: Icons.favorite_border, + imageUrl: + 'https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSmwxp_mc1c8Rukc6Dg4GLNv1JLZbO7DKqF4w&s', + ), + ]; + return Center( + child: SingleChildScrollView( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: data.map((data) { + return _Card.fromData( + data, + onLike: (String title, bool isLiked) => + _showSnackBar(context, title, isLiked), + onTap: () => _navToDetails(context, data), + ); + }).toList(), + ), + ), + ); + } + + void _navToDetails(BuildContext context, CardData data) { + Navigator.push( + context, + CupertinoPageRoute(builder: (context) => DetailsPage(data)), + ); + } + + void _showSnackBar(BuildContext context, String title, bool isLiked) { + WidgetsBinding.instance.addPostFrameCallback((_) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + 'You ${isLiked ? 'like!' : 'disliked :('} $title ', + style: const TextStyle( + color: Colors.white, + fontSize: 18, + fontWeight: FontWeight.bold, + ), + ), + backgroundColor: Colors.black, + duration: const Duration(seconds: 1), + )); + }); + }} \ No newline at end of file