diff --git a/lib/domain/models/card_data.dart b/lib/domain/models/card_data.dart new file mode 100644 index 0000000..9a6dd2d --- /dev/null +++ b/lib/domain/models/card_data.dart @@ -0,0 +1,6 @@ +class CardData { + final String name; + final double price; + + CardData({required this.name, required this.price}); +} diff --git a/lib/main.dart b/lib/main.dart index 67bca32..af78b5b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:lab/presentation/home_page/home_page.dart'; void main() { runApp(const MyApp()); @@ -21,93 +22,3 @@ 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( - backgroundColor: Theme.of(context).colorScheme.inversePrimary, - title: Text(widget.title), - ), - body: Padding( - padding: const EdgeInsets.all(30), - child: ListView.separated( - itemBuilder: (context, index) => - Card(name: "test $index", price: 11.0), - separatorBuilder: (context, index) => const SizedBox(height: 20), - itemCount: 2, - ))); - } -} - -class Card extends StatefulWidget { - const Card({super.key, required this.name, required this.price}); - - final String name; - final double price; - - @override - State createState() => _CardState(); -} - -class _CardState extends State { - bool _isFavourite = true; - - void toggleIsFavourite() { - setState(() { - _isFavourite = !_isFavourite; - }); - } - - @override - Widget build(BuildContext context) { - return Stack( - children: [ - Container( - padding: const EdgeInsets.only(top: 50, bottom: 15, left: 40, right: 40), - decoration: BoxDecoration( - border: Border.all(color: Colors.black12, width: 2), - borderRadius: BorderRadius.circular(20)), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Center( - child: Image.network( - "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTtAT11wKgHrJBUYzIBFogucXg0a9fE0fQXDQ&s"), - ), - Padding( - padding: EdgeInsets.only(top: 50), - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text(widget.name, style: TextStyle(fontSize: 17)), - Text("${widget.price} Руб", - style: TextStyle(fontSize: 17, color: Colors.orange)) - ], - ), - ) - ], - ), - ), - Positioned( - right: 10, - top: 10, - child: IconButton( - icon: Icon(_isFavourite ? Icons.favorite : Icons.favorite_border), - color: Colors.red, - onPressed: toggleIsFavourite, - ) - ) - ], - ); - } -} diff --git a/lib/presentation/details_page/details_page.dart b/lib/presentation/details_page/details_page.dart new file mode 100644 index 0000000..7e0315f --- /dev/null +++ b/lib/presentation/details_page/details_page.dart @@ -0,0 +1,38 @@ +import 'package:flutter/material.dart'; +import 'package:lab/domain/models/card_data.dart'; + +class DetailsPage extends StatelessWidget { + final CardData data; + + const DetailsPage({super.key, required this.data}); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + title: Text('Product ${data.name}'), + ), + body: SingleChildScrollView( + padding: const EdgeInsets.all(30), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Center( + child: Image.network( + "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTtAT11wKgHrJBUYzIBFogucXg0a9fE0fQXDQ&s"), + ), + const SizedBox(height: 20), + Text( + "Цена: ${data.price} Руб", + style: const TextStyle(fontSize: 25, color: Colors.orange), + ), + const Text( + "Описание: some text some text some text some text some text some text some text some text ", + style: TextStyle(fontSize: 18), + ), + ], + ), + ), + ); + } +} diff --git a/lib/presentation/home_page/card.dart b/lib/presentation/home_page/card.dart new file mode 100644 index 0000000..9afebaa --- /dev/null +++ b/lib/presentation/home_page/card.dart @@ -0,0 +1,99 @@ +part of "home_page.dart"; + +typedef OnLikeFunction = void Function(String text); + +class _Card extends StatefulWidget { + final String name; + final double price; + + final OnLikeFunction? onLike; + final VoidCallback? onTap; + + const _Card( + {required this.name, + required this.price, + this.onLike, + this.onTap}); + + factory _Card.fromData( + CardData data, OnLikeFunction? onLike, VoidCallback? onTap) => + _Card( + name: data.name, + price: data.price, + onTap: onTap, + onLike: onLike, + ); + + @override + State createState() => _CardState(); +} + +class _CardState extends State<_Card> { + bool _isFavourite = false; + + void toggleIsFavourite() { + setState(() { + _isFavourite = !_isFavourite; + }); + widget.onLike?.call(_isFavourite + ? "Product added in favourite" + : "Product deleted from favourite"); + } + + @override + Widget build(BuildContext context) { + return GestureDetector( + onTap: widget.onTap, + child: Container( + width: double.infinity, + padding: + const EdgeInsets.only(top: 15, bottom: 15, left: 30, right: 30), + decoration: BoxDecoration( + border: Border.all(color: Colors.black12, width: 2), + borderRadius: BorderRadius.circular(20)), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + children: [ + GestureDetector( + onTap: toggleIsFavourite, + child: AnimatedSwitcher( + duration: const Duration(milliseconds: 200), + child: _isFavourite + ? const Icon( + Icons.favorite, + color: Colors.red, + key: ValueKey(0), + ) + : const Icon( + Icons.favorite_border, + color: Colors.red, + key: ValueKey(1), + ), + ), + ) + ], + ), + Center( + child: Image.network( + "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTtAT11wKgHrJBUYzIBFogucXg0a9fE0fQXDQ&s"), + ), + Padding( + padding: const EdgeInsets.only(top: 50), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text(widget.name, style: const TextStyle(fontSize: 17)), + Text("${widget.price} Руб", + style: const TextStyle(fontSize: 17, color: Colors.orange)) + ], + ), + ) + ], + ), + ), + ); + } +} diff --git a/lib/presentation/home_page/home_page.dart b/lib/presentation/home_page/home_page.dart new file mode 100644 index 0000000..de14891 --- /dev/null +++ b/lib/presentation/home_page/home_page.dart @@ -0,0 +1,67 @@ +import 'package:flutter/cupertino.dart'; +import 'package:flutter/material.dart'; +import 'package:lab/domain/models/card_data.dart'; +import 'package:lab/presentation/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 { + void _showSnackBar(BuildContext context, String text) { + WidgetsBinding.instance.addPostFrameCallback((_) { + ScaffoldMessenger.of(context).showSnackBar(SnackBar( + content: Text(text), + duration: const Duration(seconds: 2), + backgroundColor: Colors.black54, + )); + }); + } + + void _navigateToDetailsPage(BuildContext context, CardData data) { + Navigator.push( + context, + CupertinoPageRoute(builder: (context) => DetailsPage(data: data)), + ); + } + + final cards = [ + CardData(name: "test 0", price: 11.0), + CardData(name: "test 1", price: 22.0) + ]; + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + backgroundColor: Theme.of(context).colorScheme.inversePrimary, + title: Text(widget.title), + ), + body: SingleChildScrollView( + padding: const EdgeInsets.all(30), + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + children: cards.map((cardData) { + return Column( + children: [ + _Card.fromData( + cardData, + (String text) => _showSnackBar(context, text), + () => _navigateToDetailsPage(context, cardData), + ), + const SizedBox(height: 20) + ], + ); + }).toList(), + ), + ), + ); + } +}