add custom audio player widget
This commit is contained in:
parent
5c2f8fa014
commit
551bec7982
2 changed files with 107 additions and 5 deletions
|
|
@ -27,6 +27,7 @@ import "package:nexus/widgets/chat_page/lazy_loading/message_displayname.dart";
|
||||||
import "package:nexus/widgets/link_preview.dart";
|
import "package:nexus/widgets/link_preview.dart";
|
||||||
import "package:nexus/widgets/loading.dart";
|
import "package:nexus/widgets/loading.dart";
|
||||||
import "package:nexus/widgets/players/video.dart";
|
import "package:nexus/widgets/players/video.dart";
|
||||||
|
import "package:nexus/widgets/players/audio.dart";
|
||||||
import "package:timeago/timeago.dart";
|
import "package:timeago/timeago.dart";
|
||||||
import "package:flutter_linkify/flutter_linkify.dart";
|
import "package:flutter_linkify/flutter_linkify.dart";
|
||||||
|
|
||||||
|
|
@ -120,10 +121,7 @@ class RenderEvent extends ConsumerWidget {
|
||||||
: colorScheme.surfaceContainer,
|
: colorScheme.surfaceContainer,
|
||||||
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: EdgeInsets.symmetric(
|
padding: EdgeInsets.all(12),
|
||||||
horizontal: 12,
|
|
||||||
vertical: 8,
|
|
||||||
),
|
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
|
|
@ -238,7 +236,10 @@ class RenderEvent extends ConsumerWidget {
|
||||||
:final info,
|
:final info,
|
||||||
) =>
|
) =>
|
||||||
VideoPlayer(url, info),
|
VideoPlayer(url, info),
|
||||||
// TODO: Support audio
|
AudioMessageContent(
|
||||||
|
:final info,
|
||||||
|
) =>
|
||||||
|
AudioPlayer(url, info),
|
||||||
// FileMessageContent(
|
// FileMessageContent(
|
||||||
// :final info,
|
// :final info,
|
||||||
// ) =>
|
// ) =>
|
||||||
|
|
|
||||||
101
lib/widgets/players/audio.dart
Normal file
101
lib/widgets/players/audio.dart
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
import "dart:async";
|
||||||
|
|
||||||
|
import "package:flutter/material.dart";
|
||||||
|
import "package:flutter_hooks/flutter_hooks.dart";
|
||||||
|
import "package:hooks_riverpod/hooks_riverpod.dart";
|
||||||
|
import "package:media_kit/media_kit.dart";
|
||||||
|
import "package:nexus/helpers/extensions/get_headers.dart";
|
||||||
|
import "package:nexus/models/info/audio.dart";
|
||||||
|
|
||||||
|
class AudioPlayer extends HookConsumerWidget {
|
||||||
|
final Uri url;
|
||||||
|
final AudioInfo? info;
|
||||||
|
|
||||||
|
const AudioPlayer(this.url, this.info, {super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
final player = useMemoized(
|
||||||
|
() => Player(
|
||||||
|
configuration: PlayerConfiguration(bufferSize: 128 * 1024 * 1024),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
final playing = useState(false);
|
||||||
|
final position = useState(Duration.zero);
|
||||||
|
final duration = useState(Duration.zero);
|
||||||
|
|
||||||
|
useEffect(() {
|
||||||
|
scheduleMicrotask(() async {
|
||||||
|
await player.open(
|
||||||
|
Media(url.toString(), httpHeaders: ref.headers),
|
||||||
|
play: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
player.stream.playing.listen((value) {
|
||||||
|
playing.value = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
player.stream.position.listen((value) {
|
||||||
|
position.value = value;
|
||||||
|
});
|
||||||
|
|
||||||
|
player.stream.duration.listen((value) {
|
||||||
|
duration.value = value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
return player.dispose;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
String format(Duration duration) {
|
||||||
|
final minutes = duration.inMinutes
|
||||||
|
.remainder(60)
|
||||||
|
.toString()
|
||||||
|
.padLeft(2, "0");
|
||||||
|
final seconds = duration.inSeconds
|
||||||
|
.remainder(60)
|
||||||
|
.toString()
|
||||||
|
.padLeft(2, "0");
|
||||||
|
|
||||||
|
return "$minutes:$seconds";
|
||||||
|
}
|
||||||
|
|
||||||
|
return Card(
|
||||||
|
color: Theme.of(context).colorScheme.surfaceContainer,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsetsGeometry.only(left: 8, right: 16),
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
IconButton(
|
||||||
|
onPressed: player.playOrPause,
|
||||||
|
icon: Icon(
|
||||||
|
playing.value ? Icons.pause_circle : Icons.play_circle,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
SizedBox(width: 8),
|
||||||
|
Text(
|
||||||
|
format(position.value),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Slider(
|
||||||
|
min: 0,
|
||||||
|
max: duration.value.inMilliseconds <= 0
|
||||||
|
? 1
|
||||||
|
: duration.value.inMilliseconds.toDouble(),
|
||||||
|
value: position.value.inMilliseconds.toDouble(),
|
||||||
|
onChanged: (value) =>
|
||||||
|
player.seek(Duration(milliseconds: value.toInt())),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
format(duration.value),
|
||||||
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue