What a file type is it 'File$' and how can it be made to type 'File' in flutter - flutter

I'm making functionality to be able to upload images to firebase storages through the Flutter Web. I need a list a files, where each file is 'File' type, but i get a type 'File$'.
import 'dart:io' as io;
SpeedDial(
animatedIconTheme: IconThemeData(size: 22.0),
child: Icon(Icons.add),
closeManually: false,
children: [
SpeedDialChild(
child: Icon(Icons.photo_library),
label: translate('agreement.image_uploader.select_images_button', context: context),
onTap: () => _callAddImagesFromWeb(context)),
],
)
_callAddImagesFromWeb(BuildContext context) async {
print('Called _callAddImagesFromWeb: upload images from web app');
html.InputElement uploadInput = html.FileUploadInputElement();
uploadInput.multiple = true;
uploadInput.click();
uploadInput.onChange.listen((changeEvent) {
print("User added images, length: " + uploadInput.files.length.toString());
allProcessAmount = uploadInput.files.length;
doneProcessAmount = 0;
uploadFile(uploadInput.files);
});
}
Method uploadFile get a list of Files and i need to storage each file to Firebase storage, but when i take one element from list, i get an error that ** Error: Expected a value of type 'File', but got one of type 'File$' **
Future uploadFile(List list) async {
// EXCEPTION IS HERE
io.File image = list.first;
var fileName = new DateTime.now().millisecondsSinceEpoch.toString();
StorageReference storageReference = FirebaseStorage.instance
.ref()
.child('agreements/' + widget.agreement.id + '/' + fileName);
StorageUploadTask uploadTask = storageReference.putFile(image);
await uploadTask.onComplete;
print('File Uploaded');
storageReference.getDownloadURL().then((fileURL) {
print(fileURL);
});
}

Related

Unable to retrieve files stored is firebase storage

I am trying to retrieve files stored is firebase storage to my app and later download them but I'm getting the error: W/NetworkRequest( 5407): No App Check token for request.
Below is my code snippet:
final firebase_storage.Reference ref = firebase_storage
.FirebaseStorage.instance
.ref('product/${data['file_name']}');
final Directory appDocDir = await getApplicationDocumentsDirectory();
final String appDocPath = appDocDir.path;
final File tempFile = File(appDocPath + '/' + '${data['file_name']}');
try {
await ref.writeToFile(tempFile);
await tempFile.create();
await OpenFile.open(tempFile.path);
} on firebase_core.FirebaseException {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'Error, file tidak bisa diunduh',
style: Theme.of(context).textTheme.bodyText1,
),
),
);
}

uploading files start from beginning when app killed in flutter or disconnect from internet and reconnect again

i am uploading files to firebase cloud storage in background with workmanager in flutter, it works good when the app is in background but when the app killed by user the uploading process starts from beginning and also when the user disconnect internet and reconnect it starts uploading process from beginning.
Here is my upload function
Future<void> uploadVideo() async {
List<String> filesPath = [];
await Future.forEach(imgSource, (AssetEntity element) async {
File file = await element.file;
filesPath.add(file.path);
});
await Workmanager().registerOneOffTask(
"1",
uploadFileTask,
inputData: <String, dynamic>{
'filesPath': filesPath,
},
constraints: Constraints(
networkType: NetworkType.connected,
requiresBatteryNotLow: true,
),
backoffPolicy: BackoffPolicy.exponential,
existingWorkPolicy: ExistingWorkPolicy.keep,
);
}
// Here is callbackDispatcher function
void callbackDispatcher() {
Workmanager().executeTask((task, inputData) async {
switch (task) {
case uploadFileTask:
try {
List<dynamic> dynamicType = inputData["filesPath"];
List<String> filesPath =
dynamicType.map((e) => e.toString()).toList();
await Firebase.initializeApp();
int counter = 1;
List<String> downloadUrlLinks = [];
await Future.forEach(filesPath, (String filePath) async {
File file = File(filePath);
String fullPath = getRandomName(file.path);
String storagePath = "test/$fullPath";
print("Full path HM" + fullPath);
String downloadUrl = await CloudService.uploadFileWithProgressBar(
file: file,
filePath: storagePath,
maxLength: filesPath.length,
uploadedLength: counter,
);
downloadUrlLinks.add(downloadUrl);
counter++;
});
await NotificationService.finishedNotification(
title: 'Uploading files finished');
print("download link: " + downloadUrlLinks.toString());
downloadUrlLinks = [];
} catch (e) {
print("uploading error" + e.toString());
}
break;
}
return Future.value(true);
});
}

