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. 44
      flutter_quill_extensions/lib/embeds/widgets/video_app.dart
  3. 71
      flutter_quill_extensions/lib/embeds/widgets/youtube_video_app.dart

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

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

@ -1,9 +1,13 @@
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: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 'video_app.dart';
class YoutubeVideoApp extends StatefulWidget {
const YoutubeVideoApp({
required this.videoUrl,
@ -20,11 +24,19 @@ class YoutubeVideoApp extends StatefulWidget {
class YoutubeVideoAppState extends State<YoutubeVideoApp> {
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
void initState() {
super.initState();
final videoId = YoutubePlayer.convertUrlToId(widget.videoUrl);
_videoId = YoutubePlayer.convertUrlToId(widget.videoUrl);
final videoId = _videoId;
if (videoId != null) {
_youtubeController = YoutubePlayerController(
initialVideoId: videoId,
@ -32,9 +44,33 @@ class YoutubeVideoAppState extends State<YoutubeVideoApp> {
autoPlay: false,
),
);
if (isDesktop(supportWeb: false)) {
_loadYoutubeVideoWithVideoPlayer =
_loadYoutubeVideoWithVideoPlayerByVideoUrl();
}
}
}
Future<String> _loadYoutubeVideoWithVideoPlayerByVideoUrl() async {
final youtubeExplode = YoutubeExplode();
final manifest =
await youtubeExplode.videos.streamsClient.getManifest(_videoId);
final streamInfo = manifest.muxed.withHighestBitrate();
final downloadUrl = streamInfo.url;
return downloadUrl.toString();
}
Widget _videoLink({required DefaultStyles defaultStyles}) {
return RichText(
text: TextSpan(
text: widget.videoUrl,
style: defaultStyles.link,
recognizer: TapGestureRecognizer()
..onTap = () => launchUrlString(widget.videoUrl),
),
);
}
@override
Widget build(BuildContext context) {
final defaultStyles = DefaultStyles.getInstance(context);
@ -42,16 +78,7 @@ class YoutubeVideoAppState extends State<YoutubeVideoApp> {
if (youtubeController == null) {
if (widget.readOnly) {
return RichText(
text: TextSpan(
text: widget.videoUrl,
style: defaultStyles.link,
recognizer: TapGestureRecognizer()
..onTap = () => launchUrl(
Uri.parse(widget.videoUrl),
),
),
);
return _videoLink(defaultStyles: defaultStyles);
}
return RichText(
@ -59,6 +86,24 @@ class YoutubeVideoAppState extends State<YoutubeVideoApp> {
);
}
// 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(
player: YoutubePlayer(
controller: youtubeController,

Loading…
Cancel
Save