Add audio visualisation in resource

This commit is contained in:
Thomas Fransolet 2023-03-31 16:45:06 +02:00
parent 15f18f9a5a
commit d3f60bcbe6
4 changed files with 219 additions and 143 deletions

View File

@ -1,48 +1,81 @@
import 'dart:convert';
import 'dart:typed_data'; import 'dart:typed_data';
import 'package:audioplayers/audioplayers.dart'; //import 'package:audioplayers/audioplayers.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:manager_app/Models/managerContext.dart';
import 'package:manager_app/app_context.dart'; import 'package:manager_app/app_context.dart';
import 'package:manager_app/constants.dart'; import 'package:manager_app/constants.dart';
import 'package:manager_api_new/api.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:http/http.dart' as http;
import 'loading_common.dart'; import 'package:just_audio/just_audio.dart';
class AudioPlayerContainer extends StatefulWidget {
const AudioPlayerContainer({Key key, this.resourceDTO, this.isAuto}) : super(key: key);
final ResourceDTO resourceDTO; class AudioPlayerFloatingContainer extends StatefulWidget {
const AudioPlayerFloatingContainer({Key key, this.audioBytes, this.isAuto}) : super(key: key);
final Uint8List audioBytes;
final bool isAuto; final bool isAuto;
@override @override
State<AudioPlayerContainer> createState() => _AudioPlayerContainerState(); State<AudioPlayerFloatingContainer> createState() => _AudioPlayerFloatingContainerState();
} }
class _AudioPlayerContainerState extends State<AudioPlayerContainer> { class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContainer> {
AudioPlayer player = AudioPlayer(); AudioPlayer player = AudioPlayer();
Uint8List audiobytes; Uint8List audiobytes;
bool isplaying = false; bool isplaying = false;
bool audioplayed = false; bool audioplayed = false;
int currentpos = 0; int currentpos = 0;
int maxduration = 100; int maxduration = 100;
Duration durationAudio;
String currentpostlabel = "00:00"; String currentpostlabel = "00:00";
@override @override
void initState() { void initState() {
//Uint8List base64String = base64Decode(audiobytes); // LOAD DATA Future.delayed(Duration.zero, () async {
/*Future.delayed(Duration.zero, () async { audiobytes = widget.audioBytes;
player.onDurationChanged.listen((Duration d) { //get the duration of audio player.durationStream.listen((Duration d) { //get the duration of audio
maxduration = d.inSeconds; maxduration = d.inSeconds;
setState(() { durationAudio = d;
});
}); });
player.onAudioPositionChanged.listen((Duration p){ //player.bufferedPositionStream
player.positionStream.listen((event) {
if(event != null) {
currentpos = event.inMilliseconds; //get the current position of playing audio
//generating the duration label
int shours = Duration(milliseconds:durationAudio.inMilliseconds - currentpos).inHours;
int sminutes = Duration(milliseconds:durationAudio.inMilliseconds - currentpos).inMinutes;
int sseconds = Duration(milliseconds:durationAudio.inMilliseconds - currentpos).inSeconds;
int rminutes = sminutes - (shours * 60);
int rseconds = sseconds - (sminutes * 60 + shours * 60 * 60);
String minutesToShow = rminutes < 10 ? '0$rminutes': rminutes.toString();
String secondsToShow = rseconds < 10 ? '0$rseconds': rseconds.toString();
currentpostlabel = "$minutesToShow:$secondsToShow";
setState(() {
//refresh the UI
if(currentpos > player.duration.inMilliseconds) {
print("RESET ALL");
player.stop();
player.seek(const Duration(seconds: 0));
isplaying = false;
audioplayed = false;
currentpostlabel = "00:00";
}
});
}
});
/*player.onPositionChanged.listen((Duration p){
currentpos = p.inMilliseconds; //get the current position of playing audio currentpos = p.inMilliseconds; //get the current position of playing audio
//generating the duration label //generating the duration label
@ -61,154 +94,148 @@ class _AudioPlayerContainerState extends State<AudioPlayerContainer> {
setState(() { setState(() {
//refresh the UI //refresh the UI
}); });
}); });*/
if(widget.isAuto) { if(widget.isAuto) {
player.playBytes(audiobytes); //player.play(BytesSource(audiobytes));
await player.setAudioSource(LoadedSource(audiobytes));
player.play();
setState(() { setState(() {
isplaying = true; isplaying = true;
audioplayed = true; audioplayed = true;
}); });
} }
});*/ });
super.initState(); super.initState();
} }
@override @override
void dispose() { void dispose() {
/*player.stop(); player.stop();
player.dispose();*/ player.dispose();
super.dispose(); super.dispose();
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final appContext = Provider.of<AppContext>(context); final appContext = Provider.of<AppContext>(context);
Size size = MediaQuery.of(context).size;
return FutureBuilder( return FloatingActionButton(
future: getAudio(widget.resourceDTO.id, appContext), backgroundColor: kPrimaryColor.withOpacity(0.7),
builder: (context, AsyncSnapshot<dynamic> snapshot) { onPressed: () async {
if (snapshot.connectionState == ConnectionState.done) { print("TODO");
print("DOOOONE"); if(!isplaying && !audioplayed){
if(snapshot.data != null) { //player.play(BytesSource(audiobytes));
print("snapshot.data"); await player.setAudioSource(LoadedSource(audiobytes));
print(snapshot.data); player.play();
//this.player.playBytes(audiobytes); setState(() {
} isplaying = true;
audioplayed = true;
return Container( });
child: Column( }else if(audioplayed && !isplaying){
children: [ //player.resume();
player.play();
Container( setState(() {
child: Text(currentpostlabel, style: TextStyle(fontSize: 25),), isplaying = true;
), audioplayed = true;
});
Container( }else{
child: Wrap( player.pause();
spacing: 10, setState(() {
children: [ isplaying = false;
ElevatedButton.icon( });
style: ElevatedButton.styleFrom(
primary: kPrimaryColor, // Background color
),
onPressed: () async {
print(isplaying);
print(audioplayed);
if(!isplaying && !audioplayed){
player.playBytes(audiobytes);
//player.playBytes(bytes)
setState(() {
isplaying = true;
audioplayed = true;
});
}else if(audioplayed && !isplaying){
player.resume();
setState(() {
isplaying = true;
audioplayed = true;
});
}else{
player.pause();
setState(() {
isplaying = false;
});
}
},
icon: Icon(isplaying?Icons.pause:Icons.play_arrow),
label:Text(isplaying?"Pause":"Play")
),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
primary: kPrimaryColor, // Background color
),
onPressed: () async {
/*player.stop();
setState(() {
isplaying = false;
audioplayed = false;
currentpostlabel = "00:00";
});*/
},
icon: Icon(Icons.stop),
label:Text("Stop")
),
],
),
)
],
),
);
}else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
} else {
return Center(
child: Container(
height: size.height * 0.2,
child: LoadingCommon()
)
);
} }
},
child: isplaying ? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.pause),
Text(currentpostlabel),
],
) : audioplayed ? Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.play_arrow),
Text(currentpostlabel),
],
): const Icon(Icons.play_arrow),
} /*Column(
children: [
//Text(currentpostlabel, style: const TextStyle(fontSize: 25)),
Wrap(
spacing: 10,
children: [
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: kSecondColor, // Background color
),
onPressed: () async {
if(!isplaying && !audioplayed){
//player.play(BytesSource(audiobytes));
await player.setAudioSource(LoadedSource(audiobytes));
player.play();
setState(() {
isplaying = true;
audioplayed = true;
});
}else if(audioplayed && !isplaying){
//player.resume();
player.play();
setState(() {
isplaying = true;
audioplayed = true;
});
}else{
player.pause();
setState(() {
isplaying = false;
});
}
},
icon: Icon(isplaying?Icons.pause:Icons.play_arrow),
//label:Text(isplaying?TranslationHelper.getFromLocale("pause", appContext.getContext()):TranslationHelper.getFromLocale("play", appContext.getContext()))
),
/*ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: kSecondColor, // Background color
),
onPressed: () async {
player.stop();
player.seek(const Duration(seconds: 0));
setState(() {
isplaying = false;
audioplayed = false;
currentpostlabel = "00:00";
});
},
icon: const Icon(Icons.stop),
//label: Text(TranslationHelper.getFromLocale("stop", appContext.getContext()))
),*/
],
)
],
),*/
); );
} }
} }
Future<Uint8List> getAudio(String resourceId, AppContext appContext) async { // Feed your own stream of bytes into the player
try { class LoadedSource extends StreamAudioSource {
ManagerAppContext managerAppContext = appContext.getContext() as ManagerAppContext; final List<int> bytes;
var url = managerAppContext.host + "/api/Resource/" + resourceId; // TO TEST TODO UPDATE ROUTE LoadedSource(this.bytes);
print("DOWNLOAD AUDDDDIOOOOO ------------");
print(url);
//HttpClient client2 = HttpClient();
print("before.. hmmm? ");
var _downloadData = <int>[];
print("before.. ? "); @override
Future<StreamAudioResponse> request([int start, int end]) async {
/*var test = await http.get(Uri.parse(url)); start ??= 0;
print("test"); end ??= bytes.length;
print(test);*/ return StreamAudioResponse(
sourceLength: bytes.length,
var test2 = await http.readBytes(Uri.parse(url)); contentLength: end - start,
print("test2"); offset: start,
print(test2); stream: Stream.value(bytes.sublist(start, end)),
contentType: 'audio/mpeg',
//final HttpClientRequest request = await client2.getUrl(url); );
print("RESPONSE");
/*HttpClientResponse response = await request.close();
await for(dynamic d in response) { _downloadData.addAll(d); }
print("AFTER");*/
final base64Str = base64.encode(test2);
Uint8List base64String = base64Decode(base64Str); // LOAD DATA
return base64String;
} catch (e) {
print(e);
print("IN CATCH");
return null;
} }
} }

View File

@ -1,8 +1,14 @@
import 'dart:convert';
import 'dart:typed_data';
import 'package:manager_app/Components/audio_player.dart'; import 'package:manager_app/Components/audio_player.dart';
import 'package:manager_app/Components/loading_common.dart';
import 'package:manager_app/Models/managerContext.dart';
import 'package:manager_app/app_context.dart'; import 'package:manager_app/app_context.dart';
import 'package:manager_app/constants.dart'; import 'package:manager_app/constants.dart';
import 'package:manager_api_new/api.dart'; import 'package:manager_api_new/api.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
getElementForResource(dynamic resourceDTO, AppContext appContext) { getElementForResource(dynamic resourceDTO, AppContext appContext) {
switch(resourceDTO.type) { switch(resourceDTO.type) {
@ -49,8 +55,32 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
); );
break; break;
case ResourceType.Audio: case ResourceType.Audio:
//return AudioPlayerContainer(resourceDTO: resourceDTO, isAuto: true); return FutureBuilder(
return Text("Fichier audio - aucune visualisation possible"); future: getAudio(resourceDTO.id, appContext),
builder: (context, AsyncSnapshot<dynamic> snapshot) {
Size size = MediaQuery.of(context).size;
if (snapshot.connectionState == ConnectionState.done) {
var audioBytes;
if(snapshot.data != null) {
print("snapshot.data");
print(snapshot.data);
audioBytes = snapshot.data;
//this.player.playBytes(audiobytes);
}
return AudioPlayerFloatingContainer(audioBytes: audioBytes, isAuto: true);
} else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data");
} else {
return Center(
child: Container(
height: size.height * 0.2,
child: LoadingCommon()
)
);
}
}
);
//return Text("Fichier audio - aucune visualisation possible");
break; break;
case ResourceType.Video: case ResourceType.Video:
return Text("Vidéo locale - aucune visualisation possible"); return Text("Vidéo locale - aucune visualisation possible");
@ -60,3 +90,18 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
break; break;
} }
} }
Future<Uint8List> getAudio(String resourceId, AppContext appContext) async {
try {
ManagerAppContext managerAppContext = appContext.getContext() as ManagerAppContext;
var url = managerAppContext.host + "/api/Resource/" + resourceId; // TO TEST TODO UPDATE ROUTE
var test2 = await http.readBytes(Uri.parse(url));
final base64Str = base64.encode(test2);
Uint8List base64String = base64Decode(base64Str); // LOAD DATA
return base64String;
} catch (e) {
print(e);
print("IN CATCH");
return null;
}
}

View File

@ -5,10 +5,14 @@
import FlutterMacOS import FlutterMacOS
import Foundation import Foundation
import audio_session
import audioplayers import audioplayers
import just_audio
import path_provider_foundation import path_provider_foundation
func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) {
AudioSessionPlugin.register(with: registry.registrar(forPlugin: "AudioSessionPlugin"))
AudioplayersPlugin.register(with: registry.registrar(forPlugin: "AudioplayersPlugin")) AudioplayersPlugin.register(with: registry.registrar(forPlugin: "AudioplayersPlugin"))
JustAudioPlugin.register(with: registry.registrar(forPlugin: "JustAudioPlugin"))
PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin"))
} }

View File

@ -41,7 +41,7 @@ dependencies:
#path_provider: ^2.0.2 #path_provider: ^2.0.2
encrypt: ^5.0.0 encrypt: ^5.0.0
qr_flutter: ^4.0.0 qr_flutter: ^4.0.0
audioplayers: 0.18.3 just_audio: ^0.9.31
pdf: ^3.6.0 pdf: ^3.6.0
multi_select_flutter: ^4.1.2 multi_select_flutter: ^4.1.2
#msix: ^2.1.3 #msix: ^2.1.3