Last active
January 14, 2019 21:24
-
-
Save paolorotolo/1605fc9be21f37c34719936d086a82c0 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:async'; | |
import 'dart:io'; | |
import 'dart:typed_data'; | |
import 'package:audioplayer/audioplayer.dart'; | |
import 'package:flutter/material.dart'; | |
import 'package:http/http.dart'; | |
import 'package:path_provider/path_provider.dart'; | |
typedef void OnError(Exception exception); | |
var kUrl = ""; | |
class FlutterAudioPlayer extends StatelessWidget { | |
String url; | |
FlutterAudioPlayer(this.url) { | |
kUrl = url; | |
} | |
@override | |
Widget build(BuildContext context) { | |
return new Scaffold( | |
appBar: AppBar( | |
backgroundColor: Colors.blueAccent, | |
), | |
body: new AudioApp()); | |
} | |
} | |
enum PlayerState { stopped, playing, paused } | |
class AudioApp extends StatefulWidget { | |
@override | |
_AudioAppState createState() => new _AudioAppState(); | |
} | |
class _AudioAppState extends State<AudioApp> { | |
Duration duration; | |
Duration position; | |
AudioPlayer audioPlayer; | |
String localFilePath; | |
PlayerState playerState = PlayerState.stopped; | |
get isPlaying => playerState == PlayerState.playing; | |
get isPaused => playerState == PlayerState.paused; | |
get durationText => | |
duration != null ? duration.toString().split('.').first : ''; | |
get positionText => | |
position != null ? position.toString().split('.').first : ''; | |
bool isMuted = false; | |
StreamSubscription _positionSubscription; | |
StreamSubscription _audioPlayerStateSubscription; | |
@override | |
void initState() { | |
super.initState(); | |
initAudioPlayer(); | |
} | |
@override | |
void dispose() { | |
_positionSubscription.cancel(); | |
_audioPlayerStateSubscription.cancel(); | |
audioPlayer.stop(); | |
super.dispose(); | |
} | |
void initAudioPlayer() { | |
audioPlayer = new AudioPlayer(); | |
_positionSubscription = audioPlayer.onAudioPositionChanged | |
.listen((p) => setState(() => position = p)); | |
_audioPlayerStateSubscription = | |
audioPlayer.onPlayerStateChanged.listen((s) { | |
if (s == AudioPlayerState.PLAYING) { | |
setState(() => duration = audioPlayer.duration); | |
} else if (s == AudioPlayerState.STOPPED) { | |
onComplete(); | |
setState(() { | |
position = duration; | |
}); | |
} | |
}, onError: (msg) { | |
setState(() { | |
playerState = PlayerState.stopped; | |
duration = new Duration(seconds: 0); | |
position = new Duration(seconds: 0); | |
}); | |
}); | |
} | |
Future play() async { | |
await audioPlayer.play(kUrl); | |
setState(() { | |
playerState = PlayerState.playing; | |
}); | |
} | |
Future _playLocal() async { | |
await audioPlayer.play(localFilePath, isLocal: true); | |
setState(() => playerState = PlayerState.playing); | |
} | |
Future pause() async { | |
await audioPlayer.pause(); | |
setState(() => playerState = PlayerState.paused); | |
} | |
Future stop() async { | |
await audioPlayer.stop(); | |
setState(() { | |
playerState = PlayerState.stopped; | |
position = new Duration(); | |
}); | |
} | |
Future mute(bool muted) async { | |
await audioPlayer.mute(muted); | |
setState(() { | |
isMuted = muted; | |
}); | |
} | |
void onComplete() { | |
setState(() => playerState = PlayerState.stopped); | |
} | |
Future<Uint8List> _loadFileBytes(String url, {OnError onError}) async { | |
Uint8List bytes; | |
try { | |
bytes = await readBytes(url); | |
} on ClientException { | |
rethrow; | |
} | |
return bytes; | |
} | |
Future _loadFile() async { | |
final bytes = await _loadFileBytes(kUrl, | |
onError: (Exception exception) => | |
print('_loadFile => exception $exception')); | |
final dir = await getApplicationDocumentsDirectory(); | |
final file = new File('${dir.path}/audio.mp3'); | |
await file.writeAsBytes(bytes); | |
if (await file.exists()) | |
setState(() { | |
localFilePath = file.path; | |
}); | |
} | |
@override | |
Widget build(BuildContext context) { | |
return new Center( | |
child: new Material( | |
elevation: 2.0, | |
color: Colors.grey[200], | |
child: new Column( | |
children: [ | |
Card(child: new Material(child: _buildPlayer())), | |
localFilePath != null | |
? new Text(localFilePath) | |
: new Container(), | |
]))); | |
} | |
Widget _buildPlayer() => new Container( | |
padding: new EdgeInsets.all(16.0), | |
child: new Column(mainAxisSize: MainAxisSize.min, children: [ | |
new Row(mainAxisSize: MainAxisSize.min, children: [ | |
new IconButton( | |
onPressed: isPlaying ? null : () => play(), | |
iconSize: 64.0, | |
icon: new Icon(Icons.play_arrow), | |
color: Colors.blueAccent), | |
new IconButton( | |
onPressed: isPlaying ? () => pause() : null, | |
iconSize: 64.0, | |
icon: new Icon(Icons.pause), | |
color: Colors.blueAccent), | |
new IconButton( | |
onPressed: isPlaying || isPaused ? () => stop() : null, | |
iconSize: 64.0, | |
icon: new Icon(Icons.stop), | |
color: Colors.blueAccent), | |
]), | |
duration == null | |
? new Container() | |
: new Slider( | |
value: position?.inMilliseconds?.toDouble() ?? 0.0, | |
onChanged: (double value) => | |
audioPlayer.seek((value / 1000).roundToDouble()), | |
min: 0.0, | |
max: duration.inMilliseconds.toDouble()), | |
new Row( | |
mainAxisAlignment: MainAxisAlignment.spaceEvenly, | |
children: <Widget>[ | |
new IconButton( | |
onPressed: () => mute(true), | |
icon: new Icon(Icons.headset_off), | |
color: Colors.blueAccent), | |
new IconButton( | |
onPressed: () => mute(false), | |
icon: new Icon(Icons.headset), | |
color: Colors.blueAccent), | |
], | |
), | |
new Row(mainAxisSize: MainAxisSize.min, children: [ | |
new Padding( | |
padding: new EdgeInsets.all(12.0), | |
child: new Stack(children: [ | |
new CircularProgressIndicator( | |
value: 1.0, | |
valueColor: new AlwaysStoppedAnimation(Colors.grey[300])), | |
new CircularProgressIndicator( | |
value: position != null && position.inMilliseconds > 0 | |
? (position?.inMilliseconds?.toDouble() ?? 0.0) / | |
(duration?.inMilliseconds?.toDouble() ?? 0.0) | |
: 0.0, | |
valueColor: new AlwaysStoppedAnimation(Colors.blueAccent), | |
backgroundColor: Colors.yellow, | |
), | |
])), | |
new Text( | |
position != null | |
? "${positionText ?? ''} / ${durationText ?? ''}" | |
: duration != null ? durationText : '', | |
style: new TextStyle(fontSize: 24.0)) | |
]) | |
])); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment