I am working on an app where I want to record a video to file with the timestamp as name. As I understand it you should be able to use the returned XFile and use the saveTo function. I get an error that does seem odd to me.
Here is the code where I save the video:
void onStopRecordingButtonPressed() {
stopVideoRecording().then((video) async {
if (video != null) {
final path = await _localPath;
final file = File('$path/${timestamp() + ".mp4"}');
await file.create(recursive: true);
print("video path " + video.path.toString());
print("VideoFile: " + video.name.toString());
print("Desired path: " + file.toString());
var fileExists = await file.exists();
if (fileExists) {
print("fileExists");
} else {
print("No, this does not exist");
}
video.saveTo(file.toString());
}
});
}
Future<XFile?> stopVideoRecording() async {
final CameraController? cameraController = controller;
if (cameraController == null || !cameraController.value.isInitialized) {
return null;
}
try {
return cameraController.stopVideoRecording();
} on CameraException catch (e) {
_showCameraException(e);
return null;
}
}
and this is the output:
flutter: video path /var/mobile/Containers/Data/Application/3339192C-B309-4E08-8017-FFBD735CA576/Documents/camera/videos/REC_4525E32A-81C0-42BA-A3A4-48E325E44E58.mp4
flutter: VideoFile: REC_4525E32A-81C0-42BA-A3A4-48E325E44E58.mp4
flutter: Desired path: File: '/var/mobile/Containers/Data/Application/3339192C-B309-4E08-8017-FFBD735CA576/Documents/1652533015054.mp4'
flutter: fileExists <-- Exists
open on File: '/var/mobile/Containers/Data/Application/3339192C-B309-4E08-8017-FFBD735CA576/Documents/1652533015054.mp4': No such file or directory <-- So how can this be?
Application finished.
XFile.toString() is the string representation of the object, not a path.
File: '/var/mobile/Containers/Data/Application/3339192C-B309-4E08-8017-FFBD735CA576/Documents/1652533015054.mp4'
Try something like this:
video.saveTo(file.path);
Related
Im new at Flutter and im trying to add images taken in my app to a custom folder in the gallery. Its the same as on WhatsApp, if you take a picture in a chat the WhatsApp create a custom folder called WhatsApp Images.
For that, I tried this:
Future<bool> saveFile(String url, String fileName) async {
Directory directory;
try {
if (Platform.isAndroid) {
if (await _requestPermission(Permission.storage)) {
directory = (await getExternalStorageDirectory())!;
String newPath = '';
List<String> folders = directory.path.split('/');
for (int x = 1; x < folders.length; x++) {
String folder = folders[x];
if (folder != 'Android') {
newPath += '/$folder';
} else {
break;
}
}
newPath = '$newPath/OnlaineApp';
directory = Directory(newPath);
} else {
return false;
}
} else {
if (await _requestPermission(Permission.photos)) {
directory = await getTemporaryDirectory();
} else {
return false;
}
}
if (!await directory.exists()) {
await directory.create(recursive: true);
}
if (await directory.exists()) {
File saveFile = File('${directory.path}/$fileName');
await dio.download(url, saveFile.path,
onReceiveProgress: (downloaded, totalSize) {
setState(() {
progress = downloaded / totalSize;
});
});
if (Platform.isIOS) {
await ImageGallerySaver.saveFile(
saveFile.path,
isReturnPathOfIOS: true,
);
}
return true;
}
} catch (e) {
print(e);
}
return false;
}
Future<bool> _requestPermission(Permission permission) async {
if (await permission.isGranted) {
return true;
} else {
var result = await permission.request();
if (result == PermissionStatus.granted) {
return true;
} else {
return false;
}
}
}
downloadFile() async {
setState(() {
loading = true;
});
bool downloaded = await saveFile(
'lib/assets/images/fundo_interno.png',
'OnlaineApp Imagens',
);
if (downloaded) {
print('File downloaded');
} else {
print('Problem downloaded file');
}
setState(() {
loading = false;
});
}
I already add in Android>app>src>main> AndroidManifest.xml these lines of code (for permission):
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
...
android:requestLegacyExternalStorage="true"
The problem I got is: I/flutter ( 5424): FileSystemException: Creation failed, path = '/storage/emulated/0/OnlaineApp' (OS Error: Permission denied, errno = 13)
" i use flutte sound package "
"saveFile function get the path of file and the fileName and save it to external file "
Future<bool> saveFile(Uint8List url,String fileName) async {
Directory? directory;
directory = await getApplicationDocumentsDirectory();
/// print("direcory ===>"+directory.path.toString());
try {
if (Platform.isAndroid) {
directory = await getExternalStorageDirectory();
if (await _requstPermission(Permission.storage) &&
await _requstPermission(Permission.accessMediaLocation) &&
await _requstPermission(Permission.manageExternalStorage)) {
String newPath = "";
List<String> folders = directory!.path.split("/");
for (int i = 1; i < folders.length; i++) {
String folder = folders[i];
if (folder != "Android") {
newPath += "/" + folder;
} else {
break;
}
}
newPath = "/storage/emulated/0/Android/SpaChat2/";
directory = Directory(newPath);
//print(directory.path);
} else {
return false;
}
} else {
}
if (!await directory.exists()) {
await directory.create(recursive: true);
}
if (await directory.exists()) {
File audioFile = File(
directory.path +fileName.split("/").last);
print("//////////////////////////////////////////////");
// print(bytes);
print("url =============================================="+utf8.decode(url));
await audioFile.writeAsBytes(url);
return true;
}
} catch (e) {
print(e);
}
return false;
}
" _requstPermission get permission for access device resource "
Future<bool> _requstPermission(Permission permission) async {
if (await permission.isGranted) {
return true;
} else {
var res = await permission.request();
if (res == PermissionStatus.granted) {
return true;
} else {
return false;
}
}
}
" starting record voice"
void startRecord() async {
try {
_myRecorder.stopRecorder();
} catch (e) {}
currentDuration.value = Duration.zero;
try {
bool hasStorage = await _requstPermission(Permission.storage);
bool hasMic = await _requstPermission( Permission.microphone);
if (!hasStorage || !hasMic) {
if (!hasStorage) await _requstPermission(Permission.storage);
if (!hasMic) await _requstPermission( Permission.microphone);
print('[chat_composer] 🔴 Denied permissions');
return;
}
if (onRecordStart != null) onRecordStart!();
Directory dir = await getApplicationDocumentsDirectory();
String path = dir.path +
'/' +
DateTime.now().millisecondsSinceEpoch.toString() +
'.aac';
pathToSaveAudio=path;
await _myRecorder.startRecorder(
toFile: pathToSaveAudio,
//codec: Codec.aacADTS,
);
emit(RecordAudioStarted());
} catch (e) {
emit(RecordAudioReady());
}
}
" stopRecord functon stop recording after stop record voice it call saveFile function and add the path of voice to saveFile arguments "
void stopRecord() async {
// timer.cancel();
try {
String? result = await _myRecorder.stopRecorder();
if (result != null) {
// tempPath =result;
print('[chat_composer] 🟢 Audio path: "$result');
onRecordEnd(result);
Uint8List bytes = Utf8Encoder().convert(pathToSaveAudio);
saveFile(bytes,pathToSaveAudio);
}
} finally {
currentDuration.value = Duration.zero;
}
emit(RecordAudioReady());
}
I have this code here in my provider, whenever I call getSongs the returned mp3s is null. I have it coded this way so that I can memoize mp3s.
class Songs with ChangeNotifier {
final tagger = Audiotagger();
List<Tag?>? mp3s;
Future<Tag?> getTags(String path) async {
final Tag? tag = await tagger.readTags(path: path);
return tag;
}
Future<Uint8List?> getArtwork(String path) async {
final Uint8List? artwork = await tagger.readArtwork(path: path);
return artwork;
}
Future<List<Tag?>> getSongs() async {
if (mp3s == null) {
final directory = Directory('/storage/emulated/0/Download');
List<FileSystemEntity> _files;
List<Tag?> _songs = [];
_files = directory.listSync(recursive: true, followLinks: false);
for (FileSystemEntity entity in _files) {
String path = entity.path;
if (path.endsWith('.mp3')) {
_songs.add(await getTags(path));
}
}
mp3s = _songs;
} else {
return mp3s!;
}
return mp3s!;
}
}
Actually, the problem to this is that there's a mp3 file that threw an error, because of this, it caused _songs to be null and therefore mp3s to be null.
Here comes the pdf converted to base64 from an API. I cannot view and download from within the application. I would be glad if you help.
Thanks in advance.
First you need to add "path_provider" and "open_file"
dependencies:
path_provider: ^2.0.9
open_file: ^3.2.1
Then create new class
class FileProcess {
static bool isFolderCreated = false;
static Directory? directory;
static checkDocumentFolder() async {
try {
if (!isFolderCreated) {
directory = await getApplicationDocumentsDirectory();
await directory!.exists().then((value) {
if (value) directory!.create();
isFolderCreated = true;
});
}
} catch (e) {
print(e.toString());
}
}
static Future<File> downloadFile() async {
final base64str = "put your base64 value";
Uint8List bytes = base64.decode(base64str);
await checkDocumentFolder();
String dir =
directory!.path + "/" + "your file name" + ".pdf";
File file = new File(dir);
if (!file.existsSync()) file.create();
await file.writeAsBytes(bytes);
return file;
}
}
After you create the class you can use it for download your pdf.
For open the file add this lines into your class
static void openFile(String fileName) {
String dir =
directory!.path + "/${fileName}.pdf";
OpenFile.open(dir));
}
After all you can use like
await FileProcess.downloadFile()
and
FileProcess.openFile(fileName)
These codes should be working.
I am using the dio plugin for downloading file in flutter and showing progress of download in widgets, while doing backpress from current downloading screen getting below exception
Unhandled Exception: setState() called after dispose(): _FileDownloadCardState#537ff(lifecycle state: defunct, not mounted)
This is my code with some file validation
Future<void> downloadFile(OfflineMapFile offlineMapFile) async {
if(offlineMapFile.isDownloading) {
return;
}
Directory fileDir;
try {
offlineMapFile.isDownloading = true;
Dio dio = Dio();
Directory dir = await UAAppContext.getInstance().appDir;
//todo: need to test on ios
fileDir = await new Directory(dir.path + offlineMapFile.fileStoragePath).create();
await dio.download(
offlineMapFile.fileUrl, "${fileDir.path}/${offlineMapFile.fileName}",
onReceiveProgress: (received, total) {
if (total != -1) {
print("Rec: $received , Total: $total");
debugPrint("Directory path : " +
offlineMapFile.fileStoragePath +
"/" +
offlineMapFile.fileName);
setState(() {
offlineMapFile.isDownloading = true;
offlineMapFile.isDownloaded = false;
downloadProgressString = ((received / total) * 100).toStringAsFixed(0) + "%";
});
}
});
} catch (e) {
print(e);
setState(() {
offlineMapFile.isDownloading = false;
offlineMapFile.isDownloaded = false;});
} finally {
// TODO Check whether the files are downloaded or not! Validation
// And set state accordingly.
setState(() {
//TODO change boolean as per the file Validation
offlineMapFile.isDownloading = false;
offlineMapFile.isDownloaded = true;
downloadProgressString = "Completed";
if(offlineMapFile.fileName.contains(".zip") && fileDir != null){
CommonUtils.unzipFile(fileDir.path +"/"+ offlineMapFile.fileName, fileDir.path + "/Offline/");
}
});
print("Download completed");
}
}
You are calling a setState on a unmounted widget, to solve this you just need to add this condition
if(mounted) {
setState(//....
}