Files
999/scripts/patch_manual_dive_illustrations.py
T

173 lines
6.6 KiB
Python

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