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( 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( 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> 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> 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!')