feat: complete academic symbol lexicon heal, 2-column Cooper extraction, and updated assets
This commit is contained in:
@@ -0,0 +1,172 @@
|
||||
with open('lib/screens/manual_dive_screen.dart', 'r', encoding='utf-8') as f:
|
||||
src = f.read()
|
||||
|
||||
# 1. Update _savePassport to preserve illustrations
|
||||
target_save = ''' final updated = WordPassport(
|
||||
id: word.id,
|
||||
word: word.word,
|
||||
pos: word.partOfSpeech,
|
||||
category: word.category,
|
||||
emoji: word.emoji,
|
||||
fields: fieldsMap,
|
||||
filledCount: _filledCount,
|
||||
isComplete: _filledCount >= 78,
|
||||
updatedAt: DateTime.now().toUtc().toIso8601String(),
|
||||
);'''
|
||||
|
||||
repl_save = ''' final existingPassport = _repo.getPassport(word.id);
|
||||
final updated = WordPassport(
|
||||
id: word.id,
|
||||
word: word.word,
|
||||
pos: word.partOfSpeech,
|
||||
category: word.category,
|
||||
emoji: word.emoji,
|
||||
fields: fieldsMap,
|
||||
filledCount: _filledCount,
|
||||
isComplete: _filledCount >= 78,
|
||||
updatedAt: DateTime.now().toUtc().toIso8601String(),
|
||||
illustrations: existingPassport?.illustrations ?? const [],
|
||||
);'''
|
||||
|
||||
assert target_save in src, "target_save not found"
|
||||
src = src.replace(target_save, repl_save, 1)
|
||||
|
||||
# 2. Add illustration banner under progress bar
|
||||
target_progress = ''' ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: LinearProgressIndicator(
|
||||
value: progress,
|
||||
minHeight: 6,
|
||||
backgroundColor: const Color(0xFF24273E),
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
progress >= 1.0
|
||||
? const Color(0xFF66BB6A)
|
||||
: (progress > 0.5 ? const Color(0xFFFFD54F) : const Color(0xFFFFA726)),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),'''
|
||||
|
||||
repl_progress = ''' ClipRRect(
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
child: LinearProgressIndicator(
|
||||
value: progress,
|
||||
minHeight: 6,
|
||||
backgroundColor: const Color(0xFF24273E),
|
||||
valueColor: AlwaysStoppedAnimation<Color>(
|
||||
progress >= 1.0
|
||||
? const Color(0xFF66BB6A)
|
||||
: (progress > 0.5 ? const Color(0xFFFFD54F) : const Color(0xFFFFA726)),
|
||||
),
|
||||
),
|
||||
),
|
||||
if ((_repo.getPassport(word.id)?.illustrations ?? const []).isNotEmpty) ...[
|
||||
const SizedBox(height: 8),
|
||||
_buildIllustrationsBar(_repo.getPassport(word.id)!.illustrations),
|
||||
],
|
||||
],
|
||||
),
|
||||
),'''
|
||||
|
||||
assert target_progress in src, "target_progress not found"
|
||||
src = src.replace(target_progress, repl_progress, 1)
|
||||
|
||||
# 3. Add _buildIllustrationsBar helper method
|
||||
helper_code = '''
|
||||
Widget _buildIllustrationsBar(List<Map<String, dynamic>> illustrations) {
|
||||
return InkWell(
|
||||
onTap: () => _showIllustrationsDialog(illustrations),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: const Color(0xFF24273E).withValues(alpha: 0.6),
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(color: const Color(0xFFFFD54F).withValues(alpha: 0.3)),
|
||||
),
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.photo_library_outlined, size: 16, color: Color(0xFFFFD54F)),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Академические гравюры: ${illustrations.length} илл. («${illustrations.first['caption']}»)',
|
||||
style: const TextStyle(fontSize: 12, color: Color(0xFFFFD54F), fontWeight: FontWeight.w600),
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const Icon(Icons.arrow_forward_ios_rounded, size: 12, color: Color(0xFFFFD54F)),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showIllustrationsDialog(List<Map<String, dynamic>> illustrations) {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
backgroundColor: const Color(0xFF161828),
|
||||
title: Row(
|
||||
children: [
|
||||
const Icon(Icons.image_search_rounded, color: Color(0xFFFFD54F)),
|
||||
const SizedBox(width: 8),
|
||||
Text('Гравюры и схемы (${illustrations.length})', style: const TextStyle(fontSize: 18, color: Colors.white)),
|
||||
],
|
||||
),
|
||||
content: SizedBox(
|
||||
width: 500,
|
||||
child: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
itemCount: illustrations.length,
|
||||
separatorBuilder: (_, __) => const Divider(color: Color(0xFF24273E)),
|
||||
itemBuilder: (context, i) {
|
||||
final ill = illustrations[i];
|
||||
final filePath = ill['file'] as String? ?? '';
|
||||
final caption = ill['caption'] as String? ?? '';
|
||||
final source = ill['source'] as String? ?? '';
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image.asset(
|
||||
filePath,
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (_, __, ___) => Container(
|
||||
height: 120,
|
||||
color: const Color(0xFF0F111E),
|
||||
child: Center(child: Text('Изображение: $filePath', style: const TextStyle(fontSize: 12))),
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
Text(caption, style: const TextStyle(fontWeight: FontWeight.bold, fontSize: 13, color: Color(0xFFFFD54F))),
|
||||
const SizedBox(height: 2),
|
||||
Text(source, style: const TextStyle(fontSize: 11, color: Colors.grey)),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.of(ctx).pop(),
|
||||
child: const Text('Закрыть', style: TextStyle(color: Color(0xFFFFD54F))),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
'''
|
||||
|
||||
last_brace = src.rfind('}')
|
||||
src = src[:last_brace] + helper_code + '\n}\n'
|
||||
|
||||
with open('lib/screens/manual_dive_screen.dart', 'w', encoding='utf-8') as f:
|
||||
f.write(src)
|
||||
|
||||
print('manual_dive_screen.dart patched successfully!')
|
||||
Reference in New Issue
Block a user