feat: complete academic symbol lexicon heal, 2-column Cooper extraction, and updated assets

This commit is contained in:
2026-10-09 15:26:58 +05:00
parent 7f91366201
commit 0b12e4583b
244 changed files with 611461 additions and 1617 deletions
+109 -55
View File
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import '../models/history_entry_model.dart';
import '../models/word_model.dart';
import '../screens/symbol_detail_screen.dart';
import '../services/ai_oracle_service.dart';
import '../services/words_repository.dart';
import 'gradient_star_badge.dart';
@@ -61,6 +62,8 @@ class _WordCardWidgetState extends State<WordCardWidget> {
}
}
Color _getPosColor(String pos) {
switch (pos.toLowerCase()) {
case 'существительное':
@@ -174,11 +177,11 @@ class _WordCardWidgetState extends State<WordCardWidget> {
final min = now.minute.toString().padLeft(2, '0');
var text =
'✨ Оракул 999 — Толкование символа ✨\n'
'✨ Оракул — Толкование символа ✨\n'
'Дата и время: $day.$month.$year $hour:$min\n'
'${widget.question != null && widget.question!.isNotEmpty ? "Вопрос: «${widget.question}»\n" : ""}'
'Знак №${widget.word.formattedSessionNumber}: ${widget.word.word.toUpperCase()}\n'
'Аспект: ${widget.word.partOfSpeech} • ${widget.word.category}\n\n'
'Знак №${widget.word.formattedSessionNumber}: ${widget.word.emoji.isNotEmpty ? widget.word.emoji + " " : ""}${widget.word.word.toUpperCase()}\n'
'${widget.word.category.isNotEmpty ? "Категория: " + widget.word.category + "\n\n" : ""}'
'🔮 Символическое значение:\n${widget.word.description}';
if (_aiInterpretation != null) {
@@ -203,11 +206,51 @@ class _WordCardWidgetState extends State<WordCardWidget> {
);
}
void _shareWord(BuildContext context) {
final buffer = StringBuffer();
buffer.writeln('🔮 ОРАКУЛ • САХРАЛЬНЫЙ ЗНАК #${widget.word.formattedSessionNumber}');
buffer.writeln('«${widget.word.word.toUpperCase()}» ${widget.word.emoji}');
if (widget.word.category.isNotEmpty) {
buffer.writeln('Категория: ${widget.word.category}');
}
buffer.writeln('');
if (widget.word.core.isNotEmpty) {
buffer.writeln('📖 Суть:');
buffer.writeln(widget.word.core);
buffer.writeln('');
}
buffer.writeln('🔮 Толкование:');
buffer.writeln(widget.word.description);
if (_aiInterpretation != null && _aiInterpretation!.isNotEmpty) {
buffer.writeln('');
buffer.writeln('🤖 Персональный отклик Оракула:');
buffer.writeln(_aiInterpretation);
}
buffer.writeln('');
buffer.writeln('— Система сакрального жребия «Оракул»');
Clipboard.setData(ClipboardData(text: buffer.toString()));
HapticFeedback.lightImpact();
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Row(
children: [
const Icon(Icons.share_rounded, color: Color(0xFFFFD54F), size: 18),
const SizedBox(width: 10),
Expanded(child: Text('Символ «${widget.word.word}» скопирован для отправки!')),
],
),
duration: const Duration(seconds: 2),
behavior: SnackBarBehavior.floating,
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(12)),
),
);
}
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final isDark = theme.brightness == Brightness.dark;
final posColor = _getPosColor(widget.word.partOfSpeech);
return Card(
elevation: 8,
@@ -330,11 +373,28 @@ class _WordCardWidgetState extends State<WordCardWidget> {
),
Row(
children: [
IconButton(
tooltip: 'Полное досье знака',
icon: const Icon(Icons.menu_book_rounded, size: 21, color: Color(0xFF80DEEA)),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => SymbolDetailScreen(word: widget.word),
),
);
},
),
IconButton(
tooltip: 'Скопировать толкование',
icon: const Icon(Icons.copy_rounded, size: 20),
onPressed: () => _copyToClipboard(context),
),
IconButton(
tooltip: 'Поделиться символом',
icon: const Icon(Icons.share_rounded, size: 20, color: Color(0xFFFFD54F)),
onPressed: () => _shareWord(context),
),
IconButton(
tooltip: _savedToHistory ? 'Сохранено в историю' : 'Сохранить в историю',
icon: Icon(
@@ -353,59 +413,53 @@ class _WordCardWidgetState extends State<WordCardWidget> {
// Big Word Title
Center(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Text(
widget.word.word.toUpperCase(),
textAlign: TextAlign.center,
style: theme.textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.w900,
letterSpacing: 1.5,
color: isDark ? const Color(0xFFFFF9C4) : const Color(0xFF1B1D30),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.word.emoji.isNotEmpty)
Padding(
padding: const EdgeInsets.only(bottom: 6.0),
child: Text(
widget.word.emoji,
style: const TextStyle(fontSize: 36),
),
),
Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0),
child: Text(
widget.word.word.toUpperCase(),
textAlign: TextAlign.center,
style: theme.textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.w900,
letterSpacing: 1.5,
color: isDark ? const Color(0xFFFFF9C4) : const Color(0xFF1B1D30),
),
),
),
],
),
),
// Category Badge
if (widget.word.category.isNotEmpty)
Center(
child: Chip(
avatar: const Icon(Icons.auto_awesome, size: 14, color: Color(0xFFFFD54F)),
label: Text(
widget.word.category,
style: TextStyle(
fontSize: 12,
fontWeight: FontWeight.w600,
color: isDark ? Colors.white70 : Colors.black87,
),
),
backgroundColor: isDark
? Colors.white.withValues(alpha: 0.08)
: Colors.black.withValues(alpha: 0.05),
side: BorderSide.none,
padding: const EdgeInsets.symmetric(horizontal: 4),
),
),
),
// Part of Speech & Category Badges
Center(
child: Wrap(
spacing: 8,
runSpacing: 6,
alignment: WrapAlignment.center,
children: [
Chip(
avatar: Icon(Icons.auto_awesome, size: 14, color: posColor),
label: Text(
widget.word.partOfSpeech,
style: TextStyle(
fontWeight: FontWeight.w600,
fontSize: 12,
color: posColor,
),
),
backgroundColor: posColor.withValues(alpha: 0.12),
side: BorderSide(color: posColor.withValues(alpha: 0.3)),
padding: const EdgeInsets.symmetric(horizontal: 4),
),
if (widget.word.category.isNotEmpty)
Chip(
label: Text(
widget.word.category,
style: TextStyle(
fontSize: 12,
color: isDark ? Colors.white70 : Colors.black87,
),
),
backgroundColor: isDark
? Colors.white.withValues(alpha: 0.08)
: Colors.black.withValues(alpha: 0.05),
side: BorderSide.none,
padding: const EdgeInsets.symmetric(horizontal: 2),
),
],
),
),
const SizedBox(height: 14),
Divider(
@@ -447,7 +501,7 @@ class _WordCardWidgetState extends State<WordCardWidget> {
),
const SizedBox(height: 8),
Text(
widget.word.description,
widget.word.displayMeaning,
style: theme.textTheme.bodyMedium?.copyWith(
height: 1.45,
fontSize: 13.5,