Files
999/lib/screens/lenormand_station_screen.dart

264 lines
8.4 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../models/lenormand_pairs.dart';
import '../services/lenormand_pairs_repository.dart';
import 'lenormand_pair_screen.dart';
class LenormandStationScreen extends StatefulWidget {
final int number;
final LenormandCardEntry? Function(int n)? lookup;
final String title;
const LenormandStationScreen({
super.key,
required this.number,
this.lookup,
this.title = 'Ленорман',
});
@override
State<LenormandStationScreen> createState() => _LenormandStationScreenState();
}
class _LenormandStationScreenState extends State<LenormandStationScreen> {
late int _n;
String _query = '';
@override
void initState() {
super.initState();
_n = widget.number;
}
@override
Widget build(BuildContext context) {
final lookup = widget.lookup ?? (n) => LenormandPairsRepository().byNumber(n);
final card = lookup(_n);
if (card == null) {
return Scaffold(
backgroundColor: const Color(0xFF0C0E1A),
appBar: AppBar(title: Text(widget.title)),
body: const Center(
child: Text('Карта не найдена', style: TextStyle(color: Color(0xFF8C93B8))),
),
);
}
final pairs = card.pairs.where((p) {
if (_query.isEmpty) return true;
final q = _query.toLowerCase();
return p.name.toLowerCase().contains(q) ||
p.preview.toLowerCase().contains(q) ||
'${p.n}'.contains(q);
}).toList();
return Scaffold(
backgroundColor: const Color(0xFF0C0E1A),
appBar: AppBar(
title: Text('${card.n}. ${card.name}'),
),
body: ListView(
padding: const EdgeInsets.fromLTRB(16, 8, 16, 32),
children: [
Row(
children: [
Container(
width: 56,
height: 56,
alignment: Alignment.center,
decoration: BoxDecoration(
color: const Color(0x1AFFD54F),
borderRadius: BorderRadius.circular(14),
border: Border.all(color: const Color(0x4DFFD54F)),
),
child: Text(card.symbol, style: const TextStyle(fontSize: 24)),
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
card.name,
style: const TextStyle(
color: Color(0xFFFFF9C4),
fontWeight: FontWeight.w900,
fontSize: 20,
),
),
if (card.lore.isNotEmpty)
Text(
card.lore,
style: const TextStyle(
color: Color(0xFF90CDF4),
fontSize: 13,
fontWeight: FontWeight.w600,
),
),
],
),
),
],
),
const SizedBox(height: 18),
const _SectionTitle('Значение'),
const SizedBox(height: 8),
Text(
card.displayMeaning,
style: const TextStyle(color: Color(0xFFD1D5DB), fontSize: 14, height: 1.5),
),
if (card.shadow.isNotEmpty) ...[
const SizedBox(height: 16),
const _SectionTitle('Тень'),
const SizedBox(height: 8),
Text(
card.shadow,
style: const TextStyle(color: Color(0xFFC5CAE9), fontSize: 13, height: 1.5),
),
],
if (card.pairs.isNotEmpty) ...[
const SizedBox(height: 22),
_SectionTitle('Сочетания (${card.pairs.length})'),
const SizedBox(height: 6),
Text(
'Пара с каждой из остальных ${card.pairs.length} карт. Нажмите, чтобы открыть толкование.',
style: TextStyle(color: Color(0x8AFFFFFF), fontSize: 12, height: 1.4),
),
const SizedBox(height: 10),
TextField(
onChanged: (v) => setState(() => _query = v.trim()),
style: const TextStyle(color: Color(0xFFE8EAF6), fontSize: 14),
decoration: InputDecoration(
hintText: 'Поиск по второй карте…',
hintStyle: const TextStyle(color: Color(0xFF8C93B8)),
filled: true,
fillColor: const Color(0xFF151829),
prefixIcon: const Icon(Icons.search, color: Color(0xFFFFD54F)),
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(12),
borderSide: const BorderSide(color: Color(0x1AFFFFFF)),
),
),
),
const SizedBox(height: 12),
for (final p in pairs)
_PairTile(
card: card,
link: p,
onOpen: () {
HapticFeedback.selectionClick();
Navigator.push(
context,
MaterialPageRoute(
builder: (_) => LenormandPairScreen(
left: card.n,
right: p.n,
lookup: lookup,
title: widget.title,
),
),
);
},
),
],
],
),
);
}
}
class _SectionTitle extends StatelessWidget {
final String text;
const _SectionTitle(this.text);
@override
Widget build(BuildContext context) {
return Text(
text,
style: const TextStyle(
color: Color(0xFFFFD54F),
fontWeight: FontWeight.w900,
fontSize: 16,
letterSpacing: 0.3,
),
);
}
}
class _PairTile extends StatelessWidget {
final LenormandCardEntry card;
final LenormandPairLink link;
final VoidCallback onOpen;
const _PairTile({
required this.card,
required this.link,
required this.onOpen,
});
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 8),
child: Material(
color: const Color(0xFF151829),
borderRadius: BorderRadius.circular(12),
child: InkWell(
onTap: onOpen,
borderRadius: BorderRadius.circular(12),
child: Container(
padding: const EdgeInsets.fromLTRB(12, 10, 10, 10),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12),
border: Border.all(color: const Color(0x1AFFFFFF)),
),
child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
SizedBox(
width: 36,
child: Text(
'${link.n}',
style: const TextStyle(
color: Color(0xFFFFD54F),
fontWeight: FontWeight.w900,
fontSize: 14,
),
),
),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
'${card.name} + ${link.name}',
style: const TextStyle(
color: Color(0xFFFFF9C4),
fontWeight: FontWeight.w800,
fontSize: 14,
),
),
const SizedBox(height: 4),
Text(
link.displayText,
maxLines: 2,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
color: Color(0xFFC5CAE9),
fontSize: 12,
height: 1.4,
),
),
],
),
),
const Icon(Icons.chevron_right_rounded, color: Color(0xFF8C93B8)),
],
),
),
),
),
);
}
}