Skip to content
221 changes: 149 additions & 72 deletions commet/lib/ui/molecules/audio_player/audio_player.dart
Comment thread
Airyzz marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@ import 'package:commet/utils/text_utils.dart';
import 'package:flutter/material.dart';
import 'package:media_kit/media_kit.dart';
import 'package:tiamat/tiamat.dart' as tiamat;
import 'package:shared_preferences/shared_preferences.dart';

class AudioPlayer extends StatefulWidget {
const AudioPlayer(
{required this.file, this.fileName, this.fileSize, super.key});
{required this.file, this.fileName, this.fileSize, super.key});

final String? fileName;
final int? fileSize;
Expand All @@ -32,9 +33,12 @@ class _AudioPlayerState extends State<AudioPlayer> {
void initState() {
super.initState();

_loadPreferences();

subs = [
player.stream.playing.listen(onPlayingChanged),
player.stream.position.listen(onPositionChanged),
player.stream.volume.listen(onVolumeChanged),
if (widget.file.onProgressChanged != null)
widget.file.onProgressChanged!.listen(onDownloadProgressChanged),
];
Expand All @@ -58,44 +62,69 @@ class _AudioPlayerState extends State<AudioPlayer> {
double displayPosition = 0;
double? downloadProgress;

bool isMuted = false;
double volume = 50;
double preMuteVolume = 50;

Future<void> _savePreferences() async {
final prefs = await SharedPreferences.getInstance();
Comment thread
Airyzz marked this conversation as resolved.
Outdated
await prefs.setBool('audio_muted', isMuted);
await prefs.setDouble('audio_volume', preMuteVolume);
}

Future<void> _loadPreferences() async {
final prefs = await SharedPreferences.getInstance();
final savedMuted = prefs.getBool('audio_muted') ?? false;
final savedVolume = prefs.getDouble('audio_volume') ?? 100.0;

setState(() {
volume = savedVolume;
preMuteVolume = savedVolume;
});
player.setVolume(savedVolume);
if (savedMuted) {
toggleMute();
}
}

@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerLow,
borderRadius: BorderRadius.circular(8)),
color: Theme.of(context).colorScheme.surfaceContainerLow,
borderRadius: BorderRadius.circular(8)),
child: SizedBox(
width: 500,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (widget.fileName != null)
Padding(
padding: const EdgeInsets.fromLTRB(12, 12, 0, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(
Icons.audio_file,
size: 20,
),
SizedBox(
width: 8,
),
tiamat.Text.labelLow(widget.fileName!),
],
),
if (widget.fileSize != null)
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 12, 0),
child: tiamat.Text.labelLow(
TextUtils.readableFileSize(widget.fileSize!)),
Padding(
padding: const EdgeInsets.fromLTRB(12, 12, 0, 0),
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
children: [
Icon(
Icons.audio_file,
size: 20,
),
],
),
SizedBox(
width: 8,
),
tiamat.Text.labelLow(widget.fileName!),
],
),
if (widget.fileSize != null)
Padding(
padding: const EdgeInsets.fromLTRB(0, 0, 12, 0),
child: tiamat.Text.labelLow(
TextUtils.readableFileSize(widget.fileSize!)),
),
],
),
),
Padding(
padding: const EdgeInsets.fromLTRB(0, 8, 0, 4),
child: tiamat.Seperator(
Expand All @@ -108,40 +137,56 @@ class _AudioPlayerState extends State<AudioPlayer> {
width: 8,
),
SizedBox(
width: 40,
height: 40,
child: state == AudioPlayerState.loading
? Center(
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
value: downloadProgress,
)),
)
: tiamat.IconButton(
icon: state == AudioPlayerState.paused
? Icons.play_arrow
: Icons.pause,
onPressed: onPlayButtonPressed,
)),
width: 40,
height: 40,
child: state == AudioPlayerState.loading
? Center(
child: SizedBox(
width: 20,
height: 20,
child: CircularProgressIndicator(
value: downloadProgress,
)),
)
: tiamat.IconButton(
icon: state == AudioPlayerState.paused
? Icons.play_arrow
: Icons.pause,
onPressed: onPlayButtonPressed,
)),
Expanded(
child: tiamat.Slider(
value: displayPosition,
onChangeStart: (value) {
dragging = true;
},
onChangeEnd: (value) {
dragging = false;

var position = player.state.duration * value;

player.seek(position);
},
onChanged: (value) => setState(() {
displayPosition = value;
child: tiamat.Slider(
value: displayPosition,
onChangeStart: (value) {
dragging = true;
},
onChangeEnd: (value) {
dragging = false;

var position = player.state.duration * value;

player.seek(position);
},
onChanged: (value) => setState(() {
displayPosition = value;
}),
)),
tiamat.IconButton(
icon: isMuted ? Icons.volume_mute : volume == 0 ? Icons.volume_off : Icons.volume_up,
onPressed: (() {
toggleMute();
_savePreferences();
}),
))
),
SizedBox(
width: 100,
child: tiamat.Slider(
value: volume / 100,
onChanged: (value) => setVolume(value * 100),
onChangeEnd: (value) => _savePreferences(),
),
),
const SizedBox(width: 8),
],
),
],
Expand Down Expand Up @@ -170,6 +215,18 @@ class _AudioPlayerState extends State<AudioPlayer> {
}
}

void onPlayingChanged(bool event) {
if (event) {
setState(() {
state = AudioPlayerState.playing;
});
} else {
setState(() {
state = AudioPlayerState.paused;
});
}
}

void loadAudio() async {
var uri = await widget.file.resolve();

Expand All @@ -183,16 +240,11 @@ class _AudioPlayerState extends State<AudioPlayer> {
});
}

void onPlayingChanged(bool event) {
if (event) {
setState(() {
state = AudioPlayerState.playing;
});
} else {
setState(() {
state = AudioPlayerState.paused;
});
}
void onDownloadProgressChanged(DownloadProgress event) {
print(event);
setState(() {
downloadProgress = event.downloaded.toDouble() / event.total.toDouble();
});
}

void onPositionChanged(Duration event) {
Expand All @@ -208,10 +260,35 @@ class _AudioPlayerState extends State<AudioPlayer> {
}
}

void onDownloadProgressChanged(DownloadProgress event) {
print(event);
void toggleMute() {
if (!isMuted) {
setState(() {
isMuted = true;
preMuteVolume = volume;
volume = 0;
});
player.setVolume(0.0);
} else {
setState(() {
isMuted = false;
volume = preMuteVolume;
});
player.setVolume(volume);
}
}

void setVolume(double value) {
setState(() {
downloadProgress = event.downloaded.toDouble() / event.total.toDouble();
volume = value;
preMuteVolume = value;
isMuted = false;
});
player.setVolume(value);
}

void onVolumeChanged(double event) {
setState(() {
volume = event;
});
}
}