Compare commits
8 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
062bc11a69 | ||
|
880c076f6b | ||
|
03821f1260 | ||
|
ec5437699c | ||
|
6bbfbf2586 | ||
|
f1d002f7dc | ||
|
f93387655a | ||
|
79abdf88b7 |
BIN
cart_example.png
Normal file
BIN
cart_example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
6
lib/domain/models/card_data.dart
Normal file
6
lib/domain/models/card_data.dart
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
class CardData {
|
||||||
|
final String name;
|
||||||
|
final double price;
|
||||||
|
|
||||||
|
CardData({required this.name, required this.price});
|
||||||
|
}
|
@ -1,4 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:lab/presentation/home_page/home_page.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
runApp(const MyApp());
|
runApp(const MyApp());
|
||||||
@ -11,58 +12,13 @@ class MyApp extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
title: 'Flutter Demo',
|
title: 'Flutter Demo',
|
||||||
|
debugShowCheckedModeBanner: false,
|
||||||
theme: ThemeData(
|
theme: ThemeData(
|
||||||
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
),
|
),
|
||||||
home: const MyHomePage(title: 'Дьяконов Руслан ПИбд-33'),
|
home: const MyHomePage(title: 'Lab 4: '),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class MyHomePage extends StatefulWidget {
|
|
||||||
const MyHomePage({super.key, required this.title});
|
|
||||||
|
|
||||||
final String title;
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<MyHomePage> createState() => _MyHomePageState();
|
|
||||||
}
|
|
||||||
|
|
||||||
class _MyHomePageState extends State<MyHomePage> {
|
|
||||||
int _counter = 0;
|
|
||||||
|
|
||||||
void _incrementCounter() {
|
|
||||||
setState(() {
|
|
||||||
_counter++;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return Scaffold(
|
|
||||||
appBar: AppBar(
|
|
||||||
backgroundColor: Theme.of(context).colorScheme.inversePrimary,
|
|
||||||
title: Text(widget.title),
|
|
||||||
),
|
|
||||||
body: Center(
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: <Widget>[
|
|
||||||
const Text(
|
|
||||||
'You have pushed the button this many times:',
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
'$_counter',
|
|
||||||
style: Theme.of(context).textTheme.headlineMedium,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
floatingActionButton: FloatingActionButton(
|
|
||||||
onPressed: _incrementCounter,
|
|
||||||
tooltip: 'Increment',
|
|
||||||
child: const Icon(Icons.add),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
41
lib/presentation/details_page/details_page.dart
Normal file
41
lib/presentation/details_page/details_page.dart
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
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",
|
||||||
|
height: 250,
|
||||||
|
width: 250,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
100
lib/presentation/home_page/card.dart
Normal file
100
lib/presentation/home_page/card.dart
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
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<StatefulWidget> 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<int>(0),
|
||||||
|
)
|
||||||
|
: const Icon(
|
||||||
|
Icons.favorite_border,
|
||||||
|
color: Colors.red,
|
||||||
|
key: ValueKey<int>(1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Center(
|
||||||
|
child: Image.network(
|
||||||
|
"https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcTtAT11wKgHrJBUYzIBFogucXg0a9fE0fQXDQ&s",
|
||||||
|
height: 250,
|
||||||
|
width: 250,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
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))
|
||||||
|
],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
67
lib/presentation/home_page/home_page.dart
Normal file
67
lib/presentation/home_page/home_page.dart
Normal file
@ -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<MyHomePage> createState() => _MyHomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MyHomePageState extends State<MyHomePage> {
|
||||||
|
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,
|
||||||
|
onTap: () => _navigateToDetailsPage(context, cardData),
|
||||||
|
onLike: (String text) => _showSnackBar(context, text),
|
||||||
|
),
|
||||||
|
const SizedBox(height: 20)
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}).toList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user