File is not loading from DocumentDirectory Path Flutter - flutter

i am new to Flutter.
I build simple demo app in which user can fill simple form and once user press button then those data will save into SQLite DB.
There's only 3 content. Title, Image Path (Image saved to DocumentDirectory), Location Details.
Add Screen
Listing Screen
Below is my code to copy image to path.
Future<void> _takePicture() async {
final picker = ImagePicker();
final pickedFile = await picker.getImage(
source: ImageSource.camera,
maxWidth: 600,
);
if (pickedFile == null) {
return;
}
setState(() {
_storedImage = File(pickedFile.path);
});
final appDir = await syspaths.getApplicationDocumentsDirectory();
String relativePath = '/' +
DateTime.now().millisecondsSinceEpoch.toString() +
path.basename(pickedFile.path);
String newPath = '${appDir.path}' + relativePath;
final savedImage = await File(pickedFile.path).copy('$newPath');
widget.onSelectImage(savedImage);
}
Listing Item Code
child: Card(
elevation: 5,
child: ListTile(
leading: CircleAvatar(
backgroundImage: FileImage(greatPlaces.items[index].image),
),
title: Text(greatPlaces.items[index].title),
subtitle: Text(
greatPlaces.items[index].location.address),
onTap: () {
print(greatPlaces.items[index].image);
//Go to detail page...
},
),
)
ISSUE ==> When i add new place and view the added place list then images are loading fine but when i stop and rerun project then i am getting below error and image is not loading.
ERROR
════════ Exception caught by image resource service
════════════════════════════ The following FileSystemException was
thrown resolving an image codec: Cannot open file, path =
'/var/mobile/Containers/Data/Application/607FB621-ABDA-472F-8B7A-D9B1BEC4A15D/Documents/1616508266743image_picker_34814E6F-218C-48F6-BE36-C4D7949F0496-1511-0000017478AD7F14.jpg'
(OS Error: No such file or directory, errno = 2) When the exception
was thrown, this was the stack
#0 _File.open. (dart:io/file_impl.dart:356:9) (elided 13 frames from dart:async) Path:
/var/mobile/Containers/Data/Application/607FB621-ABDA-472F-8B7A-D9B1BEC4A15D/Documents/1616508266743image_picker_34814E6F-218C-48F6-BE36-C4D7949F0496-1511-0000017478AD7F14.jpg ════════════════════════════════════════════════════════════════════════════════
I downloaded app container and confirm image exist at the same place. greatPlaces.items[index].image return the File
NOTE: ==> Same code working fine in Android Devices.
it will be very helpful if someone help me with this. Thanks

Path of the documents directory changes on iOS after each app update. Therefore, one can not store absolute paths to the files stored in this directory. Instead, it is required to store the relative paths and then join them with the value returned by getApplicationDocumentsDirectory() every time to access the files.

Related

Uploading image into Floating Action Button, set state not working

I have a floating action button that I want a user to click to take a picture with their camera and then have that image replace the camera icon on the floating action bar button.
Here is the code for my FAB, and including uploading the image to firestore storage.
floatingActionButton: FloatingActionButton.large(
heroTag: "add image",
backgroundColor: const Color(0xFF93C3B9),
child: (imageURL == ' ')
? const Icon(Icons.add_a_photo_outlined)
: Image.network(imageURL),
//open add gear page
onPressed: () async {
// todo: upload an image to Firebase Storage
//Take picture
ImagePicker imagePicker = ImagePicker();
XFile? file = await imagePicker.pickImage(source: ImageSource.camera);
if (file == null) return;
String uniqueFileName =
DateTime.now().millisecondsSinceEpoch.toString();
//Get reference to storage root
Reference referenceRoot = FirebaseStorage.instance.ref();
Reference referenceDirImages = referenceRoot.child('images/$userID');
Reference referenceImageToUpload =
referenceDirImages.child(uniqueFileName);
try {
//upload image
await referenceImageToUpload.putFile(File(file.path));
//get download URL
setState(() async {
imageURL = await referenceImageToUpload.getDownloadURL();
print(imageURL);
});
//upload path to fireStore database
} catch (error) {}
},
),
After the image uploads it's like the set state is not working to replace the icon with the image. The odd part is is I crtl-s and save in Visual Studio Code then the widgets seem to rebuild and then the image is visible there...
So after playing around with my code a bit I decided to edit the above code and take tha await function out of the setState() and make setState() not async anymore:
//get download URL
String tempUrl = await referenceImageToUpload.getDownloadURL();
setState(() {
print("--------- Set State -----------");
imageURL = tempUrl;
print("--------- Set State end -----------");
});
print("New image url $imageURL ------------");
not sure why it works, but this solves my issue.
By your description of the issue, I think you might be using StatelessWidget instead of StatefulWidget.
You see the button change when performing a hotreload because the value of imageURL is correctly changing internally, but you need a StatefulWidget to update the UI also.
Hope it helps!

