fixup video playback on apple platforms
This commit is contained in:
parent
84dd903bc4
commit
0e29690134
5 changed files with 144 additions and 68 deletions
|
|
@ -32,7 +32,7 @@ class const AudioPlayer(
|
||||||
// Keeps the audio loaded after it finishes, so it can be replayed
|
// Keeps the audio loaded after it finishes, so it can be replayed
|
||||||
await player.setReleaseMode(.stop);
|
await player.setReleaseMode(.stop);
|
||||||
try {
|
try {
|
||||||
// AVFoundation infers the format from the extension, which the cached file lacks
|
// AVFoundation needs the format, since gomuks caches files without an extension
|
||||||
await player.setSource(
|
await player.setSource(
|
||||||
audioplayers.DeviceFileSource(audio.path, mimeType: info?.mimeType),
|
audioplayers.DeviceFileSource(audio.path, mimeType: info?.mimeType),
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,9 @@ import "package:material_ui/material_ui.dart";
|
||||||
import "package:hooks_riverpod/hooks_riverpod.dart";
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
import "package:nexus/controllers/client.dart";
|
import "package:nexus/controllers/client.dart";
|
||||||
import "package:nexus/helpers/extensions/save_attachment.dart";
|
import "package:nexus/helpers/extensions/save_attachment.dart";
|
||||||
|
import "package:mime/mime.dart";
|
||||||
import "package:nexus/models/info/video.dart";
|
import "package:nexus/models/info/video.dart";
|
||||||
|
import "package:nexus/widgets/common/error_dialog.dart";
|
||||||
import "package:flutter_hooks/flutter_hooks.dart";
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
import "package:nexus/widgets/players/player_controls.dart";
|
import "package:nexus/widgets/players/player_controls.dart";
|
||||||
|
|
||||||
|
|
@ -43,6 +45,8 @@ class const VideoPlayer(
|
||||||
}, [controller]);
|
}, [controller]);
|
||||||
|
|
||||||
final playing = value.value?.isPlaying ?? false;
|
final playing = value.value?.isPlaying ?? false;
|
||||||
|
final ready = isLoaded && (value.value?.initialized ?? false);
|
||||||
|
final error = value.value?.errorDescription;
|
||||||
|
|
||||||
// better_player doesn't use material_ui, so this Material is needed.
|
// better_player doesn't use material_ui, so this Material is needed.
|
||||||
return Material(
|
return Material(
|
||||||
|
|
@ -52,13 +56,55 @@ class const VideoPlayer(
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
behavior: .opaque,
|
behavior: .opaque,
|
||||||
onTap: isLoaded
|
onTap: ready
|
||||||
? playing
|
? playing
|
||||||
? controller.pause
|
? controller.pause
|
||||||
: controller.play
|
: controller.play
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (error != null)
|
||||||
|
Positioned.fill(
|
||||||
|
child: ColoredBox(
|
||||||
|
color: Colors.black54,
|
||||||
|
child: Center(
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: .min,
|
||||||
|
children: [
|
||||||
|
Padding(
|
||||||
|
padding: .all(12),
|
||||||
|
child: Icon(
|
||||||
|
Icons.videocam_off,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.error,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Flexible(
|
||||||
|
child: Text(
|
||||||
|
"Can't play this video",
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.bodySmall
|
||||||
|
?.copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.error,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => ErrorDialog(error, null),
|
||||||
|
),
|
||||||
|
child: Text("Show Error"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
Positioned(
|
Positioned(
|
||||||
top: 4,
|
top: 4,
|
||||||
right: 4,
|
right: 4,
|
||||||
|
|
@ -77,50 +123,51 @@ class const VideoPlayer(
|
||||||
icon: Icon(Icons.download),
|
icon: Icon(Icons.download),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Positioned(
|
if (error == null)
|
||||||
left: 0,
|
Positioned(
|
||||||
right: 0,
|
left: 0,
|
||||||
bottom: 0,
|
right: 0,
|
||||||
child: DecoratedBox(
|
bottom: 0,
|
||||||
decoration: const BoxDecoration(
|
child: DecoratedBox(
|
||||||
gradient: LinearGradient(
|
decoration: const BoxDecoration(
|
||||||
begin: .bottomCenter,
|
gradient: LinearGradient(
|
||||||
end: .topCenter,
|
begin: .bottomCenter,
|
||||||
colors: [Colors.black54, Colors.transparent],
|
end: .topCenter,
|
||||||
|
colors: [Colors.black54, Colors.transparent],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
child: Padding(
|
||||||
child: Padding(
|
padding: const .only(left: 4, right: 4, top: 16),
|
||||||
padding: const .only(left: 4, right: 4, top: 16),
|
child: PlayerControls(
|
||||||
child: PlayerControls(
|
playing: playing,
|
||||||
playing: playing,
|
buffering: value.value?.isBuffering ?? false,
|
||||||
buffering: value.value?.isBuffering ?? false,
|
position: value.value?.position ?? .zero,
|
||||||
position: value.value?.position ?? .zero,
|
duration: value.value?.duration ?? .zero,
|
||||||
duration: value.value?.duration ?? .zero,
|
onPlayPause: playing
|
||||||
onPlayPause: playing
|
? controller.pause
|
||||||
? controller.pause
|
: controller.play,
|
||||||
: controller.play,
|
onSeek: controller.seekTo,
|
||||||
onSeek: controller.seekTo,
|
loading: !ready,
|
||||||
loading: !isLoaded,
|
size: info?.size,
|
||||||
size: info?.size,
|
color: Colors.white,
|
||||||
color: Colors.white,
|
actions: .new([
|
||||||
actions: .new([
|
IconButton(
|
||||||
IconButton(
|
onPressed: controller.toggleFullScreen,
|
||||||
onPressed: controller.toggleFullScreen,
|
color: Colors.white,
|
||||||
color: Colors.white,
|
tooltip: controller.isFullScreen
|
||||||
tooltip: controller.isFullScreen
|
? "Exit fullscreen"
|
||||||
? "Exit fullscreen"
|
: "Fullscreen",
|
||||||
: "Fullscreen",
|
icon: Icon(
|
||||||
icon: Icon(
|
controller.isFullScreen
|
||||||
controller.isFullScreen
|
? Icons.fullscreen_exit
|
||||||
? Icons.fullscreen_exit
|
: Icons.fullscreen,
|
||||||
: Icons.fullscreen,
|
),
|
||||||
),
|
),
|
||||||
),
|
]),
|
||||||
]),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
@ -137,7 +184,15 @@ class const VideoPlayer(
|
||||||
.read(ClientController.provider.notifier)
|
.read(ClientController.provider.notifier)
|
||||||
.downloadMedia(.new(mxc: uri, encrypted: encrypted));
|
.downloadMedia(.new(mxc: uri, encrypted: encrypted));
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
await controller.setupDataSource(.file(video.path));
|
await controller.setupDataSource(
|
||||||
|
.file(
|
||||||
|
video.path,
|
||||||
|
videoExtension: switch (info?.mimeType) {
|
||||||
|
final mimeType? => extensionFromMime(mimeType),
|
||||||
|
null => null,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
// better_player's mpv backend (Linux and Windows) starts playing as
|
// better_player's mpv backend (Linux and Windows) starts playing as
|
||||||
// soon as it loads a file, despite autoPlay being off
|
// soon as it loads a file, despite autoPlay being off
|
||||||
await controller.pause();
|
await controller.pause();
|
||||||
|
|
|
||||||
|
|
@ -55,6 +55,9 @@ flutter.buildFlutterApplication {
|
||||||
customSourceBuilders.avif_native = callPackage ./avif_native.nix { };
|
customSourceBuilders.avif_native = callPackage ./avif_native.nix { };
|
||||||
|
|
||||||
gitHashes = {
|
gitHashes = {
|
||||||
|
better_player = "sha256-7OoRdtbswGcP97Vn+Jkj3lBU8h2slJ/KPz98G3XOyNQ=";
|
||||||
|
better_player_ios = "sha256-7OoRdtbswGcP97Vn+Jkj3lBU8h2slJ/KPz98G3XOyNQ=";
|
||||||
|
better_player_macos = "sha256-7OoRdtbswGcP97Vn+Jkj3lBU8h2slJ/KPz98G3XOyNQ=";
|
||||||
linkify = "sha256-TpMD6+0zyY6i9l+6d8ErnVufmepCv362rCtnbOht/z4=";
|
linkify = "sha256-TpMD6+0zyY6i9l+6d8ErnVufmepCv362rCtnbOht/z4=";
|
||||||
location = "sha256-zWnffXiK1LD4Ln23coPozBjYfTlhZmBhC5Z8mCdAgwQ=";
|
location = "sha256-zWnffXiK1LD4Ln23coPozBjYfTlhZmBhC5Z8mCdAgwQ=";
|
||||||
fab_m3e = "sha256-5V9m6yY0jimx2gh7lQHYg4HDKQ4Wrl0ATmBhw5DkQMI=";
|
fab_m3e = "sha256-5V9m6yY0jimx2gh7lQHYg4HDKQ4Wrl0ATmBhw5DkQMI=";
|
||||||
|
|
|
||||||
53
pubspec.lock
53
pubspec.lock
|
|
@ -164,43 +164,46 @@ packages:
|
||||||
better_player:
|
better_player:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
name: better_player
|
path: "packages/better_player"
|
||||||
sha256: bde9cc4c35f8ccca5e75465934b51ac11db5cbfca7b221f2122d546bb5c5b324
|
ref: "quad/feat/mimetypes"
|
||||||
url: "https://pub.dev"
|
resolved-ref: "0f9d7f391973cf1e2096fd7f9a7c9d3c0586a687"
|
||||||
source: hosted
|
url: "https://github.com/Henry-Hiles/betterplayer"
|
||||||
version: "1.36.0"
|
source: git
|
||||||
|
version: "1.37.0"
|
||||||
better_player_android:
|
better_player_android:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: better_player_android
|
name: better_player_android
|
||||||
sha256: "2a1eb33ff1f67155f8840224836a6c90e95b335263986bcce78e89bf837be04e"
|
sha256: "24d3ce6c357186e0ec1eed63519e47a552bdc497ad48556f32593f5d6b406672"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.13.0"
|
version: "1.13.1"
|
||||||
better_player_ios:
|
better_player_ios:
|
||||||
dependency: transitive
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
name: better_player_ios
|
path: "packages/better_player_ios"
|
||||||
sha256: d26bc4b7d6d8c8047772f498fcdfe7cd896aecf156842d0fca9072d13eb4864b
|
ref: "quad/feat/mimetypes"
|
||||||
url: "https://pub.dev"
|
resolved-ref: "0f9d7f391973cf1e2096fd7f9a7c9d3c0586a687"
|
||||||
source: hosted
|
url: "https://github.com/Henry-Hiles/betterplayer"
|
||||||
version: "1.13.0"
|
source: git
|
||||||
|
version: "1.14.0"
|
||||||
better_player_linux:
|
better_player_linux:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: better_player_linux
|
name: better_player_linux
|
||||||
sha256: "0e73f56852f7bb16b35b059f1ee40cc1b9cb84c9883dccd1e7766fcd26b3f40f"
|
sha256: "97d9eb16a587df4d714c1906ef2c49b825c1483e7d4c9050d63e696e26998f6e"
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.1.0"
|
version: "1.1.1"
|
||||||
better_player_macos:
|
better_player_macos:
|
||||||
dependency: transitive
|
dependency: "direct overridden"
|
||||||
description:
|
description:
|
||||||
name: better_player_macos
|
path: "packages/better_player_macos"
|
||||||
sha256: "9e5154bc33c1b1af22da851829b658eab7d318a33c9037c4da98bc37091dc7b7"
|
ref: "quad/feat/mimetypes"
|
||||||
url: "https://pub.dev"
|
resolved-ref: "0f9d7f391973cf1e2096fd7f9a7c9d3c0586a687"
|
||||||
source: hosted
|
url: "https://github.com/Henry-Hiles/betterplayer"
|
||||||
version: "1.8.0"
|
source: git
|
||||||
|
version: "1.9.0"
|
||||||
better_player_platform_interface:
|
better_player_platform_interface:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
@ -213,18 +216,18 @@ packages:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: better_player_web
|
name: better_player_web
|
||||||
sha256: "2faf05dc31ec9082dbd5f90cee7777887c282c2af17bb54efab4ebceae9c25f4"
|
sha256: d7b365221f7724f22d3fef7840e45af2493a784e2429a30e980f807bcb7c9539
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.6.0"
|
version: "1.6.1"
|
||||||
better_player_windows:
|
better_player_windows:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: better_player_windows
|
name: better_player_windows
|
||||||
sha256: "4bfdce8c0f9c55c362b2f931edfb2cd7cebdac757217ad09d4804ea21ec95f35"
|
sha256: eddc817dce6af08e74de456ad711ffd987a641c45f73998cbe9ccbf6ab5ebf22
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "1.5.0"
|
version: "1.5.1"
|
||||||
boolean_selector:
|
boolean_selector:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
|
|
||||||
17
pubspec.yaml
17
pubspec.yaml
|
|
@ -47,6 +47,21 @@ dependency_overrides:
|
||||||
git:
|
git:
|
||||||
url: https://github.com/appelladev/linkify
|
url: https://github.com/appelladev/linkify
|
||||||
ref: fix/consecutive-periods-loose-url
|
ref: fix/consecutive-periods-loose-url
|
||||||
|
better_player:
|
||||||
|
git:
|
||||||
|
url: https://github.com/Henry-Hiles/betterplayer
|
||||||
|
ref: quad/feat/mimetypes
|
||||||
|
path: packages/better_player
|
||||||
|
better_player_ios:
|
||||||
|
git:
|
||||||
|
url: https://github.com/Henry-Hiles/betterplayer
|
||||||
|
ref: quad/feat/mimetypes
|
||||||
|
path: packages/better_player_ios
|
||||||
|
better_player_macos:
|
||||||
|
git:
|
||||||
|
url: https://github.com/Henry-Hiles/betterplayer
|
||||||
|
ref: quad/feat/mimetypes
|
||||||
|
path: packages/better_player_macos
|
||||||
|
|
||||||
dependencies:
|
dependencies:
|
||||||
flutter:
|
flutter:
|
||||||
|
|
@ -119,7 +134,7 @@ dependencies:
|
||||||
url: https://github.com/Henry-Hiles/flutterlocation # Adds an option to leave out proprietary Google Play services, unreleased
|
url: https://github.com/Henry-Hiles/flutterlocation # Adds an option to leave out proprietary Google Play services, unreleased
|
||||||
ref: feat/optional-play-services
|
ref: feat/optional-play-services
|
||||||
path: packages/location
|
path: packages/location
|
||||||
better_player: 1.36.0
|
better_player: 1.37.0
|
||||||
audioplayers: 6.8.1
|
audioplayers: 6.8.1
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue