Files
Dino-Field-Guide/lib/screens/detail_screen.dart
T
2026-04-24 23:31:40 -05:00

112 lines
5.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../models/dinosaur.dart';
import '../providers/dino_provider.dart';
class DetailScreen extends StatelessWidget {
final Dinosaur dinosaur;
const DetailScreen({super.key, required this.dinosaur});
@override
Widget build(BuildContext context) {
final provider = Provider.of<DinoProvider>(context);
return Scaffold(
appBar: AppBar(
actions: [
IconButton(
icon: Icon(provider.isFavorite(dinosaur.name) ? Icons.favorite : Icons.favorite_border, color: provider.isFavorite(dinosaur.name) ? Colors.red : null),
onPressed: () => provider.toggleFavorite(dinosaur.name),
)
],
),
body: SingleChildScrollView(
child: Column(
children: [
Hero(tag: dinosaur.name, child: Container(height: 250, width: double.infinity, padding: const EdgeInsets.all(20), child: Image.asset(dinosaur.imagePath, fit: BoxFit.contain, errorBuilder: (_,__,___) => const Icon(Icons.pets, size: 80)))),
Padding(
padding: const EdgeInsets.all(20),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(dinosaur.name, style: const TextStyle(fontSize: 32, fontWeight: FontWeight.bold)),
Text(dinosaur.pronunciation, style: const TextStyle(fontStyle: FontStyle.italic, color: Colors.green)),
const SizedBox(height: 20),
// Bento Box with dynamic units
GridView.count(
shrinkWrap: true, physics: const NeverScrollableScrollPhysics(),
crossAxisCount: 2, childAspectRatio: 2.5, mainAxisSpacing: 10, crossAxisSpacing: 10,
children: [
_buildTile("DIET", dinosaur.dietType, Icons.restaurant),
_buildTile("LENGTH", provider.formatLength(dinosaur.lengthMeters), Icons.straighten),
_buildTile("LOCOMOTION", dinosaur.locomotion, Icons.directions_run),
_buildTile("WEIGHT", provider.formatWeight(dinosaur.weightKg), Icons.scale),
],
),
const SizedBox(height: 30),
_buildTimeline(dinosaur.periodIndex),
const SizedBox(height: 30),
_buildCladogram(provider, context),
const SizedBox(height: 30),
const Text("FIELD NOTES", style: TextStyle(fontWeight: FontWeight.bold, letterSpacing: 1.2)),
const Divider(),
Text("Meaning: ${dinosaur.meaning}", style: const TextStyle(fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
Text(dinosaur.description, style: const TextStyle(fontSize: 16, height: 1.6)),
const SizedBox(height: 40),
],
),
),
],
),
),
);
}
Widget _buildTimeline(int periodIndex) {
final List<String> eras = ["Triassic", "Jurassic", "Cretaceous"];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const Text("GEOLOGICAL TIMELINE", style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
Row(children: List.generate(3, (i) => Expanded(child: Container(
height: 35, margin: const EdgeInsets.symmetric(horizontal: 2),
decoration: BoxDecoration(color: i == periodIndex ? Colors.green : Colors.grey.withValues(alpha: 0.1), borderRadius: BorderRadius.circular(8)),
child: Center(child: Text(eras[i], style: TextStyle(fontSize: 10, color: i == periodIndex ? Colors.white : Colors.grey))),
)))),
],
);
}
Widget _buildCladogram(DinoProvider p, BuildContext context) {
final related = p.getRelated(dinosaur);
if (related.isEmpty) return const SizedBox();
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text("RELATED SPECIES (${dinosaur.family})", style: const TextStyle(fontSize: 12, fontWeight: FontWeight.bold)),
const SizedBox(height: 10),
SizedBox(height: 100, child: ListView.builder(
scrollDirection: Axis.horizontal,
itemCount: related.length,
itemBuilder: (context, i) => GestureDetector(
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => DetailScreen(dinosaur: related[i]))),
child: Container(width: 80, margin: const EdgeInsets.only(right: 15), child: Column(children: [Expanded(child: Image.asset(related[i].imagePath, errorBuilder: (_,__,___) => const Icon(Icons.pets))), Text(related[i].name, style: const TextStyle(fontSize: 9), textAlign: TextAlign.center)]))
)
))
],
);
}
Widget _buildTile(String label, String val, IconData icon) {
return Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(color: Colors.grey.withValues(alpha: 0.05), borderRadius: BorderRadius.circular(12)),
child: Row(children: [Icon(icon, size: 20, color: Colors.green), const SizedBox(width: 8), Expanded(child: Column(crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: [Text(label, style: const TextStyle(fontSize: 9, color: Colors.grey)), Text(val, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 12))]))]),
);
}
}