import 'dart:math'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import '../models/syncretic_session_model.dart'; import '../models/word_model.dart'; import '../services/day_numerology.dart'; import '../services/words_repository.dart'; import '../widgets/divination_instruction_modal.dart'; import 'symbol_detail_screen.dart'; class NumerologyDivinationScreen extends StatefulWidget { final String? initialQuestion; const NumerologyDivinationScreen({super.key, this.initialQuestion}); @override State createState() => _NumerologyDivinationScreenState(); } class _NumerologyDivinationScreenState extends State with SingleTickerProviderStateMixin { late TabController _tabController; final _questionController = TextEditingController(); final _repo = WordsRepository(); DateTime _selectedDate = DateTime(1990, 7, 15); final _dayCtrl = TextEditingController(text: '15'); final _monthCtrl = TextEditingController(text: '07'); final _yearCtrl = TextEditingController(text: '1990'); // Matrix calculation data int _w1 = 0; int _w2 = 0; int _w3 = 0; int _w4 = 0; int _lifePath = 0; Map _counts = {}; int? _selectedCell = 1; bool _savedToSession = false; // Dice roll state List _diceDigits = []; bool _isRollingDice = false; @override void initState() { super.initState(); _tabController = TabController(length: 2, vsync: this); if (widget.initialQuestion != null) { _questionController.text = widget.initialQuestion!; } _calculateFromDate(_selectedDate); } @override void dispose() { _tabController.dispose(); _questionController.dispose(); _dayCtrl.dispose(); _monthCtrl.dispose(); _yearCtrl.dispose(); super.dispose(); } // --- Numerological Math (Alexandrian School) --- void _calculateFromDate(DateTime date) { _selectedDate = date; _dayCtrl.text = date.day.toString().padLeft(2, '0'); _monthCtrl.text = date.month.toString().padLeft(2, '0'); _yearCtrl.text = date.year.toString(); final dayDigits = _splitDigits(date.day); final monthDigits = _splitDigits(date.month); final yearDigits = _splitDigits(date.year); final allDateDigits = [...dayDigits, ...monthDigits, ...yearDigits]; // 1st working number: sum of all digits of date final w1 = allDateDigits.reduce((a, b) => a + b); // 2nd working number: sum of digits of w1 final w2 = _splitDigits(w1).reduce((a, b) => a + b); // 3rd working number: w1 - 2 * (first non-zero digit of day) int firstNonZeroDayDigit = dayDigits.firstWhere((d) => d > 0, orElse: () => 1); final w3 = w1 - (2 * firstNonZeroDayDigit); // 4th working number: sum of digits of w3 final w4 = _splitDigits(w3.abs()).reduce((a, b) => a + b); // Life Path Number: reduce day + month + year int rDay = _reduceNumber(date.day, keepMaster: true); int rMonth = _reduceNumber(date.month, keepMaster: true); int rYear = _reduceNumber(date.year, keepMaster: true); int lifePath = _reduceNumber(rDay + rMonth + rYear, keepMaster: true); // Digit pool for 3x3 matrix final pool = [ ...allDateDigits, ..._splitDigits(w1), ..._splitDigits(w2), ..._splitDigits(w3.abs()), ..._splitDigits(w4), ]; final counts = {}; for (int i = 1; i <= 9; i++) { counts[i] = pool.where((d) => d == i).length; } setState(() { _w1 = w1; _w2 = w2; _w3 = w3; _w4 = w4; _lifePath = lifePath; _counts = counts; _savedToSession = false; }); } void _calculateFromDigits(List digits) { // Digits is 8 numbers: d1 d2 m1 m2 y1 y2 y3 y4 final day = digits[0] * 10 + digits[1]; final month = digits[2] * 10 + digits[3]; final year = digits[4] * 1000 + digits[5] * 100 + digits[6] * 10 + digits[7]; final w1 = digits.reduce((a, b) => a + b); final w2 = _splitDigits(w1).reduce((a, b) => a + b); int firstNonZero = digits.take(2).firstWhere((d) => d > 0, orElse: () => 1); final w3 = w1 - (2 * firstNonZero); final w4 = _splitDigits(w3.abs()).reduce((a, b) => a + b); int lifePath = _reduceNumber(w1, keepMaster: true); final pool = [ ...digits, ..._splitDigits(w1), ..._splitDigits(w2), ..._splitDigits(w3.abs()), ..._splitDigits(w4), ]; final counts = {}; for (int i = 1; i <= 9; i++) { counts[i] = pool.where((d) => d == i).length; } setState(() { _w1 = w1; _w2 = w2; _w3 = w3; _w4 = w4; _lifePath = lifePath; _counts = counts; _savedToSession = false; }); } List _splitDigits(int n) { if (n == 0) return [0]; final s = n.abs().toString(); return s.split('').map(int.parse).toList(); } int _reduceNumber(int n, {bool keepMaster = false}) { return DayNumerology.reduce(n, keepMaster: keepMaster); } WordItem? _findWordForNumber(int n) { final names = { 0: 'ноль', 1: 'один', 2: 'два', 3: 'три', 4: 'четыре', 5: 'пять', 6: 'шесть', 7: 'семь', 8: 'восемь', 9: 'девять', 10: 'десять', 11: 'одиннадцать', 12: 'двенадцать', 13: 'тринадцать', 21: 'двадцать один', 22: 'двадцать два', 33: 'тридцать три', 1000: 'тысяча', }; final name = names[n]; if (name == null) return null; try { return _repo.allWords.firstWhere((w) => w.word.toLowerCase() == name); } catch (_) { return null; } } void _rollDice() async { setState(() => _isRollingDice = true); HapticFeedback.mediumImpact(); final rng = Random(); // Generate 8 d10 digits (0..9) await Future.delayed(const Duration(milliseconds: 300)); final digits = List.generate(8, (_) => rng.nextInt(10)); // Ensure day month year make somewhat sane numerology if (digits[0] > 3) digits[0] = rng.nextInt(3); if (digits[2] > 1) digits[2] = rng.nextInt(2); _diceDigits = digits; _calculateFromDigits(digits); setState(() => _isRollingDice = false); } Future _saveToSyncreticSession() async { if (_savedToSession) return; final lpWord = _findWordForNumber(_lifePath); final items = [ ReadingSignItem( title: 'Число Жизненного Пути: $_lifePath', subtitle: _getLifePathTitle(_lifePath), symbol: '$_lifePath', lore: _getLifePathLore(_lifePath), linkedWord: lpWord, meta: { 'type': 'life_path', 'number': _lifePath, 'w1': _w1, 'w2': _w2, 'w3': _w3, 'w4': _w4, }, ), ReadingSignItem( title: 'Рабочие Числа Пифагора', subtitle: 'W1: $_w1 • W2: $_w2 • W3: $_w3 • W4: $_w4', symbol: 'Σ', lore: 'W1 (сумма даты) показывает потенциал воплощения. W2 — ведущее качество. W3 — кармический багаж рода. W4 — ключевой навык для реализации.', ), ]; // Add significant cells (counts > 0) for (int cell = 1; cell <= 9; cell++) { final cnt = _counts[cell] ?? 0; final cellWord = _findWordForNumber(cell); items.add( ReadingSignItem( title: 'Ячейка $cell: ${_getCellName(cell)} (${cnt > 0 ? List.filled(cnt, cell).join() : "нет"})', subtitle: _getCellQualitySummary(cell, cnt), symbol: '$cell', lore: _getCellLore(cell, cnt), linkedWord: cellWord, meta: {'cell': cell, 'count': cnt}, ), ); } final reading = SyncreticReading( id: 'num_${DateTime.now().millisecondsSinceEpoch}', systemId: 'numerology', systemName: 'Нумерология и Квадрат Пифагора', systemIcon: '🔢', timestamp: DateTime.now(), layoutTitle: 'Психоматрица 3×3 (ЧЖП: $_lifePath)', inputMethod: _tabController.index == 0 ? 'manual' : 'dice', items: items, question: _questionController.text.trim().isNotEmpty ? _questionController.text.trim() : null, ); await _repo.addReadingToSyncreticSession(reading, question: _questionController.text.trim()); setState(() => _savedToSession = true); HapticFeedback.heavyImpact(); ScaffoldMessenger.of(context).showSnackBar( SnackBar( backgroundColor: const Color(0xFF2E7D32), behavior: SnackBarBehavior.floating, content: Row( children: [ const Icon(Icons.check_circle_rounded, color: Colors.white, size: 20), const SizedBox(width: 10), Expanded( child: Text( 'Психоматрица сохранена в Сессию Дня (ЧЖП: $_lifePath)', style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13), ), ), ], ), ), ); } @override Widget build(BuildContext context) { final selectedCellWord = _selectedCell != null ? _findWordForNumber(_selectedCell!) : null; return Scaffold( backgroundColor: const Color(0xFF0C0E1A), appBar: AppBar( backgroundColor: const Color(0xFF141729), elevation: 0, title: const Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Нумерология и Пифагор', style: TextStyle(color: Color(0xFFFFF9C4), fontSize: 16, fontWeight: FontWeight.bold), ), Text( 'Психоматрица 3×3 и Число Судьбы', style: TextStyle(color: Color(0xFF8C93B8), fontSize: 11), ), ], ), actions: [ IconButton( icon: const Icon(Icons.menu_book_rounded, color: Color(0xFFFFD54F)), tooltip: 'Инструкция', onPressed: () => DivinationInstructionModal.show(context, 'numerology'), ), IconButton( icon: Icon( _savedToSession ? Icons.bookmark_added_rounded : Icons.bookmark_add_outlined, color: _savedToSession ? const Color(0xFF81C784) : const Color(0xFFFFD54F), ), tooltip: 'Добавить в Сессию Дня', onPressed: _saveToSyncreticSession, ), ], bottom: TabBar( controller: _tabController, indicatorColor: const Color(0xFFFFD54F), indicatorWeight: 3, labelColor: const Color(0xFFFFD54F), unselectedLabelColor: const Color(0xFF8C93B8), tabs: const [ Tab(icon: Icon(Icons.cake_rounded, size: 18), text: 'Дата рождения'), Tab(icon: Icon(Icons.casino_rounded, size: 18), text: 'Жребий d10'), ], ), ), body: SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 14), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ // Question Input TextField( controller: _questionController, style: const TextStyle(color: Colors.white, fontSize: 13), decoration: InputDecoration( hintText: 'Фокус внимания / имя кверента / вопрос...', hintStyle: const TextStyle(color: Color(0xFF6B7280), fontSize: 12), filled: true, fillColor: const Color(0xFF16192E), prefixIcon: const Icon(Icons.help_outline_rounded, color: Color(0xFFFFD54F), size: 18), border: OutlineInputBorder(borderRadius: BorderRadius.circular(12), borderSide: BorderSide.none), contentPadding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), ), ), const SizedBox(height: 14), // Tab View Area if (_tabController.index == 0) _buildDateControls() else _buildDiceControls(), const SizedBox(height: 16), // Life Path & Working Numbers Banner _buildSummaryBanner(), const SizedBox(height: 16), // Pythagorean 3x3 Grid _buildPythagoreanGrid(), const SizedBox(height: 16), // Selected Cell Detail Card if (_selectedCell != null) _buildCellDetailCard(_selectedCell!, selectedCellWord), const SizedBox(height: 16), // Lines Analysis (Rows, Cols, Diags) _buildLinesAnalysis(), const SizedBox(height: 24), // Save to Session Button SizedBox( width: double.infinity, height: 48, child: ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: _savedToSession ? const Color(0xFF2E7D32) : const Color(0xFFFFD54F), foregroundColor: _savedToSession ? Colors.white : Colors.black, shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)), elevation: 4, ), icon: Icon(_savedToSession ? Icons.check_circle_rounded : Icons.auto_awesome_rounded), label: Text( _savedToSession ? 'Сохранено в Сессию Дня' : 'Записать матрицу в Сессию Дня', style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 14), ), onPressed: _saveToSyncreticSession, ), ), const SizedBox(height: 20), ], ), ), ); } Widget _buildDateControls() { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFF141729), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFF232845)), ), child: Column( children: [ Row( children: [ Expanded( child: Row( children: [ Expanded( child: TextField( controller: _dayCtrl, keyboardType: TextInputType.number, maxLength: 2, textAlign: TextAlign.center, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold), decoration: InputDecoration( counterText: '', labelText: 'День', labelStyle: const TextStyle(color: Color(0xFF8C93B8), fontSize: 11), filled: true, fillColor: const Color(0xFF1C2038), border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), contentPadding: const EdgeInsets.symmetric(vertical: 8), ), onChanged: (_) => _onManualDateInput(), ), ), const SizedBox(width: 6), Expanded( child: TextField( controller: _monthCtrl, keyboardType: TextInputType.number, maxLength: 2, textAlign: TextAlign.center, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold), decoration: InputDecoration( counterText: '', labelText: 'Месяц', labelStyle: const TextStyle(color: Color(0xFF8C93B8), fontSize: 11), filled: true, fillColor: const Color(0xFF1C2038), border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), contentPadding: const EdgeInsets.symmetric(vertical: 8), ), onChanged: (_) => _onManualDateInput(), ), ), const SizedBox(width: 6), Expanded( flex: 2, child: TextField( controller: _yearCtrl, keyboardType: TextInputType.number, maxLength: 4, textAlign: TextAlign.center, style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold), decoration: InputDecoration( counterText: '', labelText: 'Год', labelStyle: const TextStyle(color: Color(0xFF8C93B8), fontSize: 11), filled: true, fillColor: const Color(0xFF1C2038), border: OutlineInputBorder(borderRadius: BorderRadius.circular(8)), contentPadding: const EdgeInsets.symmetric(vertical: 8), ), onChanged: (_) => _onManualDateInput(), ), ), ], ), ), const SizedBox(width: 8), IconButton( style: IconButton.styleFrom( backgroundColor: const Color(0xFF232845), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), icon: const Icon(Icons.calendar_month_rounded, color: Color(0xFFFFD54F)), tooltip: 'Календарь', onPressed: () async { final picked = await showDatePicker( context: context, initialDate: _selectedDate, firstDate: DateTime(1900), lastDate: DateTime(2100), builder: (ctx, child) { return Theme( data: ThemeData.dark().copyWith( colorScheme: const ColorScheme.dark( primary: Color(0xFFFFD54F), onPrimary: Colors.black, surface: Color(0xFF181C30), ), ), child: child!, ); }, ); if (picked != null) { _calculateFromDate(picked); } }, ), ], ), const SizedBox(height: 8), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ TextButton.icon( icon: const Icon(Icons.today_rounded, size: 15, color: Color(0xFF80DEEA)), label: const Text('Сегодняшний день', style: TextStyle(color: Color(0xFF80DEEA), fontSize: 12)), onPressed: () => _calculateFromDate(DateTime.now()), ), Text( 'Дата: ${_selectedDate.day.toString().padLeft(2, '0')}.${_selectedDate.month.toString().padLeft(2, '0')}.${_selectedDate.year}', style: const TextStyle(color: Color(0xFFFFF9C4), fontSize: 12, fontWeight: FontWeight.bold), ), ], ), ], ), ); } void _onManualDateInput() { final d = int.tryParse(_dayCtrl.text) ?? 1; final m = int.tryParse(_monthCtrl.text) ?? 1; final y = int.tryParse(_yearCtrl.text) ?? 1990; if (d >= 1 && d <= 31 && m >= 1 && m <= 12 && y >= 1900 && y <= 2100) { _calculateFromDate(DateTime(y, m, d)); } } Widget _buildDiceControls() { return Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFF141729), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFF232845)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'МАНТИЧЕСКИЙ СРЕЗ (8×d10)', style: TextStyle(color: Color(0xFFFFD54F), fontSize: 11, fontWeight: FontWeight.bold), ), ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFFFFD54F), foregroundColor: Colors.black, padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)), ), icon: _isRollingDice ? const SizedBox(width: 14, height: 14, child: CircularProgressIndicator(strokeWidth: 2, color: Colors.black)) : const Icon(Icons.casino_rounded, size: 16), label: const Text('Бросить кости', style: TextStyle(fontWeight: FontWeight.bold, fontSize: 12)), onPressed: _isRollingDice ? null : _rollDice, ), ], ), const SizedBox(height: 8), if (_diceDigits.isNotEmpty) Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: _diceDigits.map((d) { return Container( width: 32, height: 32, alignment: Alignment.center, decoration: BoxDecoration( color: const Color(0xFF232845), borderRadius: BorderRadius.circular(6), border: Border.all(color: const Color(0xFFFFD54F).withValues(alpha: 0.5)), ), child: Text( '$d', style: const TextStyle(color: Color(0xFFFFF9C4), fontWeight: FontWeight.bold, fontSize: 15), ), ); }).toList(), ) else const Text( 'Нажмите «Бросить кости», чтобы сгенерировать нумерологический код ситуации.', style: TextStyle(color: Color(0xFF8C93B8), fontSize: 11.5), ), ], ), ); } Widget _buildSummaryBanner() { final lpWord = _findWordForNumber(_lifePath); return Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( gradient: const LinearGradient( colors: [Color(0xFF1E1B38), Color(0xFF141729)], begin: Alignment.topLeft, end: Alignment.bottomRight, ), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFFFFD54F).withValues(alpha: 0.3)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( width: 44, height: 44, alignment: Alignment.center, decoration: BoxDecoration( color: const Color(0xFF3B2B5E), shape: BoxShape.circle, border: Border.all(color: const Color(0xFFFFD54F), width: 1.5), ), child: Text( '$_lifePath', style: const TextStyle(color: Color(0xFFFFD54F), fontSize: 20, fontWeight: FontWeight.w900), ), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Text( 'ЧИСЛО ЖИЗНЕННОГО ПУТИ', style: TextStyle(color: Color(0xFFFFD54F), fontSize: 10.5, fontWeight: FontWeight.bold, letterSpacing: 0.8), ), if (lpWord != null) ...[ const SizedBox(width: 6), Container( padding: const EdgeInsets.symmetric(horizontal: 5, vertical: 1), decoration: BoxDecoration( color: const Color(0xFF232845), borderRadius: BorderRadius.circular(4), ), child: Text( '#${lpWord.formattedSessionNumber} «${lpWord.word}»', style: const TextStyle(color: Color(0xFF80DEEA), fontSize: 10, fontWeight: FontWeight.bold), ), ), ], ], ), const SizedBox(height: 2), Text( _getLifePathTitle(_lifePath), style: const TextStyle(color: Colors.white, fontSize: 14, fontWeight: FontWeight.bold), ), ], ), ), ], ), const SizedBox(height: 10), Text( _getLifePathLore(_lifePath), style: const TextStyle(color: Color(0xFFECEFF1), fontSize: 12, height: 1.35), ), const Divider(color: Color(0xFF2B2F4C), height: 20), Row( mainAxisAlignment: MainAxisAlignment.spaceAround, children: [ _buildWorkingNumberBadge('W1', '$_w1', 'Потенциал'), _buildWorkingNumberBadge('W2', '$_w2', 'Доминанта'), _buildWorkingNumberBadge('W3', '$_w3', 'Карма рода'), _buildWorkingNumberBadge('W4', '$_w4', 'Основа'), ], ), ], ), ); } Widget _buildWorkingNumberBadge(String label, String value, String desc) { return Column( children: [ Text(label, style: const TextStyle(color: Color(0xFF8C93B8), fontSize: 10, fontWeight: FontWeight.bold)), const SizedBox(height: 2), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: const Color(0xFF16192E), borderRadius: BorderRadius.circular(6), border: Border.all(color: const Color(0xFF2E3458)), ), child: Text( value, style: const TextStyle(color: Color(0xFFFFD54F), fontSize: 13, fontWeight: FontWeight.bold), ), ), const SizedBox(height: 2), Text(desc, style: const TextStyle(color: Color(0xFF6B7280), fontSize: 9)), ], ); } Widget _buildPythagoreanGrid() { // Standard layout of the 3x3 Pythagorean Psychomatrix: // Row 1: 1, 4, 7 // Row 2: 2, 5, 8 // Row 3: 3, 6, 9 return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row( children: [ Icon(Icons.grid_3x3_rounded, size: 16, color: Color(0xFFFFD54F)), SizedBox(width: 6), Text( 'ПСИХОМАТРИЦА 3×3 (КВАДРАТ ПИФАГОРА)', style: TextStyle(color: Color(0xFFFFD54F), fontSize: 11, fontWeight: FontWeight.bold, letterSpacing: 0.8), ), ], ), const SizedBox(height: 8), Container( decoration: BoxDecoration( color: const Color(0xFF141729), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFF232845)), ), child: Column( children: [ Row( children: [ Expanded(child: _buildGridCell(1)), Container(width: 1, height: 80, color: const Color(0xFF232845)), Expanded(child: _buildGridCell(4)), Container(width: 1, height: 80, color: const Color(0xFF232845)), Expanded(child: _buildGridCell(7)), ], ), Container(height: 1, color: const Color(0xFF232845)), Row( children: [ Expanded(child: _buildGridCell(2)), Container(width: 1, height: 80, color: const Color(0xFF232845)), Expanded(child: _buildGridCell(5)), Container(width: 1, height: 80, color: const Color(0xFF232845)), Expanded(child: _buildGridCell(8)), ], ), Container(height: 1, color: const Color(0xFF232845)), Row( children: [ Expanded(child: _buildGridCell(3)), Container(width: 1, height: 80, color: const Color(0xFF232845)), Expanded(child: _buildGridCell(6)), Container(width: 1, height: 80, color: const Color(0xFF232845)), Expanded(child: _buildGridCell(9)), ], ), ], ), ), ], ); } Widget _buildGridCell(int cell) { final count = _counts[cell] ?? 0; final isSelected = _selectedCell == cell; final name = _getCellShortName(cell); return InkWell( onTap: () { setState(() => _selectedCell = cell); HapticFeedback.selectionClick(); }, child: Container( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 4), decoration: BoxDecoration( color: isSelected ? const Color(0xFFFFD54F).withValues(alpha: 0.12) : Colors.transparent, border: isSelected ? Border.all(color: const Color(0xFFFFD54F), width: 1.5) : null, ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Text( name, style: TextStyle( color: isSelected ? const Color(0xFFFFD54F) : const Color(0xFF8C93B8), fontSize: 10, fontWeight: FontWeight.bold, ), ), const SizedBox(height: 4), Text( count > 0 ? List.filled(count, cell).join() : '—', style: TextStyle( color: count > 0 ? Colors.white : const Color(0xFF4B5563), fontSize: count > 3 ? 15 : 17, fontWeight: FontWeight.w900, letterSpacing: 1.2, ), ), const SizedBox(height: 2), Text( count == 0 ? 'нет' : '$count шт.', style: TextStyle( color: count > 0 ? const Color(0xFF80DEEA) : const Color(0xFF6B7280), fontSize: 9, ), ), ], ), ), ); } Widget _buildCellDetailCard(int cell, WordItem? word) { final count = _counts[cell] ?? 0; final name = _getCellName(cell); final lore = _getCellLore(cell, count); final summary = _getCellQualitySummary(cell, count); return Container( padding: const EdgeInsets.all(14), decoration: BoxDecoration( color: const Color(0xFF141729), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFFFFD54F).withValues(alpha: 0.4)), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: const Color(0xFF232845), borderRadius: BorderRadius.circular(8), border: Border.all(color: const Color(0xFFFFD54F).withValues(alpha: 0.4)), ), child: Text( '$cell', style: const TextStyle(color: Color(0xFFFFD54F), fontWeight: FontWeight.bold, fontSize: 16), ), ), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Ячейка $cell: $name', style: const TextStyle(color: Colors.white, fontWeight: FontWeight.bold, fontSize: 14), ), Text( 'Количество: ${count > 0 ? List.filled(count, cell).join() : "нет"} ($summary)', style: const TextStyle(color: Color(0xFF80DEEA), fontSize: 11.5), ), ], ), ), ], ), const SizedBox(height: 10), Text( lore, style: const TextStyle(color: Color(0xFFCFD8DC), fontSize: 12.5, height: 1.4), ), if (word != null) ...[ const Divider(color: Color(0xFF232845), height: 18), InkWell( onTap: () => Navigator.push( context, MaterialPageRoute(builder: (_) => SymbolDetailScreen(word: word)), ), child: Row( children: [ const Icon(Icons.link_rounded, color: Color(0xFFFFD54F), size: 16), const SizedBox(width: 6), Text( 'Связанный знак 999: #${word.formattedSessionNumber} «${word.word.toUpperCase()}»', style: const TextStyle(color: Color(0xFFFFD54F), fontSize: 11.5, fontWeight: FontWeight.bold), ), const Spacer(), const Icon(Icons.arrow_forward_ios_rounded, size: 12, color: Color(0xFF8C93B8)), ], ), ), ], ], ), ); } Widget _buildLinesAnalysis() { final c = _counts; final r1 = (c[1] ?? 0) + (c[4] ?? 0) + (c[7] ?? 0); // Целеустремленность final r2 = (c[2] ?? 0) + (c[5] ?? 0) + (c[8] ?? 0); // Семья final r3 = (c[3] ?? 0) + (c[6] ?? 0) + (c[9] ?? 0); // Стабильность final col1 = (c[1] ?? 0) + (c[2] ?? 0) + (c[3] ?? 0); // Самооценка final col2 = (c[4] ?? 0) + (c[5] ?? 0) + (c[6] ?? 0); // Быт и Финансы final col3 = (c[7] ?? 0) + (c[8] ?? 0) + (c[9] ?? 0); // Талант final d1 = (c[1] ?? 0) + (c[5] ?? 0) + (c[9] ?? 0); // Духовность final d2 = (c[3] ?? 0) + (c[5] ?? 0) + (c[7] ?? 0); // Темперамент return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row( children: [ Icon(Icons.tune_rounded, size: 16, color: Color(0xFFFFD54F)), SizedBox(width: 6), Text( 'БАЛАНС ЛИНИЙ И СИЛ МАТРИЦЫ', style: TextStyle(color: Color(0xFFFFD54F), fontSize: 11, fontWeight: FontWeight.bold, letterSpacing: 0.8), ), ], ), const SizedBox(height: 8), Container( padding: const EdgeInsets.all(12), decoration: BoxDecoration( color: const Color(0xFF141729), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFF232845)), ), child: Column( children: [ _buildLineBar('Строка 1 (1-4-7): Целеустремленность', r1, 5), _buildLineBar('Строка 2 (2-5-8): Качество семьянина', r2, 5), _buildLineBar('Строка 3 (3-6-9): Стабильность и уклад', r3, 5), const Divider(color: Color(0xFF232845), height: 14), _buildLineBar('Столбец 1 (1-2-3): Самооценка и эго', col1, 5), _buildLineBar('Столбец 2 (4-5-6): Быт и заработок', col2, 5), _buildLineBar('Столбец 3 (7-8-9): Внутренний талант', col3, 5), const Divider(color: Color(0xFF232845), height: 14), _buildLineBar('Диагональ 1 (1-5-9): Духовный вектор', d1, 5), _buildLineBar('Диагональ 2 (3-5-7): Темперамент', d2, 5), ], ), ), ], ); } Widget _buildLineBar(String title, int count, int normalMax) { final ratio = (count / normalMax).clamp(0.0, 1.0); final color = count == 0 ? const Color(0xFF6B7280) : (count < 3 ? const Color(0xFF4DD0E1) : (count <= 5 ? const Color(0xFF81C784) : const Color(0xFFFFB74D))); return Padding( padding: const EdgeInsets.symmetric(vertical: 4), child: Row( children: [ Expanded( flex: 6, child: Text( title, style: const TextStyle(color: Color(0xFFECEFF1), fontSize: 11), ), ), Expanded( flex: 3, child: ClipRRect( borderRadius: BorderRadius.circular(4), child: LinearProgressIndicator( value: ratio, minHeight: 6, backgroundColor: const Color(0xFF1E2238), valueColor: AlwaysStoppedAnimation(color), ), ), ), const SizedBox(width: 8), SizedBox( width: 32, child: Text( '$count ц.', textAlign: TextAlign.right, style: TextStyle(color: color, fontSize: 11, fontWeight: FontWeight.bold), ), ), ], ), ); } // --- String Helpers for Matrix Interpretation --- String _getCellShortName(int cell) { switch (cell) { case 1: return '1. Характер'; case 2: return '2. Энергия'; case 3: return '3. Интерес'; case 4: return '4. Здоровье'; case 5: return '5. Логика'; case 6: return '6. Труд'; case 7: return '7. Удача'; case 8: return '8. Долг'; case 9: return '9. Память'; default: return '$cell'; } } String _getCellName(int cell) { switch (cell) { case 1: return 'Характер, воля и эго'; case 2: return 'Энергия действия и биополе'; case 3: return 'Интерес, наука и творчество'; case 4: return 'Здоровье, тело и витальность'; case 5: return 'Логика, интуиция и расчёт'; case 6: return 'Труд, заземление и ремесло'; case 7: return 'Удача, везение и ангел-хранитель'; case 8: return 'Долг, ответственность и совесть'; case 9: return 'Память, ум и проницательность'; default: return 'Стихия $cell'; } } String _getCellQualitySummary(int cell, int count) { if (count == 0) return 'Качество не дано от рождения, зона наработки'; if (count == 1) return 'Ослабленное качество, требует осознанных усилий'; if (count == 2) return 'Норма качества, гармоничное проявление'; if (count == 3) return 'Переменчивость («хочу — проявлю, хочу — нет»)'; if (count == 4) return 'Сильное проявление, яркая доминанта'; return 'Гипер-потенциал, требует сублимации во избежание кризиса'; } String _getCellLore(int cell, int count) { switch (cell) { case 1: if (count == 1) return '«1» — Мягкий характер, стремление к компромиссам, уступчивость, иногда нехватка напора.'; if (count == 2) return '«11» — Гармоничный характер, общительность, умение выслушать других и отстоять свои границы.'; if (count == 3) return '«111» — Золотая середина: лидер, умеющий подстраиваться под коллектив и брать ответственность.'; if (count == 4) return '«1111» — Волевой лидер, несгибаемый стержень, командирские качества, не терпит диктата.'; return '«11111+» — Властный характер, мощный эго-потенциал. Опасность авторитаризма и перенапряжения.'; case 2: if (count == 0) return '«нет двоек» — Дефицит собственной энергии. Забор сил извне, быстрая утомляемость, нужна подзарядка через природу и спорт.'; if (count == 1) return '«2» — Дефицитная энергия: хватает на текущие задачи, но рывки вызывают истощение. Избегайте стрессов.'; if (count == 2) return '«22» — Норма энергии: оптимальный баланс для работы, общения и гармоничной жизни.'; if (count == 3) return '«222» — Экстрасенсорный потенциал: всплески энергии, способность заряжать окружающих.'; return '«2222+» — Донор энергии: мощный витальный заряд, природный магнетизм. Важно сбрасывать избыток через физический труд.'; case 3: if (count == 0) return '«нет троек» — Гуманитарный склад ума, склонность к искусству, педантичность в порядке.'; if (count == 1) return '«3» — Способности к точным или гуманитарным наукам зависят от личного настроения.'; if (count == 2) return '«33» — Аналитический ум, способность к наукам, технике, исследовательской работе.'; return '«333+» — Врождённый изобретатель, жажда познания, нестандартный творческий интеллект.'; case 4: if (count == 0) return '«нет четверок» — Слабое от природы тело, необходимо сознательно укреплять здоровье и режим.'; if (count == 1) return '«4» — Нормальное здоровье, требует регулярной профилактики и заботы.'; return '«44+» — Крепкий физический иммунитет, высокая выносливость, спортивный потенциал.'; case 5: if (count == 0) return '«нет пятерок» — Практическое мышление, ориентация на опыт. Интуиция включается редко.'; if (count == 1) return '«5» — Развитая интуиция, умение предчувствовать события и просчитывать шаги.'; if (count == 2) return '«55» — Сильная интуиция и логика, дар прогнозирования, минимизация ошибок.'; return '«555+» — Ясновидение, глубокое проникновение в скрытые взаимосвязи мира.'; case 6: if (count == 0) return '«нет шестерок» — Нелюбовь к монотонному физическому труду, тяга к творчеству и мысли.'; if (count == 1) return '«6» — Труд по настроению: работа руками требует вдохновения.'; if (count == 2) return '«66» — «Золотые руки», заземление, практичность, высокое мастерство ремесленника.'; return '«666+» — Предельная материальная концентрация, манипуляция плотными формами.'; case 7: if (count == 0) return '«нет семерок» — Удача зарабатывается исключительно собственным трудом без подарков судьбы.'; if (count == 1) return '«7» — Небольшое везение, защита в критических ситуациях, скрытый талант.'; if (count == 2) return '«77» — Баловень судьбы, открытые пути, интуитивное избегание катастроф.'; return '«777+» — Особая кармическая миссия, знак высшего покровительства.'; case 8: if (count == 0) return '«нет восьмерок» — Ослабленное чувство долга: человек никому ничем не обязан, важна личная свобода.'; if (count == 1) return '«8» — Развитое чувство долга, забота о близких, честность и надежность.'; if (count == 2) return '«88» — Врождённая справедливость, готовность служить людям, преданность слову.'; return '«888+» — Самоотверженное служение, кармический долг перед родом или народом.'; case 9: if (count == 1) return '«9» — Память требует тренировки, забывчивость к мелочам при фокусе на главном.'; if (count == 2) return '«99» — Отличная память, быстрая обучаемость, ясный и цепкий аналитический ум.'; if (count == 3) return '«999» — Блестящий интеллект, высокая скорость усвоения любой информации.'; return '«9999+» — Гениальность восприятия, проницательность, опасность перегрузки рассудка.'; default: return 'Стихия $cell: числовой архетип матрицы.'; } } String _getLifePathTitle(int lp) { switch (lp) { case 1: return '1 — Первопроходец и Лидер (Монада)'; case 2: return '2 — Дипломат и Миротворец (Дуада)'; case 3: return '3 — Творец и Вдохновитель (Триада)'; case 4: return '4 — Строитель и Хранитель Порядка (Тетрада)'; case 5: return '5 — Искатель Свободы и Странник (Пентада)'; case 6: return '6 — Наставник и Хранитель Очага (Гексада)'; case 7: return '7 — Философ и Искатель Истины (Септенер)'; case 8: return '8 — Владыка Материи и Стратег (Октава)'; case 9: return '9 — Мудрец и Гуманист (Эннеада)'; case 11: return '11 — Духовный Проводник (Мастер-Число)'; case 22: return '22 — Великий Архитектор (Мастер-Число)'; case 33: return '33 — Аватар Сострадания (Мастер-Число)'; default: return '$lp — Сакральное Число'; } } String _getLifePathLore(int lp) { switch (lp) { case 1: return 'Ваш путь — путь первопроходца, инициатора и лидера. Вы призваны прокладывать новые тропы, опираться на независимость духа и вести за собой.'; case 2: return 'Ваш путь — гармонизация противоположностей, тонкая дипломатия, сотрудничество и интуитивное исцеление разобщенности.'; case 3: return 'Ваш путь — самовыражение через слово, образ, радость и творчество. Вы пробуждаете мир от серости и косности.'; case 4: return 'Ваш путь — созидание несокрушимого фундамента, дисциплина, честный труд и превращение хаоса в устойчивую структуру.'; case 5: return 'Ваш путь — динамические перемены, расширение горизонтов, путешествия, разрушение отживших догм и свобода опыта.'; case 6: return 'Ваш путь — служение любви, воспитание, забота о семье и гармонизация пространства вокруг себя.'; case 7: return 'Ваш путь — глубинное исследование тайн мироздания, медитация, наука и отделение непреходящей истины от иллюзий.'; case 8: return 'Ваш путь — овладение законами материального изобилия, масштабное управление ресурсами и восстановление кармической справедливости.'; case 9: return 'Ваш путь — безусловное сострадание, завершение старых циклов, космическая мудрость и служение благу всего человечества.'; case 11: return 'Мастер-визионер. Вы обладаете прямым каналом озарения свыше. Ваша задача — нести духовный свет и вдохновлять людей на пробуждение.'; case 22: return 'Мастер-строитель. Способность превращать самые смелые идеалистические мечты в осязаемые материальные системы планетарного масштаба.'; case 33: return 'Мастер духовного служения. Высшее сострадание, самоотдача и исцеление сердец через чистую любовь.'; default: return 'Сакральный вектор вашего воплощения.'; } } }