From fbd70f10bda62aed3394a8164bbe02469a92f1fe Mon Sep 17 00:00:00 2001 From: DavidMakarov <wshirotame@gmail.com> Date: Fri, 4 Oct 2024 20:36:43 +0400 Subject: [PATCH] add snackBar for liked state, details_page --- lib/domain/models/card.dart | 6 ++ lib/main.dart | 120 +---------------------- lib/views/details_page/details_page.dart | 51 ++++++++++ lib/views/home_page/card.dart | 118 ++++++++++++++++++++++ lib/views/home_page/home_page.dart | 71 ++++++++++++++ 5 files changed, 248 insertions(+), 118 deletions(-) create mode 100644 lib/domain/models/card.dart create mode 100644 lib/views/details_page/details_page.dart create mode 100644 lib/views/home_page/card.dart create mode 100644 lib/views/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..9308ff4 --- /dev/null +++ b/lib/domain/models/card.dart @@ -0,0 +1,6 @@ +class CardData { + final String textData; + final String imageUrl; + + const CardData({required this.textData, required this.imageUrl}); +} diff --git a/lib/main.dart b/lib/main.dart index c4b12cf..9adb4a0 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_project/views/home_page/home_page.dart'; void main() { runApp(const MyApp()); @@ -15,124 +16,7 @@ class MyApp extends StatelessWidget { colorScheme: ColorScheme.fromSeed(seedColor: Colors.lightGreen), useMaterial3: true, ), - home: const MyHomePage(), - ); - } -} - -class MyHomePage extends StatefulWidget { - const MyHomePage({super.key}); - - @override - State<MyHomePage> createState() => _MyHomePageState(); -} - -class _MyHomePageState extends State<MyHomePage> { - List<_CardData> data = [ - _CardData( - textData: "250x150 picture", - imageUrl: "https://loremflickr.com/250/150/kitty"), - _CardData( - textData: "200x250 picture", - imageUrl: "https://loremflickr.com/200/250/kitty"), - _CardData( - textData: "200x200 picture", - imageUrl: "https://loremflickr.com/200/200/kitty"), - _CardData( - textData: "100x150 picture", - imageUrl: "https://loremflickr.com/100/150/kitty"), - _CardData( - textData: "300x150 picture", - imageUrl: "https://loremflickr.com/350/150/kitty"), - ]; - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text( - 'Item list', - ), - ), - body: SingleChildScrollView( - child: Column( - children: data.map((d) => _Card.withData(d)).toList(), - ), - )); - } -} - -class _CardData { - final String textData; - final String imageUrl; - - const _CardData({required this.textData, required this.imageUrl}); -} - -class _Card extends StatelessWidget { - final String text; - final String imageUrl; - - const _Card({required this.text, required this.imageUrl}); - - factory _Card.withData(_CardData d) => _Card( - text: d.textData, - imageUrl: d.imageUrl, - ); - - @override - Widget build(BuildContext context) { - return Padding( - padding: const EdgeInsets.all(8.0), - child: Container( - margin: EdgeInsets.all(5.0), - padding: EdgeInsets.all(8.0), - decoration: BoxDecoration( - boxShadow: [ - BoxShadow( - color: Colors.grey.withOpacity(0.5), - spreadRadius: 3, - offset: const Offset(0, 2), - blurRadius: 4) - ], - color: Theme.of(context).colorScheme.inversePrimary, - borderRadius: BorderRadius.circular(20)), - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ClipRRect( - borderRadius: BorderRadius.circular(20), - child: SizedBox( - width: 150, - height: 150, - child: Image.network( - imageUrl == "" - ? "https://loremflickr.com/150/150?random=1" - : imageUrl, - fit: BoxFit.cover, - ), - ), - ), - Expanded( - child: Padding( - padding: const EdgeInsets.only(left: 16.0, top: 16.0), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - text, - style: Theme.of(context).textTheme.headlineSmall, - ), - Text( - "This is card with picture and text", - style: Theme.of(context).textTheme.labelSmall, - ), - ], - ), - ), - ) - ], - )), + home: const HomePage(), ); } } diff --git a/lib/views/details_page/details_page.dart b/lib/views/details_page/details_page.dart new file mode 100644 index 0000000..9f732d6 --- /dev/null +++ b/lib/views/details_page/details_page.dart @@ -0,0 +1,51 @@ +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( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + ), + body: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Container( + color: Theme.of(context).colorScheme.inversePrimary, + child: Center( + child: Padding( + padding: const EdgeInsets.only(top: 10, bottom: 10), + child: ClipRRect( + borderRadius: BorderRadius.all(Radius.circular(20)), + child: Image.network(data.imageUrl == "" + ? "https://loremflickr.com/150/150?random=1" + : data.imageUrl)), + ), + ), + ), + Padding( + padding: const EdgeInsets.all(10), + child: Text( + data.textData, + style: Theme.of(context).textTheme.headlineLarge, + ), + ), + Padding( + padding: const EdgeInsets.all(10), + child: Text( + "This is card with some picture and provided text", + style: Theme.of(context).textTheme.bodyLarge, + ), + ) + ], + ), + ); + } +} diff --git a/lib/views/home_page/card.dart b/lib/views/home_page/card.dart new file mode 100644 index 0000000..cb28fa8 --- /dev/null +++ b/lib/views/home_page/card.dart @@ -0,0 +1,118 @@ +part of 'home_page.dart'; + +typedef onLikeCallback = void Function(String title, bool isLiked)?; + +class _Card extends StatefulWidget { + final String text; + final String imageUrl; + final onLikeCallback onLike; + final VoidCallback? onTap; + + const _Card( + {required this.text, required this.imageUrl, this.onLike, this.onTap}); + + factory _Card.withData(CardData d, + {onLikeCallback onLike, VoidCallback? onTap}) => + _Card( + text: d.textData, + imageUrl: d.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( + onTap: widget.onTap, + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Container( + margin: EdgeInsets.only(left: 15, top: 10, right: 15), + decoration: BoxDecoration( + boxShadow: [ + BoxShadow( + color: Colors.grey.withOpacity(0.5), + spreadRadius: 3, + offset: const Offset(0, 2), + blurRadius: 4) + ], + color: Theme.of(context).colorScheme.inversePrimary, + borderRadius: BorderRadius.circular(20)), + child: IntrinsicHeight( + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ClipRRect( + borderRadius: BorderRadius.only( + topLeft: Radius.circular(20), + bottomLeft: Radius.circular(20)), + child: SizedBox( + width: 150, + height: 150, + child: Image.network( + widget.imageUrl == "" + ? "https://loremflickr.com/150/150?random=1" + : widget.imageUrl, + fit: BoxFit.cover, + ), + ), + ), + Expanded( + child: Padding( + padding: const EdgeInsets.only(left: 16.0, top: 16.0), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + widget.text, + style: Theme.of(context).textTheme.headlineSmall, + ), + Text( + "This is card with picture and text", + style: Theme.of(context).textTheme.labelSmall, + ), + ], + ), + ), + ), + Column( + children: [ + Padding( + padding: const EdgeInsets.only(top: 16.0, right: 8.0), + child: GestureDetector( + onTap: () { + setState(() { + isLiked = !isLiked; + }); + widget.onLike?.call(widget.text, isLiked); + }, + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 150), + child: isLiked + ? Icon( + Icons.favorite, + key: ValueKey<int>(1), + ) + : Icon( + Icons.favorite_border, + key: ValueKey<int>(0), + ), + ), + ), + ) + ], + ) + ], + ), + )), + ), + ); + } +} diff --git a/lib/views/home_page/home_page.dart b/lib/views/home_page/home_page.dart new file mode 100644 index 0000000..c72e3fc --- /dev/null +++ b/lib/views/home_page/home_page.dart @@ -0,0 +1,71 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_project/domain/models/card.dart'; +import 'package:flutter_project/views/details_page/details_page.dart'; + +part 'card.dart'; + +class HomePage extends StatefulWidget { + const HomePage({super.key}); + + @override + State<HomePage> createState() => _HomePageState(); +} + +class _HomePageState extends State<HomePage> { + List<CardData> data = [ + CardData( + textData: "250x150 picture", + imageUrl: "https://loremflickr.com/250/150/cat"), + CardData( + textData: "200x250 picture", + imageUrl: "https://loremflickr.com/200/250/cat"), + CardData( + textData: "200x200 picture", + imageUrl: "https://loremflickr.com/200/200/cat"), + CardData( + textData: "100x150 picture", + imageUrl: "https://loremflickr.com/100/150/cat"), + CardData( + textData: "300x150 picture", + imageUrl: "https://loremflickr.com/350/150/cat"), + ]; + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: Text( + 'Item list', + ), + ), + body: SingleChildScrollView( + child: Column( + children: data + .map((d) => _Card.withData(d, + onTap: () => _navToDetails(context, d), + onLike: (String title, bool isLiked) => + _showSnackBar(context, isLiked, title))) + .toList(), + ), + )); + } + + void _showSnackBar(BuildContext context, bool isLiked, String title) { + WidgetsBinding.instance.addPostFrameCallback((_) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text( + isLiked ? "You liked $title" : "Like removed from $title", + style: Theme.of(context).textTheme.bodyLarge, + ), + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + duration: const Duration(milliseconds: 1200), + )); + }); + } + + void _navToDetails(BuildContext context, CardData d) { + Navigator.push( + context, CupertinoPageRoute(builder: (context) => DetailsPage(d))); + } +}