173 lines
6.6 KiB
Python
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!')
|