Flutter GestureDetector with multiple futures

I got 2 futures. When I press a GestureDetector I want the first to be completed and then run the second one. But it doesn’t work. What can I do to fix the issue?
Here is my code.
GestureDetector(
onTap: () => pickImage(), uploadImageToFirebase(),
),
Future pickImage() async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_imageFile = File(pickedFile.path);
});
}
Future uploadImageToFirebase(BuildContext context) async {
String fileName = basename(_imageFile.path);
StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child('uploads/$fileName');
StorageUploadTask uploadTask = firebaseStorageRef.putFile(_imageFile);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
taskSnapshot.ref.getDownloadURL().then(
(value) => imageUrl = value,
);
}
You can use Future.wait() , It takes a List of Futures and return when all underlying future completes/resolves.
In your code, You can do something like this,
GestureDetector(
onTap: () => pickImageandUploadToFirebase(),
),
The method pickImageandUploadToFirebase() looks like this,
Future<void> pickImageandUploadToFirebase() async {
await Future.wait([
pickImage(),
uploadImageToFirebase(),
]);
}
and you already have the 2 methods pickImage() and uploadImageToFirebase()
Hope this helps, Happy fluttering !
upload this after image pick done,
like this
GestureDetector(
onTap: () => pickImage(context);
),
Future pickImage(context) async {
final pickedFile = await picker.getImage(source: ImageSource.gallery);
setState(() {
_imageFile = File(pickedFile.path);
});
uploadImageToFirebase(context);
}
Future uploadImageToFirebase(BuildContext context) async {
String fileName = basename(_imageFile.path);
StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child('uploads/$fileName');
StorageUploadTask uploadTask = firebaseStorageRef.putFile(_imageFile);
StorageTaskSnapshot taskSnapshot = await uploadTask.onComplete;
taskSnapshot.ref.getDownloadURL().then(
(value) => imageUrl = value,
);
}
also, another option is if you need to call one by one in single method.
then return data from first method "pickImage" after retrun done, you call second "uploadImageToFirebase",

Save Image Url in Cloud FireStore

