import 'dart:io'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import '../app/tema.dart'; import '../cekirdek/ffmpeg_servisi.dart'; import 'ses_calar.dart'; /// Dalga formu + spektrum görselini ffmpeg'den lazy üretip önbellekler. final dalgaFormuProvider = FutureProvider.family((ref, yol) async { return FfmpegServisi.dalgaFormu(yol); }); final spektrumProvider = FutureProvider.family((ref, yol) async { return FfmpegServisi.spektrum(yol); }); /// Profesyonel müzik çalar — dalga formu/spektrum, playhead, seek, kontroller. class ProfesyonelCalar extends ConsumerStatefulWidget { const ProfesyonelCalar({super.key, required this.dosyaYolu, this.kompakt = false}); final String dosyaYolu; final bool kompakt; @override ConsumerState createState() => _ProfesyonelCalarState(); } class _ProfesyonelCalarState extends ConsumerState { bool _spektrum = false; @override Widget build(BuildContext context) { final durum = ref.watch(sesCalarProvider); final calar = ref.read(sesCalarProvider.notifier); final benimki = durum.dosya == widget.dosyaYolu; final caliyor = benimki && durum.caliyor; final varMi = File(widget.dosyaYolu).existsSync(); final oran = (benimki && durum.sure.inMilliseconds > 0) ? durum.konum.inMilliseconds / durum.sure.inMilliseconds : 0.0; final gorselYol = _spektrum ? ref.watch(spektrumProvider(widget.dosyaYolu)).valueOrNull : ref.watch(dalgaFormuProvider(widget.dosyaYolu)).valueOrNull; final yukseklik = widget.kompakt ? 46.0 : 96.0; return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ // Dalga formu / spektrum + playhead, tıkla-seek LayoutBuilder(builder: (context, c) { return GestureDetector( onTapDown: (d) { if (benimki && durum.sure.inMilliseconds > 0) { final o = (d.localPosition.dx / c.maxWidth).clamp(0.0, 1.0); calar.atla(Duration( milliseconds: (durum.sure.inMilliseconds * o).round())); } }, child: Container( height: yukseklik, decoration: BoxDecoration( color: Theme.of(context).colorScheme.surface, borderRadius: BorderRadius.circular(8), border: Border.all(color: Theme.of(context).dividerColor), ), clipBehavior: Clip.antiAlias, child: Stack( fit: StackFit.expand, children: [ if (gorselYol != null && File(gorselYol).existsSync()) Image.file(File(gorselYol), fit: BoxFit.fill, gaplessPlayback: true) else Center( child: Icon(Icons.graphic_eq, size: 26, color: FikoRenkler.neonCyan.withValues(alpha: 0.4)), ), // Çalınan kısım vurgusu if (benimki) Align( alignment: Alignment.centerLeft, child: FractionallySizedBox( widthFactor: oran.clamp(0.0, 1.0), child: Container( color: FikoRenkler.neonCyan.withValues(alpha: 0.12), ), ), ), // Playhead çizgisi if (benimki && oran > 0) Align( alignment: Alignment(-1 + 2 * oran.clamp(0.0, 1.0), 0), child: Container( width: 2, color: FikoRenkler.neonPembe), ), ], ), ), ); }), const SizedBox(height: 6), // Kontrol satırı Row( children: [ IconButton( visualDensity: VisualDensity.compact, icon: Icon( caliyor ? Icons.pause_circle_filled : Icons.play_circle_fill, size: 30, color: varMi ? FikoRenkler.neonCyan : Colors.grey), onPressed: varMi ? () => calar.calDurdur(widget.dosyaYolu) : null, ), Text( benimki ? '${_fmt(durum.konum)} / ${_fmt(durum.sure)}' : '0:00', style: const TextStyle(fontSize: 10.5), ), const Spacer(), // Spektrum/dalga geçişi IconButton( visualDensity: VisualDensity.compact, tooltip: _spektrum ? 'Dalga formu' : 'Spektrum', icon: Icon(_spektrum ? Icons.show_chart : Icons.gradient, size: 17, color: _spektrum ? FikoRenkler.neonMor : null), onPressed: () => setState(() => _spektrum = !_spektrum), ), ], ), ], ); } static String _fmt(Duration d) => '${d.inMinutes}:${(d.inSeconds % 60).toString().padLeft(2, '0')}'; }