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 {
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;
@override
@ -32,8 +33,10 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
@override
void initState() {
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
if(d != null) {
maxduration = d.inSeconds;
@ -100,7 +103,8 @@ class _AudioPlayerFloatingContainerState extends State<AudioPlayerFloatingContai
if(widget.isAuto) {
//player.play(BytesSource(audiobytes));
await player.setAudioSource(LoadedSource(audiobytes));
//await player.setAudioSource(LoadedSource(audiobytes));
await player.setUrl(widget.resourceURl);
player.play();
setState(() {
isplaying = true;

View File

@ -5,19 +5,18 @@ IconData getResourceIcon(elementType) {
switch(elementType) {
case ResourceType.Image:
return Icons.image;
break;
case ResourceType.ImageUrl:
return Icons.image_search; // art_track
break;
case ResourceType.Audio:
return Icons.audiotrack; // art_track
break;
case ResourceType.Video:
return Icons.slow_motion_video;
break;
case ResourceType.VideoUrl:
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;
}

View File

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

View File

@ -46,7 +46,7 @@ class StringInputContainer extends StatelessWidget {
Padding(
padding: const EdgeInsets.all(10.0),
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(
color: color!,
textColor: kBlack,

View File

@ -65,7 +65,7 @@ class _UploadOnlineResourceContainerState extends State<UploadOnlineResourceCont
} else {
return Image.network(
urlResourceToShow!,
height: 200,
height: 150,
fit:BoxFit.scaleDown,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent? loadingProgress) {
@ -105,14 +105,14 @@ class _UploadOnlineResourceContainerState extends State<UploadOnlineResourceCont
child: Container(
width: size.width *0.35, // TODO GET SIZE
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
onChanged: (String text) {
//print("onchanged url");
widget.resourceDTO.url = text; // TODO check if ok
widget.onChanged(widget.resourceDTO);
// TODO check type of resource
widget.resourceDTO.type = ResourceType.ImageUrl; // ou VideoUrl
widget.resourceDTO.type = _isYouTubeVideo(widget.resourceDTO.url!) ? ResourceType.VideoUrl : ResourceType.ImageUrl; // ou VideoUrl
print("URL OR NOOOOT ?");
print(widget.resourceDTO.type);
},
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) {
case ResourceType.Image:
return Image.network(
(appContext.getContext() as ManagerAppContext).clientAPI!.resourceApi!.apiClient.basePath+"/api/Resource/"+ resourceDTO.id,
resourceDTO.url,
fit:BoxFit.fill,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent? loadingProgress) {
@ -35,7 +35,7 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
break;
case ResourceType.ImageUrl:
return Image.network(
resourceDTO.data,
resourceDTO.url,
fit:BoxFit.fill,
loadingBuilder: (BuildContext context, Widget child,
ImageChunkEvent? loadingProgress) {
@ -55,8 +55,9 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
);
break;
case ResourceType.Audio:
return FutureBuilder(
future: getAudio(resourceDTO.id, appContext),
return AudioPlayerFloatingContainer(audioBytes: null, resourceURl: resourceDTO.url, isAuto: true);
/*return FutureBuilder(
future: getAudio(resourceDTO.url, appContext),
builder: (context, AsyncSnapshot<dynamic> snapshot) {
Size size = MediaQuery.of(context).size;
if (snapshot.connectionState == ConnectionState.done) {
@ -67,7 +68,7 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
audioBytes = snapshot.data;
//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) {
return Text("No data");
} else {
@ -80,19 +81,19 @@ getElementForResource(dynamic resourceDTO, AppContext appContext) {
);
}
}
);
);*/
//return Text("Fichier audio - aucune visualisation possible");
break;
case ResourceType.Video:
return Text("Vidéo locale - aucune visualisation possible");
break;
case ResourceType.VideoUrl:
return Text(resourceDTO.data);
return Text(resourceDTO.url);
break;
}
}
Future<Uint8List?> getAudio(String resourceId, AppContext appContext) async {
/*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
@ -105,4 +106,4 @@ Future<Uint8List?> getAudio(String resourceId, AppContext appContext) async {
print("IN CATCH");
return null;
}
}
}*/

View File

@ -29,7 +29,7 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
child: Column(
children: [
Text("Nouvelle ressource", style: new TextStyle(fontSize: 25, fontWeight: FontWeight.w400)),
Column(
/*Column(
children: [
StringInputContainer(
label: "Nom :",
@ -40,8 +40,10 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
),
if (fileName != null) new Text(fileName),
],
),
Container(
),*/
Padding(
padding: const EdgeInsets.only(top: 10.0),
child: Container(
width: size.width *0.85,
height: size.height *0.5,
child: ResourceTab(
@ -54,6 +56,7 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
},
)
),
),
],
),
),
@ -89,7 +92,7 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async {
color: kPrimaryColor,
textColor: kWhite,
press: () {
if (resourceDetailDTO.label != null && resourceDetailDTO.label!.trim() != '') {
//if (resourceDetailDTO.label != null && resourceDetailDTO.label!.trim() != '') {
if(kIsWeb) {
if(resourceDetailDTO.url != null || filesToSendWeb != null) { // TODO clarify resourceDetailDTO.data != null
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);
}
}
} else {
/*} else {
showNotification(Colors.orange, kWhite, 'Veuillez donner un nom à la ressource', context, null);
}
}*/
//Navigator.of(context).pop();
//create(resourceDetailDTO, fileToSend, appContext, context);
},

View File

@ -190,14 +190,12 @@ class _ResourceBodyGridState extends State<ResourceBodyGrid> {
}
}
boxDecoration(ResourceDTO resourceDetailDTO, appContext) {
print("boxDecorationboxDecorationboxDecorationboxDecoration");
print(resourceDetailDTO);
boxDecoration(dynamic resourceDetailDTO, appContext) {
return BoxDecoration(
color: resourceDetailDTO.id == null ? kSecond : kBackgroundColor,
shape: BoxShape.rectangle,
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,
colorFilter: new ColorFilter.mode(Colors.black.withOpacity(0.3), BlendMode.dstATop),
image: new NetworkImage(

View File

@ -128,8 +128,10 @@ Future<List<ResourceDTO?>?> create(ResourceDTO resourceDTO, List<File>? files, L
ManagerAppContext managerAppContext = appContext.getContext();
int index = 0;
// TODO handle online resource
for (PlatformFile platformFile in filesWeb!) {
if(filesWeb != null) {
for (PlatformFile platformFile in filesWeb) {
var mimeType = "";
print("Coucou platformFile");
print(platformFile);
print(platformFile.name);
@ -140,18 +142,23 @@ Future<List<ResourceDTO?>?> create(ResourceDTO resourceDTO, List<File>? files, L
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;
@ -163,9 +170,13 @@ Future<List<ResourceDTO?>?> create(ResourceDTO resourceDTO, List<File>? files, L
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}');
Reference ref = storage.ref().child('pictures/${appContext.getContext().instanceId}/${Path.basename(newResource.id!.toString())}');
UploadTask uploadTask = ref.putData(platformFile.bytes!);
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);
@ -184,6 +195,18 @@ Future<List<ResourceDTO?>?> create(ResourceDTO resourceDTO, List<File>? files, L
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;
/*switch(resourceDTO.type) {

View File

@ -1,3 +1,4 @@
import 'package:firebase_storage/firebase_storage.dart';
import 'package:flutter/material.dart';
import 'package:manager_app/Components/confirmation_dialog.dart';
import 'package:manager_app/Components/message_notification.dart';
@ -135,6 +136,20 @@ Future<void> delete(ResourceDTO resourceDTO, AppContext appContext, context) asy
() {},
() async {
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
ManagerAppContext managerAppContext = appContext.getContext();
appContext.setContext(managerAppContext);

View File

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