Compare commits

..

6 Commits

Author SHA1 Message Date
1ff98b7bbf Display media size 2022-03-24 12:06:11 +01:00
545d9a951f Can change music position from cursor 2022-03-24 11:56:21 +01:00
b11eb6063c Attempt to automatically play next music 2022-03-24 11:47:27 +01:00
aa3f743eee Add slider 2022-03-24 11:43:02 +01:00
30aa018bed Automatically stop audio on widget destruction 2022-03-24 11:26:01 +01:00
41feac8ef5 Change audio player 2022-03-24 11:24:40 +01:00
3 changed files with 141 additions and 36 deletions

View File

@ -3,12 +3,19 @@
import 'dart:math';
import 'dart:ui';
import 'package:audioplayers/audioplayers.dart';
import 'package:chewie_audio/chewie_audio.dart';
import 'package:fluent_ui/fluent_ui.dart' as fluent;
import 'package:fluentui_system_icons/fluentui_system_icons.dart';
import 'package:flutter/material.dart';
import 'package:music_web_player/api.dart';
import 'package:music_web_player/ui/cover_image.dart';
import 'package:video_player/video_player.dart';
extension DurationExt on Duration {
String get formatted {
return "$inMinutes:${(inSeconds % 60).toString().padLeft(2, '0')}";
}
}
class MusicPlayer extends StatefulWidget {
final MusicsList musicsList;
@ -22,8 +29,14 @@ class MusicPlayer extends StatefulWidget {
class _MusicPlayerState extends State<MusicPlayer> {
final rng = Random();
final audioPlayer = AudioPlayer(playerId: "player");
var _playerState = PlayerState.STOPPED;
VideoPlayerController? _videoPlayerController;
ChewieAudioController? _chewieAudioController;
bool get _isPlaying => _videoPlayerController?.value.isPlaying ?? false;
Duration? get _duration => _videoPlayerController?.value.duration;
Duration? get _position => _videoPlayerController?.value.position;
final List<MusicEntry> stack = [];
int currMusicPos = 0;
@ -40,37 +53,40 @@ class _MusicPlayerState extends State<MusicPlayer> {
return stack[currMusicPos];
}
@override
void initState() {
super.initState();
audioPlayer.onPlayerError.listen((event) {
print("Player error!");
print(event);
_playNext();
});
audioPlayer.onPlayerStateChanged.listen((s) => setState(() {
_playerState = s;
if (_playerState == PlayerState.COMPLETED) _playNext();
}));
}
Future<void> _play() async {
if (_playerState == PlayerState.PAUSED) {
await audioPlayer.resume();
if (_chewieAudioController != null) {
await _chewieAudioController!.play();
} else {
await audioPlayer.play(currMusic.musicURL);
_videoPlayerController =
VideoPlayerController.network(currMusic.musicURL);
await _videoPlayerController!.initialize();
_chewieAudioController = ChewieAudioController(
videoPlayerController: _videoPlayerController!,
autoPlay: true,
showControls: false);
_videoPlayerController!.addListener(() => setState(() {
// Automatically play next music if required
if (_videoPlayerController != null && _duration == _position) {
if (_duration?.inSeconds == _position?.inSeconds &&
(_duration?.inSeconds ?? 0) > 0) {
_playNext();
}
}
}));
}
}
Future<void> _stop() async {
await audioPlayer.stop();
_chewieAudioController?.dispose();
_videoPlayerController?.dispose();
_chewieAudioController = null;
_videoPlayerController = null;
}
void _pause() async {
await audioPlayer.pause();
await _chewieAudioController?.pause();
}
void _playPrevious() async {
@ -85,6 +101,14 @@ class _MusicPlayerState extends State<MusicPlayer> {
await _play();
}
void _updatePosition(Duration d) => _videoPlayerController?.seekTo(d);
@override
void dispose() {
super.dispose();
_stop();
}
@override
Widget build(BuildContext context) {
return LayoutBuilder(
@ -149,6 +173,24 @@ class _MusicPlayerState extends State<MusicPlayer> {
const SizedBox(height: 20),
Text(currMusic.artist, textAlign: TextAlign.center),
const fluent.SizedBox(height: 40),
fluent.Row(
children: [
DurationText(_position),
const SizedBox(width: 15),
Flexible(
child: fluent.Slider(
max: _duration?.inSeconds as double? ?? 0,
value: _position?.inSeconds as double? ?? 0,
onChanged: (d) =>
_updatePosition(Duration(seconds: d.toInt())),
label: _position?.formatted,
),
),
const SizedBox(width: 15),
DurationText(_duration),
],
),
const fluent.SizedBox(height: 40),
fluent.Row(
children: [
IconButton(
@ -157,11 +199,10 @@ class _MusicPlayerState extends State<MusicPlayer> {
),
const Spacer(),
IconButton(
icon: PlayerIcon(_playerState == PlayerState.PLAYING
icon: PlayerIcon(_isPlaying
? fluent.FluentIcons.pause
: fluent.FluentIcons.play),
onPressed:
_playerState == PlayerState.PLAYING ? _pause : _play,
onPressed: _isPlaying ? _pause : _play,
),
const Spacer(),
IconButton(
@ -185,3 +226,17 @@ class PlayerIcon extends StatelessWidget {
@override
Widget build(BuildContext context) => Icon(icon, size: 35);
}
class DurationText extends StatelessWidget {
final Duration? duration;
const DurationText(this.duration, {Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Text(
duration?.formatted ?? "0:00",
style: const TextStyle(fontSize: 10),
);
}
}

View File

@ -8,13 +8,6 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.8.2"
audioplayers:
dependency: "direct main"
description:
name: audioplayers
url: "https://pub.dartlang.org"
source: hosted
version: "0.20.1"
boolean_selector:
dependency: transitive
description:
@ -57,6 +50,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.1"
chewie_audio:
dependency: "direct main"
description:
name: chewie_audio
url: "https://pub.dartlang.org"
source: hosted
version: "1.3.0"
clock:
dependency: transitive
description:
@ -78,6 +78,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
csslib:
dependency: transitive
description:
name: csslib
url: "https://pub.dartlang.org"
source: hosted
version: "0.17.1"
cupertino_icons:
dependency: "direct main"
description:
@ -163,6 +170,13 @@ packages:
description: flutter
source: sdk
version: "0.0.0"
html:
dependency: transitive
description:
name: html
url: "https://pub.dartlang.org"
source: hosted
version: "0.15.0"
http:
dependency: transitive
description:
@ -420,6 +434,41 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
video_player:
dependency: "direct main"
description:
name: video_player
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.0"
video_player_android:
dependency: transitive
description:
name: video_player_android
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.1"
video_player_avfoundation:
dependency: transitive
description:
name: video_player_avfoundation
url: "https://pub.dartlang.org"
source: hosted
version: "2.3.1"
video_player_platform_interface:
dependency: transitive
description:
name: video_player_platform_interface
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.1"
video_player_web:
dependency: transitive
description:
name: video_player_web
url: "https://pub.dartlang.org"
source: hosted
version: "2.0.7"
win32:
dependency: transitive
description:

View File

@ -47,7 +47,8 @@ dependencies:
cached_network_image_platform_interface: ^1.0.0
# Audio player
audioplayers: ^0.20.1
video_player: ^2.3.0
chewie_audio: ^1.3.0
dev_dependencies:
flutter_test: