import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../app/tema.dart'; import '../resim/nsfw_kataloglari.dart'; import 'video_kataloglari.dart'; import 'video_sihirbaz_secimleri.dart'; /// Kapsamlı sekmeli video prompt sihirbazı — resim sihirbazı pattern'i. /// Form state'e bağlı değildir; [secimler] + [onDegisti] ile dışarıdan yönetilir. class VideoSihirbazi extends ConsumerStatefulWidget { const VideoSihirbazi({ super.key, required this.secimler, required this.onDegisti, }); final VideoSihirbazSecimleri secimler; final ValueChanged onDegisti; @override ConsumerState createState() => _VideoSihirbaziState(); } class _VideoSihirbaziState extends ConsumerState { int _aktif = 0; VideoSihirbazSecimleri get _s => widget.secimler; void _g(VideoSihirbazSecimleri y) => widget.onDegisti(y); @override Widget build(BuildContext context) { final s = _s; final tablar = _tablariOlustur(s); final aktif = _aktif.clamp(0, tablar.length - 1); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ const Icon(Icons.auto_fix_high, size: 15, color: FikoRenkler.neonMor), const SizedBox(width: 6), const Text('Video Sihirbazı', style: TextStyle(fontSize: 12.5, fontWeight: FontWeight.w700)), const Spacer(), TextButton.icon( style: TextButton.styleFrom( visualDensity: VisualDensity.compact, padding: const EdgeInsets.symmetric(horizontal: 8)), icon: const Icon(Icons.cleaning_services, size: 14), label: const Text('Temizle', style: TextStyle(fontSize: 11.5)), onPressed: () => _g(VideoSihirbazSecimleri(nsfwAcik: s.nsfwAcik)), ), const SizedBox(width: 6), GestureDetector( onTap: () => _g(s.kopyala(nsfwAcik: !s.nsfwAcik)), child: Container( padding: const EdgeInsets.symmetric(horizontal: 9, vertical: 5), decoration: BoxDecoration( color: s.nsfwAcik ? const Color(0xFFFF2E6A).withValues(alpha: 0.22) : Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(7), border: Border.all( color: s.nsfwAcik ? const Color(0xFFFF2E6A) : Theme.of(context).dividerColor, width: s.nsfwAcik ? 1.3 : 1), ), child: Row(mainAxisSize: MainAxisSize.min, children: [ Icon(s.nsfwAcik ? Icons.lock_open : Icons.lock, size: 13, color: s.nsfwAcik ? const Color(0xFFFF2E6A) : Theme.of(context) .colorScheme .onSurface .withValues(alpha: 0.5)), const SizedBox(width: 4), Text('18+', style: TextStyle( fontSize: 11, fontWeight: FontWeight.w800, color: s.nsfwAcik ? const Color(0xFFFF2E6A) : Theme.of(context).colorScheme.onSurface)), ]), ), ), ], ), const SizedBox(height: 6), SizedBox( height: 32, child: ListView.separated( scrollDirection: Axis.horizontal, itemCount: tablar.length, separatorBuilder: (_, _) => const SizedBox(width: 5), itemBuilder: (_, i) => _TabCip( etiket: tablar[i].etiket, renk: tablar[i].renk, secili: i == aktif, dolu: tablar[i].dolu, onTap: () => setState(() => _aktif = i), ), ), ), const Divider(height: 14), Padding( padding: const EdgeInsets.only(bottom: 4), child: tablar[aktif].icerik, ), if (!s.bos) _onizleme(s), ], ); } List<_Tab> _tablariOlustur(VideoSihirbazSecimleri s) { final tablar = <_Tab>[ _Tab('🎬 Sahne', FikoRenkler.neonCyan, _sahne(s), s.sahneTuru.isNotEmpty || s.ozne.isNotEmpty), _Tab('📷 Kamera', FikoRenkler.neonAmber, _kamera(s), s.kameraHareketi.isNotEmpty || s.kameraAcisi.isNotEmpty || s.lens.isNotEmpty), _Tab('🏃 Hareket', FikoRenkler.neonYesil, _hareket(s), s.hareketYogunlugu.isNotEmpty || s.hizDuygusu.isNotEmpty), _Tab('🌫️ Atmosfer', FikoRenkler.neonPembe, _atmosfer(s), s.atmosfer.isNotEmpty || s.efektDokunuslari.isNotEmpty), _Tab('💡 Işık', FikoRenkler.neonAmber, _isik(s), s.isikZaman.isNotEmpty), _Tab('🎨 Stil', FikoRenkler.neonMor, _stil(s), s.stil.isNotEmpty || s.renkPaleti.isNotEmpty), if (s.nsfwAcik) _Tab('🔞 NSFW', const Color(0xFFFF2E6A), _nsfw(s), s.nsfwSecimler.isNotEmpty), ]; return tablar; } // ── Sekmeler ── Widget _sahne(VideoSihirbazSecimleri s) { final oneriler = VideoSihirbazKataloglari.ozneOnerileri[s.sahneTuru] ?? VideoSihirbazKataloglari.genelOzneler; return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ _tek('Sahne türü', VideoSihirbazKataloglari.sahneTurleri, s.sahneTuru, (id) => _g(s.kopyala(sahneTuru: id, ozne: ''))), _tek('Özne önerisi', oneriler, s.ozne, (id) => _g(s.kopyala(ozne: id))), ]); } Widget _kamera(VideoSihirbazSecimleri s) => Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ _coklu('Hareket', VideoKataloglari.kameraHareketleri, s.kameraHareketi, (yeni) => _g(s.kopyala(kameraHareketi: yeni))), _tek('Açı', VideoSihirbazKataloglari.kameraAcilari, s.kameraAcisi, (id) => _g(s.kopyala(kameraAcisi: id))), _tek('Lens', VideoSihirbazKataloglari.lensler, s.lens, (id) => _g(s.kopyala(lens: id))), ]); Widget _hareket(VideoSihirbazSecimleri s) => Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ _tek('Yoğunluk', VideoKataloglari.hareketYogunlugu, s.hareketYogunlugu, (id) => _g(s.kopyala(hareketYogunlugu: id))), _tek('Hız duygusu', VideoSihirbazKataloglari.hizDuygulari, s.hizDuygusu, (id) => _g(s.kopyala(hizDuygusu: id))), ]); Widget _atmosfer(VideoSihirbazSecimleri s) => Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ _coklu('Atmosfer', VideoKataloglari.atmosfer, s.atmosfer, (yeni) => _g(s.kopyala(atmosfer: yeni))), _coklu('Efekt dokunuşları', VideoSihirbazKataloglari.efektDokunuslari, s.efektDokunuslari, (yeni) => _g(s.kopyala(efektDokunuslari: yeni))), ]); Widget _isik(VideoSihirbazSecimleri s) => Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ _tek('Işık / Zaman', VideoKataloglari.isikZaman, s.isikZaman, (id) => _g(s.kopyala(isikZaman: id))), ]); Widget _stil(VideoSihirbazSecimleri s) => Column(crossAxisAlignment: CrossAxisAlignment.start, children: [ _tek('Stil', VideoSihirbazKataloglari.stiller, s.stil, (id) => _g(s.kopyala(stil: id))), _tek('Renk paleti', VideoSihirbazKataloglari.renkPaletleri, s.renkPaleti, (id) => _g(s.kopyala(renkPaleti: id))), ]); Widget _nsfw(VideoSihirbazSecimleri s) { final seviyeIdleri = NsfwKataloglari.seviye.map((o) => o.id).toSet(); final seciliSeviye = s.nsfwSecimler .firstWhere(seviyeIdleri.contains, orElse: () => ''); return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( padding: const EdgeInsets.symmetric(horizontal: 9, vertical: 6), decoration: BoxDecoration( color: const Color(0xFFFF2E6A).withValues(alpha: 0.1), borderRadius: BorderRadius.circular(7), ), child: const Text('18+ içerik · sadece yetişkin (adult) üretim', style: TextStyle(fontSize: 10.5, color: Color(0xFFFF2E6A))), ), const SizedBox(height: 6), for (final g in NsfwKataloglari.gruplar) g.cokluSecim ? _coklu(g.ad, _videoOge(g.ogeler), s.nsfwSecimler, (yeni) => _g(s.kopyala(nsfwSecimler: yeni))) : _tek(g.ad, _videoOge(g.ogeler), seciliSeviye, (id) { final yeni = Set.from(s.nsfwSecimler) ..removeAll(seviyeIdleri); if (id.isNotEmpty) yeni.add(id); _g(s.kopyala(nsfwSecimler: yeni)); }), ], ); } // ── Canlı önizleme ── Widget _onizleme(VideoSihirbazSecimleri s) { final tema = Theme.of(context); return Container( width: double.infinity, margin: const EdgeInsets.only(top: 6), padding: const EdgeInsets.all(8), decoration: BoxDecoration( color: tema.colorScheme.surface, borderRadius: BorderRadius.circular(8), border: Border.all(color: tema.dividerColor), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row(children: [ Icon(Icons.preview, size: 13, color: FikoRenkler.neonCyan), SizedBox(width: 5), Text('Önizleme', style: TextStyle(fontSize: 11, fontWeight: FontWeight.w700)), ]), const SizedBox(height: 4), SelectableText(s.promptDerle(), style: TextStyle( fontSize: 10.5, height: 1.35, color: tema.colorScheme.onSurface.withValues(alpha: 0.85))), const SizedBox(height: 3), SelectableText('Negatif: ${s.negatifDerle()}', style: TextStyle( fontSize: 10, height: 1.3, color: const Color(0xFFFF5370).withValues(alpha: 0.85))), ], ), ); } // ── Yardımcılar ── static List _videoOge(List ogeler) => [ for (final o in ogeler) VideoOge(o.id, o.etiketTr, o.promptEn), ]; Widget _tek(String etiket, List ogeler, String secili, ValueChanged onSec) => _TekSecimSatiri( etiket: etiket, ogeler: ogeler, secili: secili, onSec: onSec); Widget _coklu(String etiket, List ogeler, Set secili, ValueChanged> onDegisti) => _CokluSecimSatiri( etiket: etiket, ogeler: ogeler, secili: secili, onDegisti: onDegisti); } class _Tab { const _Tab(this.etiket, this.renk, this.icerik, this.dolu); final String etiket; final Color renk; final Widget icerik; final bool dolu; } class _TabCip extends StatelessWidget { const _TabCip({ required this.etiket, required this.renk, required this.secili, required this.dolu, required this.onTap, }); final String etiket; final Color renk; final bool secili; final bool dolu; final VoidCallback onTap; @override Widget build(BuildContext context) { final tema = Theme.of(context); return GestureDetector( onTap: onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 140), padding: const EdgeInsets.symmetric(horizontal: 11, vertical: 6), decoration: BoxDecoration( color: secili ? renk.withValues(alpha: 0.2) : tema.colorScheme.surface, borderRadius: BorderRadius.circular(8), border: Border.all( color: secili ? renk : tema.dividerColor, width: secili ? 1.4 : 1, ), ), child: Row( mainAxisSize: MainAxisSize.min, children: [ Text(etiket, style: TextStyle( fontSize: 11.5, fontWeight: secili ? FontWeight.w700 : FontWeight.w500, color: secili ? renk : tema.colorScheme.onSurface)), if (dolu && !secili) ...[ const SizedBox(width: 4), Container( width: 6, height: 6, decoration: BoxDecoration(color: renk, shape: BoxShape.circle), ), ], ], ), ), ); } } /// Etiket + tek seçim çipleri satırı. class _TekSecimSatiri extends StatelessWidget { const _TekSecimSatiri({ required this.etiket, required this.ogeler, required this.secili, required this.onSec, }); final String etiket; final List ogeler; final String secili; final ValueChanged onSec; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 3), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(etiket, style: const TextStyle( fontSize: 11.5, fontWeight: FontWeight.w600)), const SizedBox(height: 4), Wrap( spacing: 5, runSpacing: 5, children: [ for (final o in ogeler) _MiniCip( etiket: o.etiketTr, secili: secili == o.id, onTap: () => onSec(secili == o.id ? '' : o.id), ), ], ), ], ), ); } } /// Çoklu seçim çipleri satırı. class _CokluSecimSatiri extends StatelessWidget { const _CokluSecimSatiri({ required this.etiket, required this.ogeler, required this.secili, required this.onDegisti, }); final String etiket; final List ogeler; final Set secili; final ValueChanged> onDegisti; @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 3), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(secili.isEmpty ? etiket : '$etiket (${secili.length})', style: const TextStyle( fontSize: 11.5, fontWeight: FontWeight.w600)), const SizedBox(height: 4), Wrap( spacing: 5, runSpacing: 5, children: [ for (final o in ogeler) _MiniCip( etiket: o.etiketTr, secili: secili.contains(o.id), onTap: () { final yeni = Set.from(secili); yeni.contains(o.id) ? yeni.remove(o.id) : yeni.add(o.id); onDegisti(yeni); }, ), ], ), ], ), ); } } class _MiniCip extends StatelessWidget { const _MiniCip({ required this.etiket, required this.secili, required this.onTap, }); final String etiket; final bool secili; final VoidCallback onTap; @override Widget build(BuildContext context) { final tema = Theme.of(context); const vurgu = FikoRenkler.neonPembe; return GestureDetector( onTap: onTap, child: AnimatedContainer( duration: const Duration(milliseconds: 120), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3.5), decoration: BoxDecoration( color: secili ? vurgu.withValues(alpha: 0.22) : tema.colorScheme.surface, borderRadius: BorderRadius.circular(6), border: Border.all( color: secili ? vurgu : tema.dividerColor, width: secili ? 1.2 : 1), ), child: Text(etiket, style: TextStyle( fontSize: 11, height: 1.1, fontWeight: secili ? FontWeight.w700 : FontWeight.w500, color: secili ? vurgu : tema.colorScheme.onSurface)), ), ); } }