121 lines
4.6 KiB
Dart
121 lines
4.6 KiB
Dart
import 'package:flutter/material.dart';
|
||
import 'main_screen.dart';
|
||
|
||
/// Модель ответа от сервера с результатами распознавания
|
||
class ApiResponse {
|
||
final Map<String, String> results; // Вероятности и названия пород
|
||
final List<BreedImages> images; // Изображения для каждой породы
|
||
|
||
ApiResponse({required this.results, required this.images});
|
||
|
||
/// Фабричный метод для преобразования JSON в объект ApiResponse
|
||
factory ApiResponse.fromJson(Map<String, dynamic> json) {
|
||
return ApiResponse(
|
||
results: Map<String, String>.from(json['results']),
|
||
images: List<BreedImages>.from(
|
||
json['images'].map((x) => BreedImages.fromJson(x)),
|
||
),
|
||
);
|
||
}
|
||
}
|
||
|
||
/// Модель для хранения изображений конкретной породы
|
||
class BreedImages {
|
||
final String name; // Название породы
|
||
final List<String> url; // Список URL изображений
|
||
|
||
BreedImages({required this.name, required this.url});
|
||
|
||
/// Фабричный метод для преобразования JSON в объект BreedImages
|
||
factory BreedImages.fromJson(Map<String, dynamic> json) {
|
||
return BreedImages(
|
||
name: json['name'],
|
||
url: List<String>.from(json['url'].map((x) => x)),
|
||
);
|
||
}
|
||
}
|
||
|
||
/// Экран отображения результатов распознавания
|
||
class ResultScreen extends StatelessWidget {
|
||
final List<double> probabilities; // Список вероятностей
|
||
final List<String> breeds; // Список названий пород
|
||
final List<String> images; // Список путей к изображениям
|
||
|
||
const ResultScreen({
|
||
super.key,
|
||
required this.probabilities,
|
||
required this.breeds,
|
||
required this.images,
|
||
}) : assert( // Проверка согласованности данных
|
||
probabilities.length == breeds.length &&
|
||
breeds.length == images.length,
|
||
'Все списки должны иметь одинаковую длину',
|
||
);
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
return Scaffold(
|
||
appBar: AppBar(
|
||
title: const Text('Результаты распознавания'),
|
||
leading: IconButton(
|
||
icon: const Icon(Icons.arrow_back),
|
||
onPressed: () => Navigator.pushAndRemoveUntil(
|
||
context,
|
||
MaterialPageRoute(builder: (context) => MainScreen()),
|
||
(route) => false,
|
||
),
|
||
),
|
||
),
|
||
body: ListView.builder(
|
||
itemCount: breeds.length,
|
||
itemBuilder: (context, index) {
|
||
return Card(
|
||
margin: const EdgeInsets.all(8.0),
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(12.0),
|
||
child: Row(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
// Контейнер для отображения миниатюры изображения породы
|
||
Container(
|
||
width: 80,
|
||
height: 80,
|
||
decoration: BoxDecoration(
|
||
borderRadius: BorderRadius.circular(8.0),
|
||
image: DecorationImage(
|
||
image: NetworkImage(
|
||
'https://xn-----6kcp3cadbabfh8a0a.xn--p1ai/beerds/${images[index]}',
|
||
),
|
||
fit: BoxFit.cover,
|
||
),
|
||
),
|
||
),
|
||
const SizedBox(width: 16),
|
||
// Колонка с информацией о породе
|
||
Expanded(
|
||
child: Column(
|
||
crossAxisAlignment: CrossAxisAlignment.start,
|
||
children: [
|
||
// Название породы
|
||
Text(
|
||
breeds[index],
|
||
style: Theme.of(context).textTheme.titleLarge,
|
||
),
|
||
const SizedBox(height: 4),
|
||
// Вероятность в процентах
|
||
Text(
|
||
'Вероятность: ${(probabilities[index] * 100).toStringAsFixed(1)}%',
|
||
style: Theme.of(context).textTheme.bodyLarge,
|
||
),
|
||
],
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
},
|
||
),
|
||
);
|
||
}
|
||
} |