Flutter: Async Await Function Not Waiting

I am doing some image processing and building in my app using the Image package. In this case, I am building a LinearProgressIndicator widget that is then converted into an image file, that is then merged into a larger image later on. However, the functions to build and take the image of the progress indicator widget isn't being waited on and the following error is observed
FileSystemException: Cannot open file, path = '/Users//Library/Developer/CoreSimulator/Devices//data/Containers/Data/Application//Library/Caches/bar.png' (OS Error: No such file or directory, errno = 2)
However, the progress indicator file is being created (I can see the cache), and then if I rerunning the image processing it works just fine (because now the file is there). However, I need it work on the first time. Here is what I have for image processing
import 'package:image/image.dart' as ui;
Future<File> instagramChalShare(BuildContext context, double progress) async {
//this is where it does not appear the progressBarPathFunct is being waited on
final testFile = await progressBarPathFunct(context, progress);
ui.Image tester = ui.decodeImage(testFile.readAsBytesSync());
//image is then resized
ui.Image progressResized = ui.Image(600, 90);
ui.drawImage(progressResized, tester);
//now progress bar is merged into larger image
final mergedImage = ui.Image(width, height);
ui.copyInto(mergedImage, progressResized, blend: true);
List<int> imageFile = ui.encodePng(mergedImage);
final imageFilePath = await File('${(await getTemporaryDirectory()).path}/temp.png').create();
print('picture finished $imageFilePath');
return imageFilePath.writeAsBytes(imageFile);
}
Here is the function to build the LinearProgressIndictor, convert it to an image, and create a file where the image is held.
Future<File> progressBarPathFunct(BuildContext context, double progress) async {
final progressFile = File('${(await getTemporaryDirectory()).path}/bar.png');
var indicator = LinearPercentIndicator(
percent: progress > 1.0 ? 1.0 : progress,
width: context.size.width,
lineHeight: 13,
),
barRadius: Radius.circular(20),
);
screenshotController.captureFromWidget(
InheritedTheme.captureAll(context, Material(child: indicator)),
).then((capturedProgress) async {
await progressFile.create(recursive: true);
await progressFile.writeAsBytes(capturedProgress);
});
print('progress bar path from functions ${progressFile.path}');
return progressFile;
}
This function is working, but it seems the top one creating the merged Image file is not waiting for this function to finish before attempting to complete.
Edit
I am following the example from the screenshot package to generate an image of a widget that is not on the screen.

Upload race condition - Google Firebase Storage

