// ignore_for_file: avoid_print import 'dart:math'; import 'dart:ui'; 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'; class MusicPlayer extends StatefulWidget { final MusicsList musicsList; const MusicPlayer({Key? key, required this.musicsList}) : super(key: key); @override State createState() => _MusicPlayerState(); } class _MusicPlayerState extends State { final rng = Random(); VideoPlayerController? _videoPlayerController; ChewieAudioController? _chewieAudioController; bool get _isPlaying => _chewieAudioController?.isPlaying ?? false; final List stack = []; int currMusicPos = 0; MusicEntry get currMusic { if (currMusicPos < 0) currMusicPos = 0; // Automatically choose next music if required if (currMusicPos >= stack.length) { var nextId = rng.nextInt(widget.musicsList.length); stack.add(widget.musicsList[nextId]); } return stack[currMusicPos]; } Future _play() async { if (_chewieAudioController != null) { await _chewieAudioController!.play(); } else { _videoPlayerController = VideoPlayerController.network(currMusic.musicURL); await _videoPlayerController!.initialize(); _chewieAudioController = ChewieAudioController( videoPlayerController: _videoPlayerController!, autoPlay: true, showControls: false); } setState(() {}); } Future _stop() async { _chewieAudioController?.dispose(); _videoPlayerController?.dispose(); _chewieAudioController = null; _videoPlayerController = null; } void _pause() async { await _chewieAudioController?.pause(); setState(() {}); } void _playPrevious() async { currMusicPos -= 1; await _stop(); await _play(); } void _playNext() async { currMusicPos += 1; await _stop(); await _play(); } @override void dispose() { super.dispose(); _stop(); } @override Widget build(BuildContext context) { return LayoutBuilder( builder: (context, constraints) => Stack( children: [ // Background image CoverImage( music: currMusic, width: constraints.maxWidth, height: constraints.maxHeight, fit: BoxFit.cover, ), ClipRRect( // Clip it cleanly. child: BackdropFilter( filter: ImageFilter.blur(sigmaX: 10, sigmaY: 10), child: Container( color: Colors.black.withOpacity(0.8), alignment: Alignment.center, child: SizedBox( width: constraints.maxWidth, height: constraints.maxHeight, ), ), )), _buildCenter(), ], ), ); } Widget _buildCenter() { return fluent.Center( child: SizedBox( width: 250, child: Column( mainAxisAlignment: fluent.MainAxisAlignment.center, crossAxisAlignment: fluent.CrossAxisAlignment.center, children: [ Material( borderRadius: const BorderRadius.all( Radius.circular(18.0), ), clipBehavior: Clip.hardEdge, child: CoverImage( width: 250, height: 250, music: currMusic, fit: BoxFit.cover, backgroundColor: Colors.black12, icon: const Icon(FluentIcons.music_note_2_24_regular, size: 90), ), ), const SizedBox(height: 40), Text( currMusic.title, style: const TextStyle(fontSize: 22), textAlign: TextAlign.center, ), const SizedBox(height: 20), Text(currMusic.artist, textAlign: TextAlign.center), const fluent.SizedBox(height: 40), fluent.Row( children: [ IconButton( icon: const PlayerIcon(fluent.FluentIcons.previous), onPressed: currMusicPos == 0 ? null : _playPrevious, ), const Spacer(), IconButton( icon: PlayerIcon(_isPlaying ? fluent.FluentIcons.pause : fluent.FluentIcons.play), onPressed: _isPlaying ? _pause : _play, ), const Spacer(), IconButton( icon: const PlayerIcon(fluent.FluentIcons.next), onPressed: _playNext, ), ], ) ], ), ), ); } } class PlayerIcon extends StatelessWidget { final IconData icon; const PlayerIcon(this.icon, {Key? key}) : super(key: key); @override Widget build(BuildContext context) => Icon(icon, size: 35); }