From 54091ea2db0c80048654347d8ac36338b1ea02fb Mon Sep 17 00:00:00 2001 From: Thomas Fransolet Date: Thu, 23 Dec 2021 13:48:46 +0100 Subject: [PATCH] upload multiple files Windows and Web + if web no remember me --- lib/Components/resource_tab.dart | 17 ++-- lib/Components/upload_image_container.dart | 77 ++++++++++++++----- lib/Screens/Resources/new_resource_popup.dart | 17 ++-- lib/Screens/Resources/resources_screen.dart | 44 +++++++---- lib/Screens/login_screen.dart | 6 +- lib/main.dart | 5 -- 6 files changed, 112 insertions(+), 54 deletions(-) diff --git a/lib/Components/resource_tab.dart b/lib/Components/resource_tab.dart index a757281..72b6c0e 100644 --- a/lib/Components/resource_tab.dart +++ b/lib/Components/resource_tab.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:manager_app/Components/upload_image_container.dart'; import 'package:manager_app/Components/upload_online_resources_container.dart'; @@ -8,10 +9,12 @@ import 'package:managerapi/api.dart'; class ResourceTab extends StatefulWidget { final ResourceDTO resourceDTO; final Function onFileUpload; + final Function onFileUploadWeb; const ResourceTab({ Key key, this.resourceDTO, this.onFileUpload, + this.onFileUploadWeb, }) : super(key: key); @override @@ -51,7 +54,7 @@ class _ResourceTabState extends State with SingleTickerProviderStat ), Expanded( child: TabBarView( - children: getContent(widget.resourceDTO, widget.onFileUpload), + children: getContent(widget.resourceDTO, widget.onFileUpload, widget.onFileUploadWeb), controller: _tabController, ), ), @@ -85,7 +88,7 @@ class _ResourceTabState extends State with SingleTickerProviderStat } } -getContent(ResourceDTO resourceDTO, Function onFileUpload) { +getContent(ResourceDTO resourceDTO, Function onFileUpload, Function onFileUploadWeb) { List tabsToShow = new List(); // Local Image @@ -93,10 +96,14 @@ getContent(ResourceDTO resourceDTO, Function onFileUpload) { new Padding( padding: EdgeInsets.symmetric(horizontal: 8, vertical: 16), child: UploadImageContainer( - onChanged: (File file) { - onFileUpload(file); + onChanged: (List files) { + onFileUpload(files); resourceDTO.type = ResourceType.image; - } + }, + onChangedWeb: (List files) { + onFileUploadWeb(files); + resourceDTO.type = ResourceType.image; + }, ), ) ); diff --git a/lib/Components/upload_image_container.dart b/lib/Components/upload_image_container.dart index 0673b1a..73fd2a9 100644 --- a/lib/Components/upload_image_container.dart +++ b/lib/Components/upload_image_container.dart @@ -1,15 +1,18 @@ import 'dart:io'; -//import 'package:dart_vlc/dart_vlc.dart'; +import 'dart:typed_data'; +import 'package:file_picker/file_picker.dart'; import 'package:manager_app/Components/loading.dart'; import 'package:manager_app/constants.dart'; -//import 'package:filepicker_windows/filepicker_windows.dart'; import 'package:flutter/material.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; class UploadImageContainer extends StatefulWidget { - final ValueChanged onChanged; + final ValueChanged> onChanged; + final ValueChanged> onChangedWeb; const UploadImageContainer({ Key key, this.onChanged, + this.onChangedWeb, }) : super(key: key); @override @@ -19,6 +22,7 @@ class UploadImageContainer extends StatefulWidget { class _UploadImageContainerState extends State with SingleTickerProviderStateMixin { var filePath; File fileToShow; + String fileToShowWeb; @override void initState() { @@ -39,7 +43,41 @@ class _UploadImageContainerState extends State with Single return (filePath.toString().split('\\').last); } - void filePicker() { + Future filePicker() async { + FilePickerResult result; + if (kIsWeb) { + result = await FilePicker.platform.pickFiles( + type: FileType.custom, + dialogTitle: 'Sélectionner un fichier', + allowMultiple: true, + allowedExtensions: ['jpg', 'jpeg', 'png'], + ); + + if (result != null) { + List files = result.files; + + setState(() { + filePath = "Fichiers"; // Only show one picture + fileToShowWeb = "Aucun aperçu possible"; // Only show one picture + widget.onChangedWeb(files); + }); + } + } else { + result = await FilePicker.platform.pickFiles( + type: FileType.custom, + dialogTitle: 'Sélectionner un fichier', + allowMultiple: true, + allowedExtensions: ['jpg', 'jpeg', 'png'], + ); + + List files = result.paths.map((path) => File(path)).toList(); + var file = files[0]; + setState(() { + filePath = file.path; // Only show one picture + fileToShow = file; // Only show one picture + widget.onChanged(files); + }); + } /*final file = OpenFilePicker() ..filterSpecification = { 'Images (*.jpg; *.png)': '*.jpg;*.png', @@ -63,8 +101,7 @@ class _UploadImageContainerState extends State with Single showFile() { if (getFileName(filePath).contains(".mp4")) { - - return FutureBuilder( + /*return FutureBuilder( future: loadFile(fileToShow), builder: (context, AsyncSnapshot snapshot) { if (snapshot.connectionState == ConnectionState.done) { @@ -96,27 +133,27 @@ class _UploadImageContainerState extends State with Single ); } } - ); - - - - /*await Media.file(widget.file)*/ + );*/ } else { - return Image.file( - fileToShow, - height: 200, - fit:BoxFit.scaleDown - ); + if (kIsWeb) { + return null; + } else { + return Image.file( + fileToShow, + height: 200, + fit:BoxFit.scaleDown + ); + } } } loadFile(File fileToShow) async { //return await Media.file(fileToShow); - return null; + return null; // Useless no mp4 for now } displayElement() { - if (fileToShow == null) return Center( + if (fileToShow == null && fileToShowWeb == null) return Center( child: InkWell( onTap: () async { filePicker(); @@ -129,14 +166,14 @@ class _UploadImageContainerState extends State with Single child: Padding( padding: const EdgeInsets.only(left: 25.0, right: 25.0, top: 15.0, bottom: 15.0), child: Text( - "Ajouter un fichier", + "Ajouter un ou plusieurs fichiers", style: new TextStyle(color: kWhite), ), ) ), ), ); - if (fileToShow != null) + if (fileToShow != null || fileToShowWeb != null) return Container( margin: EdgeInsets.all(8.0), child: Card( diff --git a/lib/Screens/Resources/new_resource_popup.dart b/lib/Screens/Resources/new_resource_popup.dart index 56a00bc..b09f3e1 100644 --- a/lib/Screens/Resources/new_resource_popup.dart +++ b/lib/Screens/Resources/new_resource_popup.dart @@ -1,5 +1,6 @@ import 'dart:io'; +import 'package:file_picker/file_picker.dart'; import 'package:manager_app/Components/message_notification.dart'; import 'package:manager_app/Components/resource_tab.dart'; import 'package:flutter/material.dart'; @@ -13,7 +14,8 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async { ResourceDTO resourceDetailDTO = new ResourceDTO(); Size size = MediaQuery.of(context).size; var fileName; - File fileToSend; + List filesToSend; + List filesToSendWeb; var result = await showDialog( builder: (BuildContext context) => AlertDialog( @@ -43,8 +45,11 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async { height: size.height *0.5, child: ResourceTab( resourceDTO: resourceDetailDTO, - onFileUpload: (File file) { - fileToSend = file; + onFileUpload: (List files) { + filesToSend = files; + }, + onFileUploadWeb: (List files) { + filesToSendWeb = files; }, ) ), @@ -83,9 +88,9 @@ dynamic showNewResource(AppContext appContext, BuildContext context) async { color: kPrimaryColor, textColor: kWhite, press: () { - if (resourceDetailDTO.label != null) { - if (resourceDetailDTO.data != null || fileToSend != null) { - Navigator.pop(context, [resourceDetailDTO, fileToSend]); + if (resourceDetailDTO.label != null && resourceDetailDTO.label.trim() != '') { + if (resourceDetailDTO.data != null || filesToSendWeb.length > 0 || filesToSend.length > 0) { + Navigator.pop(context, [resourceDetailDTO, filesToSend, filesToSendWeb]); } else { showNotification(Colors.orange, kWhite, 'Aucun fichier n\'a été chargé', context, null); } diff --git a/lib/Screens/Resources/resources_screen.dart b/lib/Screens/Resources/resources_screen.dart index 64939db..c13faa7 100644 --- a/lib/Screens/Resources/resources_screen.dart +++ b/lib/Screens/Resources/resources_screen.dart @@ -1,6 +1,7 @@ import 'dart:convert'; +import 'dart:developer'; import 'dart:io'; - +import 'package:file_picker/file_picker.dart'; import 'package:flutter/material.dart'; import 'package:manager_app/Components/loading.dart'; import 'package:manager_app/Components/message_notification.dart'; @@ -13,6 +14,7 @@ import 'package:manager_app/constants.dart'; import 'package:managerapi/api.dart'; import 'package:provider/provider.dart'; import 'package:http/http.dart' as http; +import 'package:flutter/foundation.dart' show kIsWeb; class ResourcesScreen extends StatefulWidget { final Function onGetResult; //return ResourceDTO @@ -51,7 +53,7 @@ class _ResourcesScreenState extends State { var result = await showNewResource(appContext, context); if (result != null) { - await create(result[0], result[1], appContext, context); + await create(result[0], result[1], result[2], appContext, context); setState(() {}); // For refresh } } else { @@ -85,19 +87,35 @@ Future getResources(Function onGetResult, bool isImage, dynamic appContext return resources; } -Future create(ResourceDTO resourceDTO, File file, AppContext appContext, context) async { +Future create(ResourceDTO resourceDTO, List files, List filesWeb, AppContext appContext, context) async { switch(resourceDTO.type) { case ResourceType.image: case ResourceType.video: + var request = http.MultipartRequest('POST', Uri.parse(appContext.getContext().clientAPI.resourceApi.apiClient.basePath+"/api/Resource/upload")); - request.files.add( - await http.MultipartFile( - 'picture', - file.readAsBytes().asStream(), - file.lengthSync(), - filename: file.path.toString().split("/").last - ) - ); + + if (kIsWeb) { + for (PlatformFile file in filesWeb) { + request.files.add( + await http.MultipartFile.fromBytes( + 'picture', + file.bytes, + filename: file.name + ) + ); + } + } else { + for (File file in files) { + request.files.add( + await http.MultipartFile( + 'picture', + file.readAsBytes().asStream(), + file.lengthSync(), + filename: file.path.toString().split("/").last + ) + ); + } + } ManagerAppContext managerAppContext = appContext.getContext(); request.headers["authorization"]="Bearer ${managerAppContext.token.accessToken}"; @@ -108,10 +126,8 @@ Future create(ResourceDTO resourceDTO, File file, AppContext appCon final respStr = await res.stream.bytesToString(); if (res.statusCode == 200) { - var result = ResourceDTO.fromJson(jsonDecode(respStr)); showNotification(Colors.green, kWhite, 'La ressource a été créée avec succès', context, null); - - return result; + return null; } else { showNotification(kPrimaryColor, kWhite, 'Une erreur est survenue lors de la création de la ressource', context, null); } diff --git a/lib/Screens/login_screen.dart b/lib/Screens/login_screen.dart index 064f13a..c860245 100644 --- a/lib/Screens/login_screen.dart +++ b/lib/Screens/login_screen.dart @@ -13,6 +13,7 @@ import 'package:manager_app/client.dart'; import 'package:manager_app/constants.dart'; import 'package:managerapi/api.dart'; import 'package:provider/provider.dart'; +import 'package:flutter/foundation.dart' show kIsWeb; class LoginScreen extends StatefulWidget { final Session session; @@ -51,9 +52,6 @@ class _LoginScreenState extends State { LoginDTO loginDTO = new LoginDTO(email: email, password: password); TokenDTO token = await clientAPI.authenticationApi.authenticationAuthenticateWithJson(loginDTO); - print("Token ??"); - print(token); - print(token.accessToken); setAccessToken(token.accessToken); if (isRememberMe) { @@ -172,7 +170,7 @@ class _LoginScreenState extends State { password = value; }, ), - Padding( + if(!kIsWeb) Padding( padding: const EdgeInsets.all(8.0), child: Row( crossAxisAlignment: CrossAxisAlignment.center, diff --git a/lib/main.dart b/lib/main.dart index 50eba52..8e7413b 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -16,11 +16,6 @@ Future main() async { String initialRoute; WidgetsFlutterBinding.ensureInitialized(); - /*if (Platform.isWindows) { - /*setWindowTitle("Manager"); - setWindowMinSize(Size(1250, 850)); - setWindowMaxSize(Size(3840, 2160));*/ - }*/ initialRoute = '/welcome';