I am attempted to update an avatar on my app and then load and display it once done. However, I am seeing the following errors which seem to indicate a false positive or race condition when the image has actually finished uploading.
I'm using a CicleAvatar widget, but also attempted with NetworkImage and am experiencing the same issues. I have also attempted .then/onComplete and various others outside of a delayed or wrapping it in a completer.
What is the best way to handle Firebase storage upload and immediate download without error§
Example Error n attempting to retrieve the image from the DownloadURLL:
════════ Exception caught by image resource service
════════════════════════════ HTTP request failed, statusCode: 503,
!isImageProcessing
? GestureDetector(
onTap: () => _uploadAvatarImage(),
child: CircleAvatar(
minRadius: 40,
backgroundColor: Colors.grey,
backgroundImage: NetworkImage(user.imageURL),
),
)
: Center(
child: CircularProgressIndicator(),
),
The actual upload of the file is being managed in this function/class
class StorageController {
static Future<String> storeAvatarImage(File file) async {
// Get user UUID to reference avatar;
String uuid = await identityBloc.retrieveActiveUUID();
String downloadURL;
TaskSnapshot ts;
ts = await firebase_storage.FirebaseStorage.instance
.ref('avatars/$uuid-avatar.png')
.putFile(file);
downloadURL = await ts.ref.getDownloadURL();
User user = await ProfileDataController.retrieveUserProfile();
user.imageURL = downloadURL;
await ProfileDataController.createUserProfile(user);
downloadURL = downloadURL;
return downloadURL;
}
}
I think you are not properly awaiting for the file upload. Can you change this line to read:
ts = await firebase_storage.FirebaseStorage.instance
.ref('avatars/$uuid-avatar.png')
.putFile(file);
// removed the below part
// .snapshot;
The image would update if there are listeners to listen to changes in the changed user avatar.
What I would advise as a workaround is store the avatarUrl to firestore or rtdb, there you can set a listener that updates the UI on the frontend when a change is written there.
Initially, the avatarUrl field would be null then when a user uploads a new picture the field is then a string and you can supply it to your UI

How can I share voice file(mpeg) which in app files to other app(like whatsapp) in flutter

I tried flutter share 2.0.1 pluggin for share voice file but it did not work(No such file). Could you solve this problem or how can I share voice file to other app? Here is my code and error screenshot.
E/flutter (31567): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: PlatformException(assets/voices/pırt.mpeg (No such file or directory), null, null, null)
E/flutter (31567): #0 StandardMethodCodec.decodeEnvelope (package:flutter/src/services/message_codecs.dart:597:7)
E/flutter (31567): #1 MethodChannel._invokeMethod (package:flutter/src/services/platform_channel.dart:158:18)
IconButton(
icon: Icon(Icons.send),
color: Colors.black,
iconSize: 35,
onPressed: () {
try{
Share.shareFiles(["assets/voices/pırt.mpeg"],text: "Share");
}
catch(ex){
print(ex);
}
},
),
As the error states, assets/voices/pırt.mpeg is not a valid path to a file on the OS. That's an asset, packaged into your application. If you want to share assets, you need to make them a file on the device first.
You'll need to add the path_provider dependency:
dependencies:
path_provider: ^2.0.1
Then, make a new File and write the data from the asset to the File:
//Get directory and make a file object
final Directory dir = await getTemporaryDirectory();
final File file = File(dir.path + '/mpeg_data');
//Get data from assets
ByteData data = await rootBundle.load('assets/voices/pırt.mpeg');
//Write actual data
await file.writeAsBytes(data.buffer.asUint8List());
This should all go before you share the file. Then when you share the file, use the path of the file object you created:
//Get directory and make a file object
final Directory dir = await getTemporaryDirectory();
final File file = File(dir.path);
//Get data from assets
ByteData data = await rootBundle.load('assets/voices/pırt.mpeg');
//Write actual data
await file.writeAsBytes(data.buffer.asUint8List());
try{
Share.shareFiles([file.path],text: "Share");
}
catch(ex){
print(ex);
}

'file.existsSync()': is not true

I am going to store an image in firebase storage. When I send file through image picker then its working fine. But when I manually pass link of image then it is showing an error that says:
'package:firebase_storage/src/storage_reference.dart':
Failed assertion: line 62 pos 12: 'file.existsSync()': is not true.
I am writing following code:
File image = File("assets/img/pic.jpg");
final StorageReference firebaseStorageRef =
FirebaseStorage.instance.ref().child('image');
InkWell(
child: Text("Tap to Upload"),
onTap: () {
firebaseStorageRef.putFile(image);
},
),
The error says it, the file doesn't exists, before doing that you should check if the file is there or create it if it's not
InkWell(
child: Text("Tap to Upload"),
onTap: () async {
File image = await File("assets/img/pic.jpg").create();
// it creates the file,
// if it already existed then just return it
// or run this if the file is created before the onTap
// if(image.existsSync()) image = await image.create();
firebaseStorageRef.putFile(image);
},
),
Also I'm not sure if you can change/create files in the assets folder, if that doesn't work maybe try to put the file in a temp directory of your app