laba 5
This commit is contained in:
parent
50c1b3600e
commit
2acfc62ea2
107
lib/card_item.dart
Normal file
107
lib/card_item.dart
Normal file
@ -0,0 +1,107 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class CardItem extends StatefulWidget {
|
||||
final String suit;
|
||||
final String value;
|
||||
final String imageUrl;
|
||||
|
||||
const CardItem({required this.suit, required this.value, required this.imageUrl});
|
||||
|
||||
@override
|
||||
_CardItemState createState() => _CardItemState();
|
||||
}
|
||||
|
||||
class _CardItemState extends State<CardItem> {
|
||||
bool isLiked = false;
|
||||
|
||||
void _toggleLike() {
|
||||
setState(() {
|
||||
isLiked = !isLiked;
|
||||
});
|
||||
|
||||
final snackBar = SnackBar(
|
||||
content: Text(isLiked ? 'Вы поставили лайк!' : 'Вы убрали лайк!'),
|
||||
);
|
||||
|
||||
ScaffoldMessenger.of(context).showSnackBar(snackBar);
|
||||
}
|
||||
|
||||
void _showDetails(BuildContext context) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
title: Text('${widget.value} из ${widget.suit}'),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Image.network(widget.imageUrl),
|
||||
SizedBox(height: 10),
|
||||
Text('Это карта ${widget.value} из масти ${widget.suit}.'),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(context).pop(),
|
||||
child: Text('Закрыть'),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => _showDetails(context),
|
||||
child: Container(
|
||||
width: 150,
|
||||
child: Card(
|
||||
|
||||
color: Colors.grey[300],
|
||||
margin: EdgeInsets.all(10),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(1),
|
||||
child: Container(
|
||||
height: 150,
|
||||
|
||||
child: Image.network(
|
||||
widget.imageUrl,
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
Text(
|
||||
'${widget.value} из ${widget.suit}',
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold),
|
||||
),
|
||||
SizedBox(height: 5),
|
||||
AnimatedSwitcher(
|
||||
duration: const Duration(milliseconds: 300),
|
||||
child: IconButton(
|
||||
key: ValueKey<bool>(isLiked),
|
||||
icon: Icon(
|
||||
isLiked ? Icons.favorite : Icons.favorite_border,
|
||||
color: isLiked ? Colors.red : null,
|
||||
),
|
||||
onPressed: _toggleLike,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
15
lib/card_model.dart
Normal file
15
lib/card_model.dart
Normal file
@ -0,0 +1,15 @@
|
||||
class CardModel {
|
||||
final String suit;
|
||||
final String value;
|
||||
final String imageUrl;
|
||||
|
||||
CardModel({required this.suit, required this.value, required this.imageUrl});
|
||||
|
||||
factory CardModel.fromJson(Map<String, dynamic> json) {
|
||||
return CardModel(
|
||||
suit: json['suit'],
|
||||
value: json['value'],
|
||||
imageUrl: json['image'],
|
||||
);
|
||||
}
|
||||
}
|
19
lib/card_repository.dart
Normal file
19
lib/card_repository.dart
Normal file
@ -0,0 +1,19 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'card_model.dart';
|
||||
|
||||
class CardRepository {
|
||||
Future<List<CardModel>> fetchCards() async {
|
||||
final response = await http.get(Uri.parse('https://deckofcardsapi.com/api/deck/new/draw/?count=5'));
|
||||
|
||||
if (response.statusCode == 200) {
|
||||
final data = json.decode(response.body);
|
||||
List<CardModel> cards = (data['cards'] as List)
|
||||
.map((card) => CardModel.fromJson(card))
|
||||
.toList();
|
||||
return cards;
|
||||
} else {
|
||||
throw Exception('Ошибка загрузки карт');
|
||||
}
|
||||
}
|
||||
}
|
133
lib/main.dart
133
lib/main.dart
@ -1,4 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'card_repository.dart';
|
||||
import 'card_item.dart';
|
||||
import 'card_model.dart'; // Убедитесь, что этот импорт присутствует
|
||||
|
||||
void main() {
|
||||
runApp(MyApp());
|
||||
@ -8,7 +11,7 @@ class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'Card List',
|
||||
title: 'Card App',
|
||||
theme: ThemeData(
|
||||
primarySwatch: Colors.blue,
|
||||
),
|
||||
@ -17,71 +20,83 @@ class MyApp extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
class CardListScreen extends StatelessWidget {
|
||||
final List<Map<String, String>> items = [
|
||||
{
|
||||
'title': 'Москва-сити',
|
||||
'description': 'ул. Пресненская Набережная, 6.',
|
||||
'image': 'https://avatars.mds.yandex.net/i?id=3b3ba2410de1f807162074752fa01cbf8b8f75ed-4507796-images-thumbs&n=13'
|
||||
},
|
||||
{
|
||||
'title': 'Красная площадь',
|
||||
'description': 'ул. Тверская, д. 10.',
|
||||
'image': 'https://avatars.mds.yandex.net/i?id=855279ca345f259516f990bd24c62645cc8eab24-4012351-images-thumbs&n=13'
|
||||
},
|
||||
{
|
||||
'title': 'ГУМ',
|
||||
'description': 'Красная площадь, 3.',
|
||||
'image': 'https://avatars.mds.yandex.net/i?id=471812ce52e0416c0172e2ad2df2de66a7601625-13101691-images-thumbs&n=13'
|
||||
},
|
||||
];
|
||||
class CardListScreen extends StatefulWidget {
|
||||
@override
|
||||
_CardListScreenState createState() => _CardListScreenState();
|
||||
}
|
||||
|
||||
class _CardListScreenState extends State<CardListScreen> {
|
||||
List<CardModel> cards = [];
|
||||
List<CardModel> filteredCards = [];
|
||||
bool isLoading = true;
|
||||
String searchQuery = '';
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
fetchCards();
|
||||
}
|
||||
|
||||
Future<void> fetchCards() async {
|
||||
final repository = CardRepository();
|
||||
try {
|
||||
final fetchedCards = await repository.fetchCards();
|
||||
setState(() {
|
||||
cards = fetchedCards;
|
||||
filteredCards = cards;
|
||||
isLoading = false;
|
||||
});
|
||||
} catch (e) {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void filterCards(String query) {
|
||||
setState(() {
|
||||
searchQuery = query;
|
||||
filteredCards = cards.where((card) {
|
||||
return card.value.toLowerCase().contains(query.toLowerCase()) ||
|
||||
card.suit.toLowerCase().contains(query.toLowerCase());
|
||||
}).toList();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('Куда сходить в Москве'),
|
||||
|
||||
),
|
||||
body: GridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2, // Количество колонок
|
||||
crossAxisSpacing: 10, // Расстояние между колонками
|
||||
mainAxisSpacing: 10, // Расстояние между строками
|
||||
),
|
||||
itemCount: items.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Card(
|
||||
color: Colors.grey[300],
|
||||
margin: EdgeInsets.all(10),
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(15),
|
||||
),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0), // Уменьшение отступов
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min, // Заставляет карточку занимать минимальный размер
|
||||
children: [
|
||||
Expanded(
|
||||
child: Image.network(
|
||||
items[index]['image']!,
|
||||
fit: BoxFit.cover, // Подгоняет изображение по размеру
|
||||
),
|
||||
),
|
||||
SizedBox(height: 5), // Отступ между изображением и текстом
|
||||
Text(
|
||||
items[index]['title']!,
|
||||
style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold), // Увеличение размера текста
|
||||
),
|
||||
SizedBox(height: 5), // Отступ между заголовком и описанием
|
||||
Text(
|
||||
items[index]['description']!,
|
||||
style: TextStyle(fontSize: 14), // Увеличение размера текста
|
||||
textAlign: TextAlign.center, // Центрирование текста
|
||||
),
|
||||
],
|
||||
title: Text('Колода карт'),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size.fromHeight(50.0),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: TextField(
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Поиск по значению или масти',
|
||||
border: OutlineInputBorder(),
|
||||
),
|
||||
onChanged: filterCards,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: isLoading
|
||||
? Center(child: CircularProgressIndicator())
|
||||
: GridView.builder(
|
||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
||||
crossAxisCount: 2,
|
||||
childAspectRatio: 1.9,
|
||||
),
|
||||
itemCount: filteredCards.length,
|
||||
itemBuilder: (context, index) {
|
||||
final card = filteredCards[index];
|
||||
return CardItem(
|
||||
suit: card.suit,
|
||||
value: card.value,
|
||||
imageUrl: card.imageUrl,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
24
pubspec.lock
24
pubspec.lock
@ -75,6 +75,22 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
http:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: http
|
||||
sha256: "5895291c13fa8a3bd82e76d5627f69e0d85ca6a30dcac95c4ea19a5d555879c2"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.13.6"
|
||||
http_parser:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: http_parser
|
||||
sha256: "2aa08ce0341cc9b354a498388e30986515406668dbcc4f7c950c3e715496693b"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "4.0.2"
|
||||
leak_tracker:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -192,6 +208,14 @@ packages:
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.7.2"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: typed_data
|
||||
sha256: facc8d6582f16042dd49f2463ff1bd6e2c9ef9f3d5da3d9b087e244a7b564b3c
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.3.2"
|
||||
vector_math:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -28,10 +28,14 @@ environment:
|
||||
# the latest version available on pub.dev. To see which dependencies have newer
|
||||
# versions available, run `flutter pub outdated`.
|
||||
dependencies:
|
||||
http: ^0.13.3 # или другая актуальная версия
|
||||
flutter:
|
||||
sdk: flutter
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
# Use with the CupertinoIcons class for iOS style icons.
|
||||
cupertino_icons: ^1.0.8
|
||||
|
@ -13,7 +13,7 @@ import 'package:untitled/main.dart';
|
||||
void main() {
|
||||
testWidgets('Counter increments smoke test', (WidgetTester tester) async {
|
||||
// Build our app and trigger a frame.
|
||||
await tester.pumpWidget(const MyApp());
|
||||
await tester.pumpWidget(MyApp());
|
||||
|
||||
// Verify that our counter starts at 0.
|
||||
expect(find.text('0'), findsOneWidget);
|
||||
|
Loading…
Reference in New Issue
Block a user