123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296 |
- import "dart:io";
- import "package:flutter/cupertino.dart";
- import "package:flutter/material.dart";
- import "package:media_kit/media_kit.dart";
- import "package:media_kit_video/media_kit_video.dart";
- import "package:photos/generated/l10n.dart";
- import "package:photos/models/file/extensions/file_props.dart";
- import "package:photos/models/file/file.dart";
- import "package:photos/services/files_service.dart";
- import "package:photos/theme/colors.dart";
- import "package:photos/theme/ente_theme.dart";
- import "package:photos/ui/viewer/file/thumbnail_widget.dart";
- import "package:photos/utils/dialog_util.dart";
- import "package:photos/utils/file_util.dart";
- import "package:photos/utils/toast_util.dart";
- class VideoWidgetNew extends StatefulWidget {
- final EnteFile file;
- final String? tagPrefix;
- const VideoWidgetNew(
- this.file, {
- this.tagPrefix,
- super.key,
- });
- @override
- State<VideoWidgetNew> createState() => _VideoWidgetNewState();
- }
- class _VideoWidgetNewState extends State<VideoWidgetNew> {
- static const verticalMargin = 100.0;
- late final player = Player();
- VideoController? controller;
- final _progressNotifier = ValueNotifier<double?>(null);
- @override
- void initState() {
- super.initState();
- if (widget.file.isRemoteFile) {
- _loadNetworkVideo();
- _setFileSizeIfNull();
- } else if (widget.file.isSharedMediaToAppSandbox) {
- final localFile = File(getSharedMediaFilePath(widget.file));
- if (localFile.existsSync()) {
- _setVideoController(localFile.path);
- } else if (widget.file.uploadedFileID != null) {
- _loadNetworkVideo();
- }
- } else {
- widget.file.getAsset.then((asset) async {
- if (asset == null || !(await asset.exists)) {
- if (widget.file.uploadedFileID != null) {
- _loadNetworkVideo();
- }
- } else {
- asset.getMediaUrl().then((url) {
- _setVideoController(
- url ??
- 'https://user-images.githubusercontent.com/28951144/229373695-22f88f13-d18f-4288-9bf1-c3e078d83722.mp4',
- );
- });
- }
- });
- }
- }
- @override
- void dispose() {
- player.dispose();
- // _progressNotifier.dispose();
- super.dispose();
- }
- @override
- Widget build(BuildContext context) {
- final colorScheme = getEnteColorScheme(context);
- return Hero(
- tag: widget.tagPrefix! + widget.file.tag,
- child: MaterialVideoControlsTheme(
- normal: MaterialVideoControlsThemeData(
- automaticallyImplySkipNextButton: false,
- automaticallyImplySkipPreviousButton: false,
- seekOnDoubleTap: false,
- displaySeekBar: true,
- seekBarMargin: const EdgeInsets.only(bottom: verticalMargin),
- bottomButtonBarMargin: const EdgeInsets.only(bottom: 112),
- controlsHoverDuration: const Duration(seconds: 3),
- seekBarHeight: 4,
- seekBarBufferColor: Colors.transparent,
- seekBarThumbColor: backgroundElevatedLight,
- seekBarColor: fillMutedDark,
- seekBarPositionColor: colorScheme.primary300,
- topButtonBarMargin: const EdgeInsets.only(top: verticalMargin),
- bufferingIndicatorBuilder: (p0) {
- return OverflowBox(
- maxHeight: MediaQuery.sizeOf(context).height,
- maxWidth: MediaQuery.sizeOf(context).width,
- child: _getLoadingWidget(),
- );
- },
- bottomButtonBar: [
- const Spacer(),
- PausePlayAndDuration(controller?.player),
- const Spacer(),
- ],
- primaryButtonBar: [],
- ),
- fullscreen: const MaterialVideoControlsThemeData(),
- child: Center(
- child: controller != null
- ? Video(
- controller: controller!,
- )
- : _getLoadingWidget(),
- ),
- ),
- );
- }
- void _loadNetworkVideo() {
- getFileFromServer(
- widget.file,
- progressCallback: (count, total) {
- _progressNotifier.value = count / (widget.file.fileSize ?? total);
- if (_progressNotifier.value == 1) {
- if (mounted) {
- showShortToast(context, S.of(context).decryptingVideo);
- }
- }
- },
- ).then((file) {
- if (file != null) {
- _setVideoController(file.path);
- }
- }).onError((error, stackTrace) {
- showErrorDialog(context, "Error", S.of(context).failedToDownloadVideo);
- });
- }
- void _setFileSizeIfNull() {
- if (widget.file.fileSize == null && widget.file.canEditMetaInfo) {
- FilesService.instance
- .getFileSize(widget.file.uploadedFileID!)
- .then((value) {
- widget.file.fileSize = value;
- if (mounted) {
- setState(() {});
- }
- });
- }
- }
- Widget _getLoadingWidget() {
- return Stack(
- children: [
- _getThumbnail(),
- Container(
- color: Colors.black12,
- constraints: const BoxConstraints.expand(),
- ),
- Center(
- child: SizedBox.fromSize(
- size: const Size.square(20),
- child: ValueListenableBuilder(
- valueListenable: _progressNotifier,
- builder: (BuildContext context, double? progress, _) {
- return progress == null || progress == 1
- ? const CupertinoActivityIndicator(
- color: Colors.white,
- )
- : CircularProgressIndicator(
- backgroundColor: Colors.black,
- value: progress,
- valueColor: const AlwaysStoppedAnimation<Color>(
- Color.fromRGBO(45, 194, 98, 1.0),
- ),
- );
- },
- ),
- ),
- ),
- ],
- );
- }
- Widget _getThumbnail() {
- return Container(
- color: Colors.black,
- constraints: const BoxConstraints.expand(),
- child: ThumbnailWidget(
- widget.file,
- fit: BoxFit.contain,
- ),
- );
- }
- void _setVideoController(String url) {
- if (mounted) {
- setState(() {
- controller = VideoController(player);
- player.open(Media(url));
- });
- }
- }
- }
- class PausePlayAndDuration extends StatefulWidget {
- final Player? player;
- const PausePlayAndDuration(this.player, {super.key});
- @override
- State<PausePlayAndDuration> createState() => _PausePlayAndDurationState();
- }
- class _PausePlayAndDurationState extends State<PausePlayAndDuration> {
- Color backgroundColor = fillMutedLight;
- @override
- Widget build(BuildContext context) {
- return GestureDetector(
- onTapDown: (details) {
- setState(() {
- backgroundColor = fillMutedDark;
- });
- },
- onTapUp: (details) {
- Future.delayed(const Duration(milliseconds: 175), () {
- if (mounted) {
- setState(() {
- backgroundColor = fillMutedLight;
- });
- }
- });
- },
- onTapCancel: () {
- Future.delayed(const Duration(milliseconds: 175), () {
- if (mounted) {
- setState(() {
- backgroundColor = fillMutedLight;
- });
- }
- });
- },
- onTap: () => widget.player!.playOrPause(),
- child: AnimatedContainer(
- duration: const Duration(milliseconds: 150),
- curve: Curves.easeInBack,
- padding: const EdgeInsets.symmetric(vertical: 4, horizontal: 8),
- decoration: BoxDecoration(
- color: backgroundColor,
- border: Border.all(
- color: strokeFaintDark,
- width: 1,
- ),
- borderRadius: BorderRadius.circular(24),
- ),
- child: AnimatedSize(
- duration: const Duration(seconds: 2),
- curve: Curves.easeInOutExpo,
- child: Row(
- children: [
- StreamBuilder(
- builder: (context, snapshot) {
- final bool isPlaying = snapshot.data ?? false;
- return AnimatedSwitcher(
- duration: const Duration(milliseconds: 350),
- switchInCurve: Curves.easeInOutCirc,
- switchOutCurve: Curves.easeInOutCirc,
- child: Icon(
- key: ValueKey(
- isPlaying ? "pause_button" : "play_button",
- ),
- isPlaying
- ? Icons.pause_rounded
- : Icons.play_arrow_rounded,
- color: backdropBaseLight,
- ),
- );
- },
- initialData: widget.player?.state.playing,
- stream: widget.player?.stream.playing,
- ),
- const SizedBox(width: 8),
- MaterialPositionIndicator(
- style: getEnteTextTheme(context).mini.copyWith(
- color: textBaseDark,
- ),
- ),
- const SizedBox(width: 10),
- ],
- ),
- ),
- ),
- );
- }
- }
|