import 'dart:io'; import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; import 'package:flutter/services.dart'; import 'dart:math'; import 'package:open_filex/open_filex.dart'; class MediaPreviewScreen extends StatefulWidget { final String path; final bool isVideo; const MediaPreviewScreen({ super.key, required this.path, required this.isVideo, }); @override State createState() => _MediaPreviewScreenState(); } class _MediaPreviewScreenState extends State { VideoPlayerController? _videoController; bool _isPlaying = true; String? _videoInitError; @override void initState() { super.initState(); if (widget.isVideo) { _videoController = VideoPlayerController.file(File(widget.path)) ..initialize() .then((_) { _videoInitError = null; if (!mounted) return; setState(() {}); _videoController!.setLooping(false); _videoController!.play(); }) .catchError((e) { _videoInitError = e.toString(); _videoController?.dispose().catchError((_) {}); _videoController = null; if (mounted) setState(() {}); }); _videoController!.addListener(() { if (mounted) setState(() {}); }); } } @override void dispose() { _videoController?.dispose(); super.dispose(); } String _formatDuration(Duration d) { String two(int n) => n.toString().padLeft(2, '0'); final m = two(d.inMinutes.remainder(60)); final s = two(d.inSeconds.remainder(60)); return "$m:$s"; } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Colors.black, appBar: null, body: Stack( children: [ // MEDIA Center( child: widget.isVideo ? (_videoInitError != null) ? _buildVideoInitErrorFallback() : (_videoController != null && _videoController!.value.isInitialized) ? Stack( alignment: Alignment.center, children: [ AspectRatio( aspectRatio: _videoController!.value.aspectRatio, child: VideoPlayer(_videoController!), ), // overlay controls Positioned( bottom: 40, left: 16, right: 16, child: _buildVideoControls(), ), ], ) : const CircularProgressIndicator() : Image.file(File(widget.path)), ), // BOTTOM ACTIONS (как Telegram) Positioned( bottom: 40, left: 16, right: 16, child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ // переснять ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: Colors.white10, ), onPressed: () { Navigator.pop(context, false); }, icon: const Icon(Icons.refresh), label: const Text("Переснять"), ), // отправить ElevatedButton.icon( onPressed: () { WidgetsBinding.instance.addPostFrameCallback((_) { Navigator.pop(context, true); }); }, icon: const Icon(Icons.send), label: const Text("Отправить"), ), ], ), ), ], ), ); } Widget _buildVideoControls() { final c = _videoController!; final duration = c.value.duration; final position = c.value.position; final posMs = position.inMilliseconds.toDouble(); final maxMs = duration.inMilliseconds .toDouble() .clamp(1, double.infinity) .toDouble(); return Container( child: Row( children: [ // ▶️ / ⏸ слева IconButton( padding: EdgeInsets.zero, constraints: const BoxConstraints(), icon: Icon( c.value.isPlaying ? Icons.pause : Icons.play_arrow, color: Colors.white, size: 26, ), onPressed: () { setState(() { if (c.value.isPlaying) { c.pause(); _isPlaying = false; } else { c.play(); _isPlaying = true; } }); }, ), Expanded( child: SliderTheme( data: SliderTheme.of(context).copyWith( trackHeight: 2, // ТОНКИЙ как в Telegram activeTrackColor: Colors.white, inactiveTrackColor: Colors.white24, thumbColor: Colors.white, overlayColor: Colors.transparent, thumbShape: const RoundSliderThumbShape(enabledThumbRadius: 5), ), child: Slider( value: posMs.clamp(0, maxMs).toDouble(), min: 0, max: maxMs, onChanged: (v) { c.seekTo(Duration(milliseconds: v.toInt())); }, ), ), ), const SizedBox(width: 8), Text( "${_formatDuration(position)} / ${_formatDuration(duration)}", style: const TextStyle(color: Colors.white, fontSize: 12), ), ], ), ); } Widget _buildVideoInitErrorFallback() { return Column( mainAxisSize: MainAxisSize.min, children: [ const Icon(Icons.play_disabled, color: Colors.white70, size: 48), const SizedBox(height: 10), const Text( 'Видео РЅРµ воспроизводится РЅР° этом устройстве', textAlign: TextAlign.center, style: TextStyle(color: Colors.white70), ), const SizedBox(height: 10), OutlinedButton.icon( onPressed: () async { try { await OpenFilex.open(widget.path); } catch (_) {} }, icon: const Icon(Icons.open_in_new, color: Colors.white70), label: const Text( 'Открыть внешним плеером', style: TextStyle(color: Colors.white70), ), ), ], ); } }