import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../app/tema.dart'; import '../karakter/karakter_servisi.dart'; import '../msr/msr_servisi.dart'; import '../veri/modeller/karakter.dart'; import '../veri/modeller/sahne.dart'; import 'film_servisi.dart'; const _ruhHalleri = [ 'gergin', 'romantik', 'komik', 'hüzünlü', 'epik', 'gizemli', 'huzurlu', 'kaotik', 'korkutucu', ]; const _zamanlar = ['gündüz', 'gece', 'şafak', 'gün batımı', 'öğlen', 'iç mekan']; /// Sahne düzenleme diyaloğunu açar. void sahneDuzenleAc(BuildContext context, WidgetRef ref, Sahne sahne) { showDialog( context: context, builder: (_) => _SahneDuzenleDialog(sahneId: sahne.id), ); } class _SahneDuzenleDialog extends ConsumerStatefulWidget { const _SahneDuzenleDialog({required this.sahneId}); final int sahneId; @override ConsumerState<_SahneDuzenleDialog> createState() => _SahneDuzenleDialogState(); } class _SahneDuzenleDialogState extends ConsumerState<_SahneDuzenleDialog> { late Sahne _s; late final TextEditingController _aciklama; late final TextEditingController _mekan; late final TextEditingController _diyalog; late final TextEditingController _prompt; late final TextEditingController _negatif; @override void initState() { super.initState(); // Listeden kopya çalış — kaydedince put. final liste = ref.read(sahneListesiProvider).valueOrNull ?? []; _s = liste.firstWhere((x) => x.id == widget.sahneId, orElse: Sahne.new); _aciklama = TextEditingController(text: _s.aciklama); _mekan = TextEditingController(text: _s.mekan); _diyalog = TextEditingController(text: _s.diyalog); _prompt = TextEditingController(text: _s.prompt); _negatif = TextEditingController(text: _s.negatifPrompt); } @override void dispose() { _aciklama.dispose(); _mekan.dispose(); _diyalog.dispose(); _prompt.dispose(); _negatif.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final karakterler = ref.watch(karakterlerProvider).valueOrNull ?? []; final wfAsync = ref.watch(msrWorkflowlariProvider); return AlertDialog( title: const Row(children: [ Icon(Icons.dashboard_customize_rounded, size: 18, color: FikoRenkler.neonCyan), SizedBox(width: 8), Text('Sahne Düzenle'), ]), content: SizedBox( width: 560, child: SingleChildScrollView( child: Column(mainAxisSize: MainAxisSize.min, children: [ TextField( controller: _aciklama, minLines: 2, maxLines: 3, decoration: const InputDecoration( labelText: 'Açıklama / aksiyon', hintText: 'Sahnede ne oluyor?')), const SizedBox(height: 8), Row(children: [ Expanded( child: TextField( controller: _mekan, decoration: const InputDecoration( labelText: 'Mekan', hintText: 'orman, kafe...'))), const SizedBox(width: 8), Expanded(child: _drop('Zaman', _zamanlar, _s.zaman, (v) { setState(() => _s.zaman = v); })), ]), const SizedBox(height: 8), Row(children: [ Expanded( child: _drop('Ruh hali', _ruhHalleri, _s.ruhHali, (v) { setState(() => _s.ruhHali = v); })), const SizedBox(width: 8), Expanded( child: Row(children: [ const Text('Süre', style: TextStyle(fontSize: 11.5)), Expanded( child: Slider( value: _s.sureSn.clamp(1, 30), min: 1, max: 30, onChanged: (v) => setState(() => _s.sureSn = v), ), ), Text('${_s.sureSn.toStringAsFixed(0)}sn', style: const TextStyle(fontSize: 11)), ]), ), ]), const SizedBox(height: 10), _KarakterSecici( karakterler: karakterler, secili: _s.karakterIdler, degisti: (yeni) => setState(() => _s.karakterIdler = yeni), ), const SizedBox(height: 8), TextField( controller: _diyalog, minLines: 2, maxLines: 4, decoration: const InputDecoration( labelText: 'Diyalog', hintText: 'Karakter konuşmaları...')), const Divider(height: 22), TextField( controller: _prompt, minLines: 2, maxLines: 4, decoration: const InputDecoration( labelText: 'Prompt (İngilizce)', hintText: 'cinematic shot, ...')), const SizedBox(height: 8), TextField( controller: _negatif, minLines: 1, maxLines: 2, decoration: const InputDecoration(labelText: 'Negatif prompt')), const SizedBox(height: 8), Row(children: [ Expanded(child: _workflowDropdown(wfAsync)), const SizedBox(width: 8), Expanded( child: _drop( 'Durum', const ['taslak', 'uretiliyor', 'hazir'], _s.durum.name, (v) { setState(() => _s.durum = SahneDurumu.values .firstWhere((d) => d.name == v)); }), ), ]), ]), ), ), actions: [ TextButton( onPressed: () => Navigator.pop(context), child: const Text('Vazgeç')), FilledButton( onPressed: () async { _s ..aciklama = _aciklama.text.trim() ..mekan = _mekan.text.trim() ..diyalog = _diyalog.text.trim() ..prompt = _prompt.text.trim() ..negatifPrompt = _negatif.text.trim(); await FilmServisi.sahneKaydet(_s); if (context.mounted) Navigator.pop(context); }, child: const Text('Kaydet'), ), ], ); } /// MSR motorundan gelen gerçek workflow listesiyle dolu dropdown. Widget _workflowDropdown(AsyncValue> wfAsync) { return wfAsync.when( loading: () => const InputDecorator( decoration: InputDecoration(labelText: 'Workflow (MSR)', isDense: true), child: Row(children: [ SizedBox( width: 14, height: 14, child: CircularProgressIndicator(strokeWidth: 2)), SizedBox(width: 8), Text('Yükleniyor…', style: TextStyle(fontSize: 11.5)), ]), ), error: (_, _) => DropdownButtonFormField( initialValue: _s.kullanilanWorkflow.isEmpty ? null : _s.kullanilanWorkflow, isExpanded: true, decoration: const InputDecoration( labelText: 'Workflow (MSR — motor kapalı)', isDense: true), items: _s.kullanilanWorkflow.isEmpty ? const [] : [ DropdownMenuItem( value: _s.kullanilanWorkflow, child: Text(_s.kullanilanWorkflow, style: const TextStyle(fontSize: 11.5))) ], onChanged: (v) => setState(() => _s.kullanilanWorkflow = v ?? ''), ), data: (liste) { final degerler = {for (final w in liste) w.dosya}; final secili = degerler.contains(_s.kullanilanWorkflow) ? _s.kullanilanWorkflow : null; return DropdownButtonFormField( initialValue: secili, isExpanded: true, decoration: const InputDecoration(labelText: 'Workflow (MSR)', isDense: true), items: [ for (final w in liste) DropdownMenuItem( value: w.dosya, child: Text(w.ad, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle(fontSize: 11.5))) ], onChanged: (v) => setState(() => _s.kullanilanWorkflow = v ?? ''), ); }, ); } Widget _drop(String etiket, List opts, String secili, void Function(String) onChange) { final deger = opts.contains(secili) ? secili : null; return DropdownButtonFormField( initialValue: deger, isExpanded: true, decoration: InputDecoration(labelText: etiket, isDense: true), items: [ for (final o in opts) DropdownMenuItem( value: o, child: Text(o, style: const TextStyle(fontSize: 12))) ], onChanged: (v) { if (v != null) onChange(v); }, ); } } /// Sahnedeki karakterleri mevcut Karakter DB'sinden seçer. class _KarakterSecici extends StatelessWidget { const _KarakterSecici( {required this.karakterler, required this.secili, required this.degisti}); final List karakterler; final List secili; final void Function(List) degisti; @override Widget build(BuildContext context) { final t = Theme.of(context); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text('Karakterler', style: TextStyle(fontSize: 11.5, fontWeight: FontWeight.w700)), const SizedBox(height: 5), if (karakterler.isEmpty) Text('Karakter Stüdyosu\'ndan karakter ekle', style: TextStyle( fontSize: 10.5, color: t.colorScheme.onSurface.withValues(alpha: 0.5))) else Wrap(spacing: 6, runSpacing: 6, children: [ for (final k in karakterler) _SecimCip( etiket: k.ad.isEmpty ? 'isimsiz' : k.ad, secili: secili.contains(k.id), onTap: () { final yeni = [...secili]; yeni.contains(k.id) ? yeni.remove(k.id) : yeni.add(k.id); degisti(yeni); }, ), ]), ], ); } } class _SecimCip extends StatelessWidget { const _SecimCip( {required this.etiket, required this.secili, required this.onTap}); final String etiket; final bool secili; final VoidCallback onTap; @override Widget build(BuildContext context) { final t = Theme.of(context); return GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5), decoration: BoxDecoration( color: secili ? FikoRenkler.neonYesil.withValues(alpha: 0.18) : t.colorScheme.surface, borderRadius: BorderRadius.circular(20), border: Border.all( color: secili ? FikoRenkler.neonYesil : t.dividerColor), ), child: Row(mainAxisSize: MainAxisSize.min, children: [ Icon(secili ? Icons.check_circle : Icons.face, size: 13, color: secili ? FikoRenkler.neonYesil : t.colorScheme.onSurface.withValues(alpha: 0.55)), const SizedBox(width: 5), Text(etiket, style: TextStyle( fontSize: 11, fontWeight: secili ? FontWeight.w700 : FontWeight.w500, color: secili ? FikoRenkler.neonYesil : t.colorScheme.onSurface)), ]), ), ); } }