feat: complete academic symbol lexicon heal, 2-column Cooper extraction, and updated assets
This commit is contained in:
@@ -0,0 +1,659 @@
|
||||
import '../widgets/divination_instruction_modal.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import '../services/words_repository.dart';
|
||||
import '../widgets/gradient_star_badge.dart';
|
||||
import 'home_search_screen.dart';
|
||||
import 'houses_field_screen.dart';
|
||||
import 'runes_divination_screen.dart';
|
||||
import 'lenormand_divination_screen.dart';
|
||||
import 'tarot_divination_screen.dart';
|
||||
import 'iching_divination_screen.dart';
|
||||
import 'cross_system_comparison_screen.dart';
|
||||
import 'numerology_divination_screen.dart';
|
||||
import 'geomancy_divination_screen.dart';
|
||||
import 'ogham_divination_screen.dart';
|
||||
|
||||
import '../services/word_of_the_day_service.dart';
|
||||
import 'word_of_the_day_screen.dart';
|
||||
|
||||
class DivinationHubScreen extends StatefulWidget {
|
||||
const DivinationHubScreen({super.key});
|
||||
|
||||
@override
|
||||
State<DivinationHubScreen> createState() => _DivinationHubScreenState();
|
||||
}
|
||||
|
||||
class _DivinationHubScreenState extends State<DivinationHubScreen> {
|
||||
final _repo = WordsRepository();
|
||||
final _wordOfDayService = WordOfTheDayService();
|
||||
|
||||
void _openComparisonScreen() {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => CrossSystemComparisonScreen(
|
||||
session: _repo.currentSyncreticSession,
|
||||
),
|
||||
),
|
||||
).then((_) => setState(() {}));
|
||||
}
|
||||
|
||||
void _showNewSessionDialog() {
|
||||
final controller = TextEditingController();
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
backgroundColor: const Color(0xFF151829),
|
||||
title: const Row(
|
||||
children: [
|
||||
GradientStar(size: 20),
|
||||
SizedBox(width: 8),
|
||||
Text('Новая Сессия Дня', style: TextStyle(color: Color(0xFFFFF9C4), fontSize: 17, fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const Text(
|
||||
'Начните новую синхронистическую сессию по новой теме или вопросу. Предыдущая сессия сохранится в архиве.',
|
||||
style: TextStyle(color: Color(0xFF8C93B8), fontSize: 13, height: 1.4),
|
||||
),
|
||||
const SizedBox(height: 14),
|
||||
TextField(
|
||||
controller: controller,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 14),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Главный вопрос / тема сессии...',
|
||||
hintStyle: const TextStyle(color: Color(0xFF8C93B8), fontSize: 12),
|
||||
filled: true,
|
||||
fillColor: const Color(0xFF1E2238),
|
||||
border: OutlineInputBorder(borderRadius: BorderRadius.circular(12)),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
child: const Text('Отмена'),
|
||||
),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: const Color(0xFFFFD54F),
|
||||
foregroundColor: Colors.black,
|
||||
),
|
||||
onPressed: () async {
|
||||
Navigator.pop(ctx);
|
||||
await _repo.startNewSyncreticSession(question: controller.text.trim());
|
||||
setState(() {});
|
||||
HapticFeedback.mediumImpact();
|
||||
},
|
||||
child: const Text('Начать'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildWordOfDayHeroBanner() {
|
||||
final now = DateTime.now();
|
||||
final rec = _wordOfDayService.getRecord(now);
|
||||
final isTriptych = rec.isTriptychMode;
|
||||
final singleWord = _wordOfDayService.getWordForDate(now, phase: 'main');
|
||||
final triptych = _wordOfDayService.getTriptychWordsForDate(now);
|
||||
final streak = _wordOfDayService.calculateStreak();
|
||||
|
||||
final isRevealed = isTriptych ? rec.isAnyRevealed : rec.isRevealed;
|
||||
final isDone = isTriptych ? rec.isDayStepCompleted : rec.isStepCompleted;
|
||||
|
||||
String titleTag = isTriptych ? 'ТРИПТИХ СУТОК (3 СЛОВА)' : 'СЛОВО ДНЯ • КАЛЕНДАРЬ';
|
||||
String subtitle;
|
||||
if (isTriptych) {
|
||||
if (rec.areAllTriptychRevealed) {
|
||||
subtitle = '🌅 ${triptych.morning.word.toUpperCase()} • ⚡ ${triptych.day.word.toUpperCase()} • 🌙 ${triptych.evening.word.toUpperCase()}';
|
||||
} else if (rec.isAnyRevealed) {
|
||||
final m = rec.isMorningRevealed ? triptych.morning.word.toUpperCase() : '•••';
|
||||
final d = rec.isDayRevealed ? triptych.day.word.toUpperCase() : '•••';
|
||||
final e = rec.isEveningRevealed ? triptych.evening.word.toUpperCase() : '•••';
|
||||
subtitle = '🌅 $m • ⚡ $d • 🌙 $e';
|
||||
} else {
|
||||
subtitle = 'Печати суток не распечатаны';
|
||||
}
|
||||
} else {
|
||||
subtitle = rec.isRevealed
|
||||
? '${singleWord.word.toUpperCase()} (#${singleWord.sessionNumber})'
|
||||
: 'Печать не распечатана';
|
||||
}
|
||||
|
||||
String statusText;
|
||||
if (isDone) {
|
||||
statusText = 'Выполнено ✓';
|
||||
} else if (isTriptych) {
|
||||
statusText = rec.areAllTriptychRevealed
|
||||
? 'Открыты 3/3'
|
||||
: (rec.isAnyRevealed ? 'В процессе' : 'Триптих');
|
||||
} else {
|
||||
statusText = rec.isRevealed ? 'В процессе' : 'Открыть';
|
||||
}
|
||||
|
||||
String descText;
|
||||
if (isTriptych) {
|
||||
if (rec.areAllTriptychRevealed) {
|
||||
descText = 'Утро: «${triptych.morning.asks}» | Вызов дня: «${triptych.day.step}»';
|
||||
} else {
|
||||
descText = 'Коснитесь, чтобы распечатать три слова дня: Настройка, Действие и Тень.';
|
||||
}
|
||||
} else {
|
||||
descText = rec.isRevealed
|
||||
? (singleWord.asks.isNotEmpty
|
||||
? '«${singleWord.asks}»'
|
||||
: (singleWord.oracle.isNotEmpty ? singleWord.oracle : singleWord.description))
|
||||
: 'Коснитесь, чтобы узнать архетип, коан и практическое задание на сегодня.';
|
||||
}
|
||||
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(builder: (_) => const WordOfTheDayScreen()),
|
||||
).then((_) => setState(() {}));
|
||||
},
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFF2E2045), Color(0xFF14172B)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(
|
||||
color: isRevealed
|
||||
? const Color(0xFFFFD54F)
|
||||
: const Color(0xFFFFD54F).withValues(alpha: 0.5),
|
||||
width: isRevealed ? 1.5 : 1.0,
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0xFFFFD54F).withValues(alpha: 0.12),
|
||||
blurRadius: 12,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 38,
|
||||
height: 38,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFFFFD54F), Color(0xFFFF8F00)],
|
||||
),
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: const Color(0xFFFFD54F).withValues(alpha: 0.3),
|
||||
blurRadius: 8,
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Text(
|
||||
isTriptych
|
||||
? '⏳'
|
||||
: (rec.isRevealed && singleWord.emoji.isNotEmpty
|
||||
? singleWord.emoji
|
||||
: '☀️'),
|
||||
style: const TextStyle(fontSize: 18),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
titleTag,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFFFD54F),
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w900,
|
||||
letterSpacing: 1.0,
|
||||
),
|
||||
),
|
||||
if (streak > 0) ...[
|
||||
const SizedBox(width: 6),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF3B2314),
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(color: const Color(0xFFFFB74D).withValues(alpha: 0.4)),
|
||||
),
|
||||
child: Text(
|
||||
'🔥 $streak дн.',
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFFFB74D),
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Text(
|
||||
subtitle,
|
||||
style: TextStyle(
|
||||
color: isRevealed ? const Color(0xFFFFF9C4) : const Color(0xFF8C93B8),
|
||||
fontSize: isTriptych ? 12.5 : 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: isDone
|
||||
? const Color(0xFF1B3D23)
|
||||
: (isRevealed ? const Color(0xFF2A2D4A) : const Color(0xFF332A1C)),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: isDone
|
||||
? const Color(0xFF81C784)
|
||||
: const Color(0xFFFFD54F).withValues(alpha: 0.4),
|
||||
),
|
||||
),
|
||||
child: Text(
|
||||
statusText,
|
||||
style: TextStyle(
|
||||
color: isDone
|
||||
? const Color(0xFF81C784)
|
||||
: const Color(0xFFFFD54F),
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
Text(
|
||||
descText,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(color: Color(0xFF8C93B8), fontSize: 12, height: 1.35),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final session = _repo.currentSyncreticSession;
|
||||
final readingsCount = session.readings.length;
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: const Color(0xFF0C0E1A),
|
||||
appBar: AppBar(
|
||||
title: const Row(
|
||||
children: [
|
||||
GradientStar(size: 22),
|
||||
SizedBox(width: 8),
|
||||
Text('Предсказания', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 18)),
|
||||
],
|
||||
),
|
||||
actions: [
|
||||
IconButton(
|
||||
tooltip: 'Начать новую тему сессии',
|
||||
icon: const Icon(Icons.add_circle_outline_rounded, color: Color(0xFFFFD54F)),
|
||||
onPressed: _showNewSessionDialog,
|
||||
),
|
||||
IconButton(
|
||||
tooltip: 'Сравнительный Мета-Промпт',
|
||||
icon: const Icon(Icons.psychology_alt_rounded, color: Color(0xFFFFD54F)),
|
||||
onPressed: _openComparisonScreen,
|
||||
),
|
||||
],
|
||||
),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.fromLTRB(16, 8, 16, 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
// Word of the Day Hero Banner
|
||||
_buildWordOfDayHeroBanner(),
|
||||
const SizedBox(height: 14),
|
||||
|
||||
// Active Day Session Banner
|
||||
InkWell(
|
||||
onTap: _openComparisonScreen,
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(16),
|
||||
decoration: BoxDecoration(
|
||||
gradient: const LinearGradient(
|
||||
colors: [Color(0xFF2A1F45), Color(0xFF151829)],
|
||||
begin: Alignment.topLeft,
|
||||
end: Alignment.bottomRight,
|
||||
),
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
border: Border.all(color: const Color(0xFFFFD54F).withValues(alpha: 0.5)),
|
||||
boxShadow: [
|
||||
BoxShadow(color: const Color(0xFFFFD54F).withValues(alpha: 0.1), blurRadius: 10),
|
||||
],
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
const GradientStar(size: 18),
|
||||
const SizedBox(width: 8),
|
||||
const Expanded(
|
||||
child: Text(
|
||||
'АКТИВНАЯ СЕССИЯ ДНЯ',
|
||||
style: TextStyle(
|
||||
color: Color(0xFFFFD54F),
|
||||
fontSize: 11,
|
||||
fontWeight: FontWeight.w900,
|
||||
letterSpacing: 1.0,
|
||||
),
|
||||
),
|
||||
),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF3B2B5E),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFFFD54F).withValues(alpha: 0.4)),
|
||||
),
|
||||
child: Text(
|
||||
'$readingsCount ${readingsCount == 1 ? "гадание" : (readingsCount < 5 ? "гадания" : "гаданий")}',
|
||||
style: const TextStyle(color: Color(0xFFFFF9C4), fontSize: 11, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
session.mainQuestion?.isNotEmpty == true
|
||||
? '«${session.mainQuestion!}»'
|
||||
: 'Синхронистический сосуд дня (все гадания аккумулируются здесь)',
|
||||
style: const TextStyle(color: Color(0xFFECEFF1), fontSize: 13.5, height: 1.4),
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
readingsCount > 0 ? 'Нажмите, чтобы сравнить системы' : 'Сделайте расклад в любой системе ниже',
|
||||
style: const TextStyle(color: Color(0xFF80DEEA), fontSize: 11, fontWeight: FontWeight.bold),
|
||||
),
|
||||
const Icon(Icons.arrow_forward_ios_rounded, size: 12, color: Color(0xFFFFD54F)),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Section 1: Core 999 Systems
|
||||
_buildSectionHeader('СИСТЕМЫ ОРАКУЛА 999', Icons.auto_awesome_rounded),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildSystemCard(
|
||||
title: 'Слово Дня',
|
||||
instructionId: 'word_of_day',
|
||||
subtitle: 'Календарь & Квест',
|
||||
icon: '☀️',
|
||||
desc: 'Ежедневный архетип, коан для ума, микродействие и дневник',
|
||||
accentColor: const Color(0xFFFFD54F),
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const WordOfTheDayScreen())).then((_) => setState(() {})),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildSystemCard(
|
||||
title: 'Оракул',
|
||||
instructionId: 'cleromancy',
|
||||
subtitle: 'Клеромантия d10',
|
||||
icon: '🎲',
|
||||
desc: '1..10 знаков по жребию костей или прямому вводу',
|
||||
accentColor: const Color(0xFFFFD54F),
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const HomeSearchScreen())).then((_) => setState(() {})),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: _buildSystemCard(
|
||||
title: 'Матрица 33×30',
|
||||
instructionId: 'matrix',
|
||||
subtitle: '990 Домов Судьбы',
|
||||
icon: '🏛️',
|
||||
desc: 'Полотно Домов, Архонты и цепочки диспозиций',
|
||||
accentColor: const Color(0xFF80DEEA),
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const HousesFieldScreen())).then((_) => setState(() {})),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
|
||||
// Section 2: Classical Divination Systems
|
||||
_buildSectionHeader('КЛАССИЧЕСКИЕ ТРАДИЦИИ', Icons.history_edu_rounded),
|
||||
const SizedBox(height: 10),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildSystemCard(
|
||||
title: 'Руны Футарка',
|
||||
instructionId: 'runes',
|
||||
subtitle: '24 Руны (2×d12)',
|
||||
icon: 'ᚱ',
|
||||
desc: 'Жребий двумя d12 либо сетка рун (прямые/перев.)',
|
||||
accentColor: const Color(0xFF81C784),
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const RunesDivinationScreen())).then((_) => setState(() {})),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: _buildSystemCard(
|
||||
title: 'Кельтский Огам',
|
||||
instructionId: 'ogham',
|
||||
subtitle: '20 Фед Рощи (d20)',
|
||||
icon: '᚛',
|
||||
desc: 'Священные деревья друидов: жребий палочек и 4 Аикмы',
|
||||
accentColor: const Color(0xFF66BB6A),
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const OghamDivinationScreen())).then((_) => setState(() {})),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildSystemCard(
|
||||
title: 'Таро',
|
||||
instructionId: 'tarot',
|
||||
subtitle: '22 Старших Аркана',
|
||||
icon: '🎴',
|
||||
desc: 'Жребий колоды или выбор из 22 Арканов',
|
||||
accentColor: const Color(0xFFBA68C8),
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const TarotDivinationScreen())).then((_) => setState(() {})),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: _buildSystemCard(
|
||||
title: 'Ленорман',
|
||||
instructionId: 'lenormand',
|
||||
subtitle: '36 Домов (d6+d12)',
|
||||
icon: '🪶',
|
||||
desc: 'Бросок d6+d12 со смещением или ввод 1..36',
|
||||
accentColor: const Color(0xFFFFB74D),
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const LenormandDivinationScreen())).then((_) => setState(() {})),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildSystemCard(
|
||||
title: 'И Цзин',
|
||||
instructionId: 'iching',
|
||||
subtitle: '3 монеты × 6',
|
||||
icon: '☯️',
|
||||
desc: 'Книга Перемен: 6 бросков монет или ввод черт',
|
||||
accentColor: const Color(0xFF4DD0E1),
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const IChingDivinationScreen())).then((_) => setState(() {})),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: _buildSystemCard(
|
||||
title: 'Геомантия',
|
||||
instructionId: 'geomancy',
|
||||
subtitle: "16 Фигур ('Илм ар-рамл)",
|
||||
icon: '⌛',
|
||||
desc: 'Земной жребий песка, Свидетели и Щит Судьбы',
|
||||
accentColor: const Color(0xFFFFB74D),
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const GeomancyDivinationScreen())).then((_) => setState(() {})),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: _buildSystemCard(
|
||||
title: 'Нумерология',
|
||||
instructionId: 'numerology',
|
||||
subtitle: 'Психоматрица 3×3',
|
||||
icon: '🔢',
|
||||
desc: '4 рабочих числа, психоматрица Пифагора и Число Судьбы',
|
||||
accentColor: const Color(0xFFFFD54F),
|
||||
onTap: () => Navigator.push(context, MaterialPageRoute(builder: (_) => const NumerologyDivinationScreen())).then((_) => setState(() {})),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSectionHeader(String title, IconData icon) {
|
||||
return Row(
|
||||
children: [
|
||||
Icon(icon, size: 16, color: const Color(0xFFFFD54F)),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
title,
|
||||
style: const TextStyle(
|
||||
color: Color(0xFFFFD54F),
|
||||
fontSize: 11.5,
|
||||
fontWeight: FontWeight.w900,
|
||||
letterSpacing: 1.0,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildSystemCard({
|
||||
required String title,
|
||||
required String subtitle,
|
||||
required String icon,
|
||||
required String desc,
|
||||
required Color accentColor,
|
||||
String? instructionId,
|
||||
required VoidCallback onTap,
|
||||
}) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
HapticFeedback.selectionClick();
|
||||
onTap();
|
||||
},
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(14),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF151829),
|
||||
borderRadius: BorderRadius.circular(16),
|
||||
border: Border.all(color: const Color(0xFF2A2D4A)),
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Container(
|
||||
width: 36,
|
||||
height: 36,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF232742),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: accentColor.withValues(alpha: 0.4)),
|
||||
),
|
||||
child: Text(icon, style: const TextStyle(fontSize: 18)),
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 13)),
|
||||
Text(subtitle, style: TextStyle(color: accentColor, fontSize: 10, fontWeight: FontWeight.bold)),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (instructionId != null)
|
||||
IconButton(
|
||||
icon: const Icon(Icons.info_outline_rounded, size: 18, color: Color(0xFF8C93B8)),
|
||||
padding: EdgeInsets.zero,
|
||||
constraints: const BoxConstraints(),
|
||||
tooltip: 'Инструкция',
|
||||
onPressed: () => DivinationInstructionModal.show(context, instructionId),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
desc,
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(color: Color(0xFF8C93B8), fontSize: 11, height: 1.3),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user