Add audio, video, image, pdf and json files (online and local)

This commit is contained in:
Thomas Fransolet 2023-12-17 16:14:39 +01:00
parent 9d099a201c
commit 0ffe261e86
11 changed files with 153 additions and 98 deletions

View File

@ -10,9 +10,10 @@ import 'package:just_audio/just_audio.dart';
class AudioPlayerFloatingContainer extends StatefulWidget { class AudioPlayerFloatingContainer extends StatefulWidget {
const AudioPlayerFloatingContainer({Key? key, required this.audioBytes, required this.isAuto}) : super(key: key); const AudioPlayerFloatingContainer({Key? key, required this.audioBytes, required this.resourceURl, required this.isAuto}) : super(key: key);
final Uint8List audioBytes; final Uint8List? audioBytes;
final String resourceURl;
final bool isAuto; final bool isAuto;
@override @override
@ -32,8 +33,10 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
@override @override
void initState() { void initState() {
Future.delayed(Duration.zero, () async { Future.delayed(Duration.zero, () async {
if(widget.audioBytes != null) {
audiobytes = widget.audioBytes!;
}
audiobytes = widget.audioBytes;
player.durationStream.listen((Duration? d) { //get the duration of audio player.durationStream.listen((Duration? d) { //get the duration of audio
if(d != null) { if(d != null) {
maxduration = d.inSeconds; maxduration = d.inSeconds;
@ -100,7 +103,8 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
if(widget.isAuto) { if(widget.isAuto) {
//player.play(BytesSource(audiobytes)); //player.play(BytesSource(audiobytes));
await player.setAudioSource(LoadedSource(audiobytes)); //await player.setAudioSource(LoadedSource(audiobytes));
await player.setUrl(widget.resourceURl);
player.play(); player.play();
setState(() { setState(() {
isplaying = true; isplaying = true;

View File

@ -5,19 +5,18 @@ IconData getResourceIcon(elementType) {
switch(elementType) { switch(elementType) {
case ResourceType.Image: case ResourceType.Image:
return Icons.image; return Icons.image;
break;
case ResourceType.ImageUrl: case ResourceType.ImageUrl:
return Icons.image_search; // art_track return Icons.image_search; // art_track
break;
case ResourceType.Audio: case ResourceType.Audio:
return Icons.audiotrack; // art_track return Icons.audiotrack; // art_track
break;
case ResourceType.Video: case ResourceType.Video:
return Icons.slow_motion_video; return Icons.slow_motion_video;
break;
case ResourceType.VideoUrl: case ResourceType.VideoUrl:
return Icons.ondemand_video_sharp; return Icons.ondemand_video_sharp;
break; case ResourceType.Pdf:
return Icons.picture_as_pdf_outlined;
case ResourceType.Json:
return Icons.file_present_outlined;
} }
return Icons.announcement; return Icons.announcement;
} }

View File

@ -51,7 +51,7 @@ class RoundedInputField extends StatelessWidget {
color: iconColor, color: iconColor,
): null, ): null,
hintText: hintText, hintText: hintText,
hintStyle: TextStyle(fontSize: fontSize, color: textColor), hintStyle: TextStyle(fontSize: fontSize, color: textColor, fontWeight: FontWeight.w400),
border: InputBorder.none, border: InputBorder.none,
) )
), ),

View File

@ -46,7 +46,7 @@ class StringInputContainer extends StatelessWidget {
Padding( Padding(
padding: const EdgeInsets.all(10.0), padding: const EdgeInsets.all(10.0),
child: Container( child: Container(
width: isUrl ? size.width *0.6 : isSmall ? size.width *0.1 : size.width *0.2, width: isUrl ? size.width *0.6 : isSmall ? size.width *0.1 : size.width *0.25,
child: RoundedInputField( child: RoundedInputField(
color: color!, color: color!,
textColor: kBlack, textColor: kBlack,

View File

@ -65,7 +65,7 @@ class _UploadOnlineResourceContainerState extends State<UploadOnlineResourceCont
} else { } else {
return Image.network( return Image.network(
urlResourceToShow!, urlResourceToShow!,
height: 200, height: 150,
fit:BoxFit.scaleDown, fit:BoxFit.scaleDown,
loadingBuilder: (BuildContext context, Widget child, loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent? loadingProgress) { ImageChunkEvent? loadingProgress) {
@ -105,14 +105,14 @@ class _UploadOnlineResourceContainerState extends State<UploadOnlineResourceCont
child: Container( child: Container(
width: size.width *0.35, // TODO GET SIZE width: size.width *0.35, // TODO GET SIZE
child: RoundedInputField( child: RoundedInputField(
hintText: "Url de l'image ou de la vidéo", hintText: "Url de l'image ou de la vidéo youtube",
//icon: widget.resourceDTO.type == ResourceType.ImageUrl ? Icons.image : Icons.ondemand_video, // TODO: TBD //icon: widget.resourceDTO.type == ResourceType.ImageUrl ? Icons.image : Icons.ondemand_video, // TODO: TBD
onChanged: (String text) { onChanged: (String text) {
//print("onchanged url");
widget.resourceDTO.url = text; // TODO check if ok widget.resourceDTO.url = text; // TODO check if ok
widget.onChanged(widget.resourceDTO); widget.onChanged(widget.resourceDTO);
// TODO check type of resource widget.resourceDTO.type = _isYouTubeVideo(widget.resourceDTO.url!) ? ResourceType.VideoUrl : ResourceType.ImageUrl; // ou VideoUrl
widget.resourceDTO.type = ResourceType.ImageUrl; // ou VideoUrl print("URL OR NOOOOT ?");
print(widget.resourceDTO.type);
}, },
initialValue: "" initialValue: ""
), ),
@ -140,4 +140,13 @@ class _UploadOnlineResourceContainerState extends State<UploadOnlineResourceCont
], ],
); );
} }
bool _isYouTubeVideo(String url) {
RegExp regExp = RegExp(
r'^https?://(?:www\.)?(?:youtube\.com/(?:[^/]+/[^/]+/|(?:v|e(?:mbed)?)\/|.*[?&]v=)|youtu\.be/)([^"&?/=%]{11})');
return regExp.hasMatch(url);
}
} }

View File

@ -14,7 +14,7 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
switch(resourceDTO.type) { switch(resourceDTO.type) {
case ResourceType.Image: case ResourceType.Image:
return Image.network( return Image.network(
(appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.apiClient.basePath+"/api/Resource/"+ resourceDTO.id, resourceDTO.url,
fit:BoxFit.fill, fit:BoxFit.fill,
loadingBuilder: (BuildContext context, Widget child, loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent? loadingProgress) { ImageChunkEvent? loadingProgress) {
@ -35,7 +35,7 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
break; break;
case ResourceType.ImageUrl: case ResourceType.ImageUrl:
return Image.network( return Image.network(
resourceDTO.data, resourceDTO.url,
fit:BoxFit.fill, fit:BoxFit.fill,
loadingBuilder: (BuildContext context, Widget child, loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent? loadingProgress) { ImageChunkEvent? loadingProgress) {
@ -55,8 +55,9 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
); );
break; break;
case ResourceType.Audio: case ResourceType.Audio:
return FutureBuilder( return AudioPlayerFloatingContainer(audioBytes: null, resourceURl: resourceDTO.url, isAuto: true);
future: getAudio(resourceDTO.id, appContext), /*return FutureBuilder(
future: getAudio(resourceDTO.url, appContext),
builder: (context, AsyncSnapshot<dynamic> snapshot) { builder: (context, AsyncSnapshot<dynamic> snapshot) {
Size size = MediaQuery.of(context).size; Size size = MediaQuery.of(context).size;
if (snapshot.connectionState == ConnectionState.done) { if (snapshot.connectionState == ConnectionState.done) {
@ -67,7 +68,7 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
audioBytes = snapshot.data; audioBytes = snapshot.data;
//this.player.playBytes(audiobytes); //this.player.playBytes(audiobytes);
} }
return AudioPlayerFloatingContainer(audioBytes: audioBytes, isAuto: true); return AudioPlayerFloatingContainer(audioBytes: audioBytes, resourceURl: resourceDTO.url, isAuto: true);
} else if (snapshot.connectionState == ConnectionState.none) { } else if (snapshot.connectionState == ConnectionState.none) {
return Text("No data"); return Text("No data");
} else { } else {
@ -80,19 +81,19 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
); );
} }
} }
); );*/
//return Text("Fichier audio - aucune visualisation possible"); //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");
break; break;
case ResourceType.VideoUrl: case ResourceType.VideoUrl:
return Text(resourceDTO.data); return Text(resourceDTO.url);
break; break;
} }
} }
Future<Uint8List?> getAudio(String resourceId, AppContext appContext) async { /*Future<Uint8List?> getAudio(String resourceId, AppContext appContext) async {
try { try {
ManagerAppContext managerAppContext = appContext.getContext() as ManagerAppContext; ManagerAppContext managerAppContext = appContext.getContext() as ManagerAppContext;
var url = managerAppContext.host! + "/api/Resource/" + resourceId; // TO TEST TODO UPDATE ROUTE var url = managerAppContext.host! + "/api/Resource/" + resourceId; // TO TEST TODO UPDATE ROUTE
@ -105,4 +106,4 @@ Future<Uint8List?> getAudio(String resourceId, AppContext appContext) async {
print("IN CATCH"); print("IN CATCH");
return null; return null;
} }
} }*/

View File

@ -29,7 +29,7 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
child: Column( child: Column(
children: [ children: [
Text("Nouvelle ressource", style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)), Text("Nouvelle ressource", style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
Column( /*Column(
children: [ children: [
StringInputContainer( StringInputContainer(
label: "Nom :", label: "Nom :",
@ -40,19 +40,22 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
), ),
if (fileName != null) new Text(fileName), if (fileName != null) new Text(fileName),
], ],
), ),*/
Container( Padding(
width: size.width *0.85, padding: const EdgeInsets.only(top: 10.0),
height: size.height *0.5, child: Container(
child: ResourceTab( width: size.width *0.85,
resourceDTO: resourceDetailDTO, height: size.height *0.5,
onFileUpload: (List<File> files) { child: ResourceTab(
filesToSend = files; resourceDTO: resourceDetailDTO,
}, onFileUpload: (List<File> files) {
onFileUploadWeb: (List<PlatformFile> files) { filesToSend = files;
filesToSendWeb = files; },
}, onFileUploadWeb: (List<PlatformFile> files) {
) filesToSendWeb = files;
},
)
),
), ),
], ],
), ),
@ -89,7 +92,7 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
color: kPrimaryColor, color: kPrimaryColor,
textColor: kWhite, textColor: kWhite,
press: () { press: () {
if (resourceDetailDTO.label != null && resourceDetailDTO.label!.trim() != '') { //if (resourceDetailDTO.label != null && resourceDetailDTO.label!.trim() != '') {
if(kIsWeb) { if(kIsWeb) {
if(resourceDetailDTO.url != null || filesToSendWeb != null) { // TODO clarify resourceDetailDTO.data != null if(resourceDetailDTO.url != null || filesToSendWeb != null) { // TODO clarify resourceDetailDTO.data != null
Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]); Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]);
@ -103,9 +106,9 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
showNotification(Colors.orange, kWhite, 'Aucun fichier n\'a été chargé', context, null); showNotification(Colors.orange, kWhite, 'Aucun fichier n\'a été chargé', context, null);
} }
} }
} else { /*} else {
showNotification(Colors.orange, kWhite, 'Veuillez donner un nom à la ressource', context, null); showNotification(Colors.orange, kWhite, 'Veuillez donner un nom à la ressource', context, null);
} }*/
//Navigator.of(context).pop(); //Navigator.of(context).pop();
//create(resourceDetailDTO, fileToSend, appContext, context); //create(resourceDetailDTO, fileToSend, appContext, context);
}, },

View File

@ -190,14 +190,12 @@ class _ResourceBodyGridState extends State<ResourceBodyGrid> {
} }
} }
boxDecoration(ResourceDTO resourceDetailDTO, appContext) { boxDecoration(dynamic resourceDetailDTO, appContext) {
print("boxDecorationboxDecorationboxDecorationboxDecoration");
print(resourceDetailDTO);
return BoxDecoration( return BoxDecoration(
color: resourceDetailDTO.id == null ? kSecond : kBackgroundColor, color: resourceDetailDTO.id == null ? kSecond : kBackgroundColor,
shape: BoxShape.rectangle, shape: BoxShape.rectangle,
borderRadius: BorderRadius.circular(30.0), borderRadius: BorderRadius.circular(30.0),
image: resourceDetailDTO.id != null && (resourceDetailDTO.type == ResourceType.Image || resourceDetailDTO.url != null && resourceDetailDTO.type == ResourceType.ImageUrl)? new DecorationImage( image: resourceDetailDTO.id != null && (resourceDetailDTO.type == ResourceType.Image || resourceDetailDTO.type == ResourceType.ImageUrl) && resourceDetailDTO.url != null ? new DecorationImage(
fit: BoxFit.cover, fit: BoxFit.cover,
colorFilter: new ColorFilter.mode(Colors.black.withOpacity(0.3), BlendMode.dstATop), colorFilter: new ColorFilter.mode(Colors.black.withOpacity(0.3), BlendMode.dstATop),
image: new NetworkImage( image: new NetworkImage(

View File

@ -128,62 +128,85 @@ Future<List<ResourceDTO?>?> create(ResourceDTO resourceDTO, List<File>? files, L
ManagerAppContext managerAppContext = appContext.getContext(); ManagerAppContext managerAppContext = appContext.getContext();
int index = 0; int index = 0;
// TODO handle online resource
for (PlatformFile platformFile in filesWeb!) {
print("Coucou platformFile");
print(platformFile);
print(platformFile.name);
print(platformFile.extension);
ResourceDTO resourceDTO = new ResourceDTO(label: platformFile.name);
switch(platformFile.extension) {
case 'jpg':
case 'jpeg':
case 'png':
resourceDTO.type = ResourceType.Image;
break;
case 'mp3':
resourceDTO.type = ResourceType.Audio;
break;
case 'mp4':
resourceDTO.type = ResourceType.Video;
break;
case 'pdf':
resourceDTO.type = ResourceType.Pdf;
break;
case 'json':
resourceDTO.type = ResourceType.Json;
break;
}
resourceDTO.instanceId = managerAppContext.instanceId;
try {
print("Trying to create resource");
resourceDTO.dateCreation = DateTime.now();
ResourceDTO? newResource = await managerAppContext.clientAPI!.resourceApi!.resourceCreate(resourceDTO);
print("created resource");
print(newResource);
if(newResource != null && resourceDTO.type != null) {
FirebaseStorage storage = FirebaseStorage.instance;
Reference ref = storage.ref().child('pictures/${appContext.getContext().instanceId}/${Path.basename(newResource.id!.toString())}.${platformFile.extension}');
UploadTask uploadTask = ref.putData(platformFile.bytes!); if(filesWeb != null) {
uploadTask.then((res) { for (PlatformFile platformFile in filesWeb) {
res.ref.getDownloadURL().then((urlImage) { var mimeType = "";
showNotification(Colors.green, kWhite, 'La ressource a été créée avec succès', context, null); print("Coucou platformFile");
newResource.url = urlImage; print(platformFile);
(appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.resourceUpdate(newResource); print(platformFile.name);
createdResources.add(newResource); print(platformFile.extension);
index++; ResourceDTO resourceDTO = new ResourceDTO(label: platformFile.name);
if(index == filesWeb.length) { switch(platformFile.extension) {
return createdResources; case 'jpg':
} case 'jpeg':
}); case 'png':
}); resourceDTO.type = ResourceType.Image;
mimeType = 'image/'+platformFile.extension!;
break;
case 'mp3':
resourceDTO.type = ResourceType.Audio;
mimeType = 'audio/'+platformFile.extension!;
break;
case 'mp4':
resourceDTO.type = ResourceType.Video;
mimeType = 'video/'+platformFile.extension!;
break;
case 'pdf':
resourceDTO.type = ResourceType.Pdf;
mimeType = 'application/'+platformFile.extension!;
break;
case 'json':
resourceDTO.type = ResourceType.Json;
mimeType = 'application/'+platformFile.extension!;
break;
}
resourceDTO.instanceId = managerAppContext.instanceId;
try {
print("Trying to create resource");
resourceDTO.dateCreation = DateTime.now();
ResourceDTO? newResource = await managerAppContext.clientAPI!.resourceApi!.resourceCreate(resourceDTO);
print("created resource");
print(newResource);
if(newResource != null && resourceDTO.type != null) {
FirebaseStorage storage = FirebaseStorage.instance;
Reference ref = storage.ref().child('pictures/${appContext.getContext().instanceId}/${Path.basename(newResource.id!.toString())}');
var metadata = SettableMetadata(
contentType: mimeType, // ou le type MIME approprié pour votre fichier
);
UploadTask uploadTask = ref.putData(platformFile.bytes!, metadata);
uploadTask.then((res) {
res.ref.getDownloadURL().then((urlImage) {
showNotification(Colors.green, kWhite, 'La ressource a été créée avec succès', context, null);
newResource.url = urlImage;
(appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.resourceUpdate(newResource);
createdResources.add(newResource);
index++;
if(index == filesWeb.length) {
return createdResources;
}
});
});
}
} catch(e) {
print("ERROR creating resource");
print(e);
} }
} catch(e) {
print("ERROR creating resource");
print(e);
} }
} else {
// online resource
print("Trying to create resource");
resourceDTO.dateCreation = DateTime.now();
resourceDTO.label = "Resource en ligne";
resourceDTO.instanceId = managerAppContext.instanceId;
ResourceDTO? newResource = await managerAppContext.clientAPI!.resourceApi!.resourceCreate(resourceDTO);
print("created resource");
createdResources.add(newResource);
return createdResources;
} }
return null; return null;
/*switch(resourceDTO.type) { /*switch(resourceDTO.type) {

View File

@ -1,3 +1,4 @@
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:manager_app/Components/confirmation_dialog.dart'; import 'package:manager_app/Components/confirmation_dialog.dart';
import 'package:manager_app/Components/message_notification.dart'; import 'package:manager_app/Components/message_notification.dart';
@ -135,6 +136,20 @@ Future<void> delete(ResourceDTO resourceDTO, AppContext appContext, context) asy
() {}, () {},
() async { () async {
await (appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.resourceDelete(resourceDTO.id!); await (appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.resourceDelete(resourceDTO.id!);
// TODO Remove from firebase storage via service or ?
FirebaseStorage storage = FirebaseStorage.instance;
Reference storageReference = storage.ref().child('pictures/${appContext.getContext().instanceId}/${resourceDTO.id}');
// Supprimer le fichier
try {
await storageReference.delete();
print('Fichier supprimé avec succès');
} catch (e) {
print('Erreur lors de la suppression du fichier : $e');
}
try {} catch (e) {}
// just to refresh // just to refresh
ManagerAppContext managerAppContext = appContext.getContext(); ManagerAppContext managerAppContext = appContext.getContext();
appContext.setContext(managerAppContext); appContext.setContext(managerAppContext);

View File

@ -111,6 +111,9 @@
loadMainDartJs(); loadMainDartJs();
} }
</script> </script>
<script type="text/javascript">
window.flutterWebRenderer = "html";
</script>
<script type="module"> <script type="module">
// Import the functions you need from the SDKs you need // Import the functions you need from the SDKs you need
import { initializeApp } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-app.js"; import { initializeApp } from "https://www.gstatic.com/firebasejs/10.7.1/firebase-app.js";