Fileuploading. Works on all platforms (iOS, Android and web)
import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart';
import 'package:file_picker/file_picker.dart';
class FilePickerTest extends StatefulWidget {
const FilePickerTest({super.key});
@override
State<FilePickerTest> createState() => _FilePickerTestState();
}
class _FilePickerTestState extends State<FilePickerTest> {
Uint8List? dataBytes;
/*
* Simpler Stream Handling: If your goal is to process the entire stream from start to finish in a simpler,
* more readable way without needing immediate feedback, then await for is recommended.
* It simplifies the code because it allows you to handle data in a sequential,
* synchronous style rather than dealing with callbacks and the complexities of stream events.
*/
Future<void> pickFilesMethod1({
required Function callback,
List<String>? allowedExtensions,
bool allowMultiple = false,
}) async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
withReadStream: true,
allowMultiple: allowMultiple,
type: FileType.any,
onFileLoading: (FilePickerStatus status) => debugPrint('status: $status'),
);
if (result != null) {
for (PlatformFile file in result.files) {
// Max filesize 5 MB
if (file.size > 5000000) {
debugPrint('Invalid file size: ${file.size} bytes');
await callback([], 406); // Error code for large file
return;
}
final Stream<List<int>> stream = file.readStream!;
final List<int> bytes = [];
try {
// Use `await for` for simpler and more readable stream handling
await for (final chunk in stream) {
bytes.addAll(chunk);
}
// Successfully processed file
await callback(bytes, 201);
} catch (error) {
debugPrint('An error occurred while reading the file: $error');
await callback([], 500); // General error code
}
}
}
}
/*
* Real-Time Processing:
* If your use case requires handling each data chunk as soon as it becomes available (for example,
* in a live data stream or when showing a progress bar), then stream.listen() is appropriate.
*/
Future<void> pickFilesMethod2({
required Function callback,
List<String>? allowedExtensions,
bool allowMultiple = false,
}) async {
FilePickerResult? result = await FilePicker.platform.pickFiles(
withReadStream: true,
allowMultiple: allowMultiple,
//type: (allowedExtensions != null) ? FileType.custom : FileType.any,
//allowedExtensions: allowedExtensions,
type: FileType.image,
onFileLoading: (FilePickerStatus status) => debugPrint('status: $status'),
);
if (result != null) {
for (PlatformFile file in result.files) {
Stream<List<int>> stream = file.readStream!;
List<int> bytes = [];
stream.listen(
(data) {
bytes.addAll(data);
},
onError: (err) {
debugPrint('An error: $err');
},
onDone: () async {
if (file.size > 5000000) {
//max 5Mbytes
await callback([], 406);
debugPrint('Invalid filesize');
return;
}
callback(bytes, 201);
},
cancelOnError: true,
);
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
decoration: BoxDecoration(
border: Border.all(),
borderRadius: const BorderRadius.all(
Radius.circular(10),
),
),
margin: const EdgeInsets.all(10),
width: double.infinity,
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
ElevatedButton(
onPressed: () => pickFilesMethod1(
callback: (bytes, status) => setState(() {
dataBytes = Uint8List.fromList(bytes);
})),
child: const Icon(Icons.upload_file),
),
const SizedBox(
height: 20,
),
if (dataBytes == null)
const SizedBox(
width: 500,
child: Placeholder(),
),
if (dataBytes != null)
Image.memory(
dataBytes!,
width: 500,
),
],
),
),
);
}
}
