I'm building a receipt scanner using the Flutter OCR plugin provided by Veryfi.
Here's a Stream function that reads an image and returns a dynamic array containing the necessary values.
Note the credentials from VeryfiDart
are removed.
The showImage
variable is an image file either captured from a camera or selected from an image gallery.
class ReceiptProcessor {
Future<dynamic> processReceipt(File image) async {
List<List<Widget>> itemList = [];
Uint8List imageData = image.readAsBytesSync();
String fileData = base64Encode(imageData);
VeryfiDart client = VeryfiDart(
'ClientId',
'ClientSecret',
'Username',
'ApiKey',
);
await client.processDocument('receipt.jpg', fileData).then(
(response) {
String totalPayment = response['total'].toString();
String currencyCode = response['currency_code'];
String vendorName = response['vendor']['name'];
for (var item in response['line_items']) {
String description = item['description'];
String quantity = item['quantity'].toString();
String totalCost = item['total'].toString();
List<Widget> itemInfo = [
Text(description),
Text(quantity),
Text(totalCost)
];
itemList.add(itemInfo);
}
List<dynamic> processedDetails = [
Text(totalPayment),
Text(currencyCode),
Text(vendorName),
itemList
];
return processedDetails;
},
).catchError((error) {
return Text('Error');
});
}
}
Apparently the data are properly fetched, but issues occur when trying to retrieve the data and display it.
class ReceiptDetailsView extends StatefulWidget {
const ReceiptDetailsView({Key? key}) : super(key: key);
@override
State<ReceiptDetailsView> createState() => _ReceiptDetailsViewState();
}
class _ReceiptDetailsViewState extends State<ReceiptDetailsView> {
Future<dynamic> loadProcessedReceipt() async {
ReceiptProcessor rp = ReceiptProcessor();
return await rp.processReceipt(showImage!);
}
late Future<dynamic> processedReceipt;
@override
void initState() {
super.initState();
processedReceipt = loadProcessedReceipt();
}
@override
Widget build(BuildContext context) {
return Container(
padding: EdgeInsets.all(10.0),
child: FutureBuilder<dynamic>(
future: processedReceipt,
builder: (context, snapshot) {
switch (snapshot.connectionState) {
case ConnectionState.waiting:
return CircularProgressIndicator();
case ConnectionState.done:
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else if (snapshot.data != null) {
return Text('Success');
}
}
return Text('Error');
},
),
);
}
}
I used a FutureBuilder
here, but continuously an empty snapshot containing a null data is returned; thus, 'Error'
is displayed on the view.
Any suggestions would be appreciated. A 'Success'
Text should appear when the snapshot data is properly retrieved.
CodePudding user response:
I think your function does indeed not return anything. Mostly, because your use of the then
function. Since you return inside your then
callback, the value is not returned globally but instead just for this function.
There's two options, you could either return the value that you resolve in the then
callback like this:
return await client.processDocument(..).then(...);
Or don't use then
at all, and instead keep relying on await
:
Map<String, dynamic> response = await client.processDocument(...);
...
return processedDetails;
I would recommend the latter case, where the single return simply returns from the function itself, and you don't include some code in a nested callback function.