I try to create details of product in Cloud FireStore. Create document and save image in storage is all works. Mu issue is image url doesn't save in document.
dart file
class ProductService {
Firestore _firestore = Firestore.instance;
void createProduct(_nameproductController, _priceproductController,
_currentCategory, url) async {
_firestore.collection("products").document().setData({
'name': _nameproductController,
'price': _priceproductController,
'category': _currentCategory,
'image': url,
});
}
}
upload image
void uploadImg() async {
var timekey = DateTime.now();
fb.StorageReference storageReference =
fb.storage().ref('imgProduct/${timekey.toString()}.jpg');
fb.UploadTaskSnapshot uploadTask = await storageReference
.put(_image1, fb.UploadMetadata(contentType: 'image/jpg'))
.future;
var imageUrl = await uploadTask.ref.getDownloadURL();
url = imageUrl.toString();
print('Image Url' + url);}
submit button
RaisedButton(
onPressed: () async {
if (_formKeyProduct.currentState.validate()) {
uploadImg();
ProductService().addProduct(
_nameproductController.text,
_priceproductController.text,
_currentCategory.categoryname.toString(),
url,
);
_formKeyProduct.currentState.reset();
_nameproductController.clear();
_priceproductController.clear();
}
setState(() {
_currentCategory = null;
});
},
you need to await uploadImg();

Flutter Dio : How to Upload Image?

I'm trying on Postman. And it works
I want upload some image to rest-api using Package DIO Package ,
I'm new for this package (i'm use this package just for CRUD operation) and i'm got problem when upload image operation.
i'm already reading documentation and nothing see for upload images. I'm try this code(ref on documentation) and got some error :
error:FileSystemException
message :"Cannot retrieve length of file"
OSError (OS Error: No such file or directory, errno = 2)
"File: '/storage/emulated/0/Android/data/com.example.mosque/files/Pictures/scaled_IMG_20190815_183541.jpg'"
Type (FileSystemException)
message:FileSystemException: Cannot retrieve length of file, path = 'File: '/storage/emulated/0/Android/data/com.example.mosque/files/Pictures/scaled_IMG_20190815_183541.jpg'' (OS Error: No such file or directory, errno = 2)
DioErrorType (DioErrorType.DEFAULT)
name:"DioErrorType.DEFAULT"
Api.dart
Future uploadImage({dynamic data,Options options}) async{
Response apiRespon = await dio.post('$baseURL/mahasiswa/upload/',data: data,options: options);
if(apiRespon.statusCode== 201){
return apiRespon.statusCode==201;
}else{
print('errr');
return null;
}
}
View.dart
void uploadImage() async {
FormData formData = FormData.from({
"name_image": _txtNameImage.text,
"image": UploadFileInfo(File("$_image"), "image.jpg")
});
bool upload =
await api.uploadImage(data: formData, options: CrudComponent.options);
upload ? print('success') : print('fail');
}
_image is type FILE
I hope who expert with this package can help me with this code and suggest me for upload images.
Thanks.
Full View.dart Code
import 'dart:io';
import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
import 'package:mosque/api/api_mosque.dart';
class UploadImage extends StatefulWidget {
#override
_UploadImageState createState() => _UploadImageState();
}
class _UploadImageState extends State<UploadImage> {
ApiHelper api = ApiHelper();
File _image;
TextEditingController _txtNameImage = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
leading: IconButton(
icon: Icon(Icons.arrow_left),
onPressed: () => Navigator.pop(context, false),
),
actions: <Widget>[
IconButton(
icon: Icon(Icons.file_upload),
onPressed: () {
uploadImage();
},
)
],
),
body: _formUpload(),
);
}
Widget _formUpload() {
return SingleChildScrollView(
scrollDirection: Axis.vertical,
child: Column(
children: <Widget>[
TextField(
controller: _txtNameImage,
keyboardType: TextInputType.text,
decoration: InputDecoration(hintText: "Nama Image"),
maxLength: 9,
textAlign: TextAlign.center,
),
SizedBox(
height: 50.0,
),
Container(
child: _image == null
? Text('No Images Selected')
: Image.file(_image),
),
SizedBox(
height: 50.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Icon(Icons.camera),
onPressed: () => getImageCamera(),
),
SizedBox(
width: 50.0,
),
RaisedButton(
child: Icon(Icons.image),
onPressed: () => getImageGallery(),
)
],
)
],
),
);
}
void uploadImage() async {
FormData formData = FormData.from({
"name_image": _txtNameImage.text,
"image": UploadFileInfo(File("$_image"), "image.jpg")
});
bool upload =
await api.uploadImage(data: formData, options: CrudComponent.options);
upload ? print('success') : print('fail');
}
getImageGallery() async {
var imageFile = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
_image = imageFile;
});
}
getImageCamera() async {
var imageFile = await ImagePicker.pickImage(source: ImageSource.camera);
setState(() {
_image = imageFile;
});
}
}
In Dio latest version, UploadFileInfo method has been replaced by MultipartFile class. And here the way how to use to post image, video or any file:
Future<String> uploadImage(File file) async {
String fileName = file.path.split('/').last;
FormData formData = FormData.fromMap({
"file":
await MultipartFile.fromFile(file.path, filename:fileName),
});
response = await dio.post("/info", data: formData);
return response.data['id'];
}
Even this question is asked a while ago, I believe the main issue is the size of image especially with Laravel.Flutter Image Picker library offers some functionalities to reduce the size of Image, I solved it with bellow steps:
Create a method to get the Image, I am using Camera to Capture the photo
Future getImage() async {
File _image;
final picker = ImagePicker();
var _pickedFile = await picker.getImage(
source: ImageSource.camera,
imageQuality: 50, // <- Reduce Image quality
maxHeight: 500, // <- reduce the image size
maxWidth: 500);
_image = _pickedFile.path;
_upload(_image);
}
Create _upload method to upload the photo, I am using Dio package Dio Package
void _upload(File file) async {
String fileName = file.path.split('/').last;
FormData data = FormData.fromMap({
"file": await MultipartFile.fromFile(
file.path,
filename: fileName,
),
});
Dio dio = new Dio();
dio.post("http://192.168.43.225/api/media", data: data)
.then((response) => print(response))
.catchError((error) => print(error));
}
On the server side, I am using Laravel Laravel, I handle the request as follow
public function store(Request $request)
{
$file = $request->file('file');
$extension = $file->getClientOriginalExtension();
$fullFileName = time(). '.'. $extension;
$file->storeAs('uploads', $fullFileName, ['disk' => 'local']);
return 'uploaded Successfully';
}
In the latest version of Dio :
It should look like this.
String fileName = imageFile.path.split('/').last;
FormData formData = FormData.fromMap({
"image-param-name": await MultipartFile.fromFile(
imageFile.path,
filename: fileName,
contentType: new MediaType("image", "jpeg"), //important
),
});
If without this line.
contentType: new MediaType("image", "jpeg")
Maybe it will cause an error: DioError [DioErrorType.RESPONSE]: Http status error [400] Exception
And get MediaType in this package: http_parser
The following code uploads multiple image files from a dio client to a golang server.
dioclient.dart
FormData formData = FormData.fromMap({
"name": "wendux",
"age": 25,
"other" : "params",
});
for (File item in yourFileList)
formData.files.addAll([
MapEntry("image_files", await MultipartFile.fromFile(item.path)),
]);
Dio dio = new Dio()..options.baseUrl = "http://serverURL:port";
dio.post("/uploadFile", data: formData).then((response) {
print(response);
}).catchError((error) => print(error));
golangServer.go
package main
import (
"fmt"
"io"
"net/http"
"os"
)
func uploadFile(w http.ResponseWriter, r *http.Request) {
err := r.ParseMultipartForm(200000)
if err != nil {
fmt.Fprintln(w, err)
return
}
formdata := r.MultipartForm
files := formdata.File["image_files"]
for i, _ := range files {
file, err := files[i].Open()
defer file.Close()
if err != nil {
fmt.Fprintln(w, err)
return
}
out, err := os.Create("/path/to/dir/" + files[i].Filename)
defer out.Close()
if err != nil {
fmt.Fprintf(w, "Unable to create the file for writing. Check your write access privilege")
return
}
_, err = io.Copy(out, file)
if err != nil {
fmt.Fprintln(w, err)
return
}
fmt.Fprintf(w, "Files uploaded successfully : ")
fmt.Fprintf(w, files[i].Filename+"\n")
}
}
func startServer() {
http.HandleFunc("/uploadFile", uploadFile)
http.ListenAndServe(":9983", nil)
}
func main() {
fmt.Println("Server starts!")
startServer()
}
I have found a solution, where I am uploading file a specific directory which is generated different camera package which requires file path to save jpg file in the provided path.
and I was fetching file name with path and passing to
DIO package
which was giving file length issue, to I have implemented below steps to solve the issue
get File Name With Full Path from directory
create a File from the Path
File(directoryFilePathWithExtension);
and pass File.path to the dio package
MultipartFile.fromFile(
File(directoryFilePathWithExtension).path,
filename: DateTime.now().toIso8601String(),
)
Use UploadFileInfo.fromBytes if you're working with memory images (The error message above shows that your file is invalid and doesn't exist).
Hi there are many issue in file upload
try in android Api 21 because it did not have android permissions if api is working in android api 21 then it wil also work on above versions.
you might not able to get the file in above android version
you just need
FormData formData = FormData.fromMap({
"av_document": await MultipartFile.fromFile(_filePath,filename:
_fileName),
});
to upload any file or image to server and one more thing to note
_filePaths = await FilePicker.getMultiFilePath(type: _pickingType,
fileExtension: _extension);
_fileName = _filePath.split('/').last
by using this process u can upload file or image to server
I am using
dio: ^4.0.6 (for uploading)
flutter_native_image: ^0.0.6+1 (for reducing image size)
to reduce file size
File? compressedFile = profileImage.value == null
? null
: await FlutterNativeImage.compressImage(
profileImage.value?.path ?? '',
quality: 20,
percentage: 60);
dio formData map
var formData = dio.FormData.fromMap({
"name": input['name']!.text,
"profile_pic": await dio.MultipartFile.fromFile(compressedFile.path),
"birth_date": input['dob']!.text,})
request ->
response = await _dio.post(url, data: formData);