chore: a workaround for loading a youtube video on desktop

pull/1916/head
Ellet 10 months ago
parent f61df390b3
commit e5a1e9724e
  1. 1
      flutter_quill_extensions/lib/embeds/video/editor/video_embed.dart
  2. 18
      flutter_quill_extensions/lib/embeds/widgets/video_app.dart
  3. 69
      flutter_quill_extensions/lib/embeds/widgets/youtube_video_app.dart

@ -53,7 +53,6 @@ class QuillEditorVideoEmbedBuilder extends EmbedBuilder {
alignment: alignment, alignment: alignment,
child: VideoApp( child: VideoApp(
videoUrl: videoUrl, videoUrl: videoUrl,
context: context,
readOnly: readOnly, readOnly: readOnly,
onVideoInit: configurations.onVideoInit, onVideoInit: configurations.onVideoInit,
), ),

@ -13,14 +13,16 @@ import '../../flutter_quill_extensions.dart';
class VideoApp extends StatefulWidget { class VideoApp extends StatefulWidget {
const VideoApp({ const VideoApp({
required this.videoUrl, required this.videoUrl,
required this.context,
required this.readOnly, required this.readOnly,
@Deprecated(
'The context is no longer required and will be removed on future releases',
)
BuildContext? context,
super.key, super.key,
this.onVideoInit, this.onVideoInit,
}); });
final String videoUrl; final String videoUrl;
final BuildContext context;
final bool readOnly; final bool readOnly;
final void Function(GlobalKey videoContainerKey)? onVideoInit; final void Function(GlobalKey videoContainerKey)? onVideoInit;
@ -92,7 +94,9 @@ class VideoAppState extends State<VideoApp> {
: _controller.play(); : _controller.play();
}); });
}, },
child: Stack(alignment: Alignment.center, children: [ child: Stack(
alignment: Alignment.center,
children: [
Center( Center(
child: AspectRatio( child: AspectRatio(
aspectRatio: _controller.value.aspectRatio, aspectRatio: _controller.value.aspectRatio,
@ -106,15 +110,17 @@ class VideoAppState extends State<VideoApp> {
Icons.play_arrow, Icons.play_arrow,
size: 60, size: 60,
color: Colors.blueGrey, color: Colors.blueGrey,
)) ),
]), )
],
),
), ),
); );
} }
@override @override
void dispose() { void dispose() {
super.dispose();
_controller.dispose(); _controller.dispose();
super.dispose();
} }
} }

@ -1,9 +1,13 @@
import 'package:flutter/gestures.dart' show TapGestureRecognizer; import 'package:flutter/gestures.dart' show TapGestureRecognizer;
import 'package:flutter/widgets.dart'; import 'package:flutter/material.dart';
import 'package:flutter_quill/extensions.dart';
import 'package:flutter_quill/flutter_quill.dart' show DefaultStyles; import 'package:flutter_quill/flutter_quill.dart' show DefaultStyles;
import 'package:url_launcher/url_launcher.dart' show launchUrl; import 'package:url_launcher/url_launcher_string.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
import 'package:youtube_player_flutter/youtube_player_flutter.dart'; import 'package:youtube_player_flutter/youtube_player_flutter.dart';
import 'video_app.dart';
class YoutubeVideoApp extends StatefulWidget { class YoutubeVideoApp extends StatefulWidget {
const YoutubeVideoApp({ const YoutubeVideoApp({
required this.videoUrl, required this.videoUrl,
@ -20,11 +24,19 @@ class YoutubeVideoApp extends StatefulWidget {
class YoutubeVideoAppState extends State<YoutubeVideoApp> { class YoutubeVideoAppState extends State<YoutubeVideoApp> {
YoutubePlayerController? _youtubeController; YoutubePlayerController? _youtubeController;
late String? _videoId;
/// On some platforms such as desktop, Webview is not supported yet
/// as a result the youtube video player package is not supported too
/// this future will be not null and fetch the video url to load it using
/// [VideoApp]
Future<String>? _loadYoutubeVideoWithVideoPlayer;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final videoId = YoutubePlayer.convertUrlToId(widget.videoUrl); _videoId = YoutubePlayer.convertUrlToId(widget.videoUrl);
final videoId = _videoId;
if (videoId != null) { if (videoId != null) {
_youtubeController = YoutubePlayerController( _youtubeController = YoutubePlayerController(
initialVideoId: videoId, initialVideoId: videoId,
@ -32,33 +44,66 @@ class YoutubeVideoAppState extends State<YoutubeVideoApp> {
autoPlay: false, autoPlay: false,
), ),
); );
if (isDesktop(supportWeb: false)) {
_loadYoutubeVideoWithVideoPlayer =
_loadYoutubeVideoWithVideoPlayerByVideoUrl();
}
} }
} }
@override Future<String> _loadYoutubeVideoWithVideoPlayerByVideoUrl() async {
Widget build(BuildContext context) { final youtubeExplode = YoutubeExplode();
final defaultStyles = DefaultStyles.getInstance(context); final manifest =
final youtubeController = _youtubeController; await youtubeExplode.videos.streamsClient.getManifest(_videoId);
final streamInfo = manifest.muxed.withHighestBitrate();
final downloadUrl = streamInfo.url;
return downloadUrl.toString();
}
if (youtubeController == null) { Widget _videoLink({required DefaultStyles defaultStyles}) {
if (widget.readOnly) {
return RichText( return RichText(
text: TextSpan( text: TextSpan(
text: widget.videoUrl, text: widget.videoUrl,
style: defaultStyles.link, style: defaultStyles.link,
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () => launchUrl( ..onTap = () => launchUrlString(widget.videoUrl),
Uri.parse(widget.videoUrl),
),
), ),
); );
} }
@override
Widget build(BuildContext context) {
final defaultStyles = DefaultStyles.getInstance(context);
final youtubeController = _youtubeController;
if (youtubeController == null) {
if (widget.readOnly) {
return _videoLink(defaultStyles: defaultStyles);
}
return RichText( return RichText(
text: TextSpan(text: widget.videoUrl, style: defaultStyles.link), text: TextSpan(text: widget.videoUrl, style: defaultStyles.link),
); );
} }
// Workaround as YoutubePlayer doesn't support Desktop
if (_loadYoutubeVideoWithVideoPlayer != null) {
return FutureBuilder<String>(
future: _loadYoutubeVideoWithVideoPlayer,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return const Center(child: CircularProgressIndicator.adaptive());
}
if (snapshot.hasError) {
return _videoLink(defaultStyles: defaultStyles);
}
return VideoApp(
videoUrl: snapshot.requireData,
readOnly: widget.readOnly,
);
},
);
}
return YoutubePlayerBuilder( return YoutubePlayerBuilder(
player: YoutubePlayer( player: YoutubePlayer(
controller: youtubeController, controller: youtubeController,

Loading…
Cancel
Save