Creating a PDF with table having dynamic rows in Flutter - flutter

I want to make a dynamic table with list contents. I am not able to map the array list with the List type of table data. I am not getting table in PDF and instead it's showing me an error.
This is my PDF code:
goTocreatePdf(context,AllTranList) async {
final Document pdf = Document();
pdf.addPage(MultiPage(
pageFormat:
PdfPageFormat.letter.copyWith(marginBottom: 1.5 * PdfPageFormat.cm),
crossAxisAlignment: CrossAxisAlignment.start,
header: (Context context) {
if (context.pageNumber == 1) {
return null;
}
return Container(
alignment: Alignment.centerRight,
margin: const EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm),
padding: const EdgeInsets.only(bottom: 3.0 * PdfPageFormat.mm),
decoration: const BoxDecoration(
border:
BoxBorder(bottom: true, width: 0.5, color: PdfColors.grey)),
child: Text('Report',
style: Theme.of(context)
.defaultTextStyle
.copyWith(color: PdfColors.grey)));
},
footer: (Context context) {
return Container(
alignment: Alignment.centerRight,
margin: const EdgeInsets.only(top: 1.0 * PdfPageFormat.cm),
child: Text('Page ${context.pageNumber} of ${context.pagesCount}',
style: Theme.of(context)
.defaultTextStyle
.copyWith(color: PdfColors.grey)));
},
build: (Context context) => <Widget>[
Header(
level: 0,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: <Widget>[
Text('TRANSACTION LIST', textScaleFactor: 2),
PdfLogo()
])),
Header(level: 1, text: 'What is Lorem Ipsum?'),
Table.fromTextArray(context: context, data: <List<String>>[
<String>[ 'TRANSACTION_AMOUNT No', 'CUSTREF_ID',
'REMARKS','PAYEE_VIR_ID','PAYER_VIR_ID'],
...AllTranList.map(
(item) => [item.TRANSACTION_AMOUNT,
item.CUSTREF_ID,item.REMARKS,item.PAYEE_VIR_ID,item.PAYER_VIR_ID])
]),
//save PDF
final String dir = (await getApplicationDocumentsDirectory()).path;
final String path = '$dir/report.pdf';
Dio dio = new Dio();
final File file = File(path);
await file.writeAsBytes(pdf.save());
material.Navigator.of(context).push(
material.MaterialPageRoute(
builder: (_) => PdfViewerPage(path: path),
),
);
}
Also I am not able to save PDF in the external storage.
This is the AllTransitList that I am mapping:
[{TRANSACTION_AMOUNT: 1.00,
CUSTREF_ID: 001819655570,
CREATED_ON: 2020-01-18T19:55:40.412Z,
REMARKS: SUCCESS,
RESPONSE: SUCCESS,
PAYEE_VIR_ID: navyabj#fbl,
PAYER_VIR_ID: abinthomas0073#oksbi},
{TRANSACTION_AMOUNT: 1.00,
CUSTREF_ID: 002218989414,
CREATED_ON: 2020-01-22T18:12:13.500Z,
REMARKS: SUCCESS,
RESPONSE: SUCCESS,
PAYEE_VIR_ID: navyabj#fbl,
PAYER_VIR_ID: abinthomas0073#oksbi},
{TRANSACTION_AMOUNT: 30.00,
CUSTREF_ID: 002218162602,
CREATED_ON: 2020-01-22T18:13:12.835Z,
REMARKS: SUCCESS,
RESPONSE: SUCCESS,
PAYEE_VIR_ID: navyabj#fbl,
PAYER_VIR_ID: aju#federal},
{TRANSACTION_AMOUNT: 36.00,
CUSTREF_ID: 002219179966,
CREATED_ON: 2020-01-22T19:23:21.377Z,
REMARKS: SUCCESS,
RESPONSE: SUCCESS,
PAYEE_VIR_ID: navyabj#fbl,
PAYER_VIR_ID: aju#federal}]

see this library.
you can create pdf with this library :
https://pub.dev/packages/pdf
i hope it's useful

Related

Flutter adding multiple network images on a pdf

I'm trying to find how could i can load network image in my Pdf. I have a list of details including an image urls. and i want to create the same list in a pdf with multiple pages.
So, i used pdf plugin to create the pages. All the details where loaded except the images. since the images should be downloaded from the server. The pdf pages are created with special widget elements (as like the flutter elements, but call with a prefix) and there is no FutureBuilder to manage the await functions.
Could anybody please help. I really stuck on this.
generatePdf(List<BhaiModel> bhaiList) async {
itemCount = 0;
List<BhaiModel> pageItems = [];
for (int i = 0; i < bhaiList.length; i++) {
if ((i + 1) % 5 == 0) {
pageItems.add(bhaiList[i]);
createPage(pageItems);
pageItems = [];
} else {
pageItems.add(bhaiList[i]);
if (i + 1 == bhaiList.length) {
createPage(pageItems);
}
}
}
final output = await getApplicationDocumentsDirectory();
final file = File("${output.path}/sample.pdf");
await file
.writeAsBytes(await pdf.save())
.then((value) => print("pdf saved"));
OpenFile.open("${output.path}/sample.pdf");
print(output.path);
}
createPage(List<BhaiModel> pageItems) async {
pdf.addPage(pw.Page(
pageFormat: PdfPageFormat.a4,
margin: const pw.EdgeInsets.all(30),
build: (pw.Context context) => pw.Column(
mainAxisAlignment: pageItems.length == 5
? pw.MainAxisAlignment.spaceEvenly
: pw.MainAxisAlignment.start,
children: pageItems.map((e) => customBhaiPdfItem(e)).toList())));
}
pw.Row customBhaiPdfItem(BhaiModel bhai) {
itemCount++;
final netImage = await networkImage(bhai.photo_url);
//THIS MAKE THE FUNCTION ASYNC
return pw.Row(children: [
pw.Container(
width: 530,
padding: const pw.EdgeInsets.all(8),
decoration: pw.BoxDecoration(border: pw.Border.all()),
child: pw.Row(mainAxisSize: pw.MainAxisSize.min, children: [
pw.Container(
color: const PdfColor(0.5, 0.5, 0.5),
width: 120,
height: 120,
child: pw.Image(netImage)),
pw.SizedBox(width: 20),
pw.Flexible(
child: pw.Container(
child: pw.Column(
mainAxisSize: pw.MainAxisSize.min,
crossAxisAlignment: pw.CrossAxisAlignment.stretch,
children: [
CustomRowText("No.", "$itemCount"),
CustomRowText("Name", "${bhai.first_name} ${bhai.last_name}"),
CustomRowText("Adhaar No.", bhai.adhaar_no),
CustomRowText("Mobile No.", bhai.mobile_no),
CustomRowText("Checkout At.",
bhai.last_checkout.replaceFirst('T', ' ').split('.')[0]),
CustomRowText("Address", bhai.address),
CustomRowText("City", bhai.city),
CustomRowText("State", bhai.state),
],
),
),
),
]),
),
]);
}
pw.Row CustomRowText(String label, String data) {
return pw.Row(children: [
pw.Expanded(
flex: 2,
child: pw.Text(label,
style: pw.TextStyle(fontWeight: pw.FontWeight.bold))),
pw.Expanded(flex: 7, child: pw.Text(data))
]);
}

How to make my own Loading Screen Indicator in flutter?

So far, I have made a loading animation that includes Container, Column, Text, and Image(gif). And this code is working fine in a new project but when I try to implement this code into my ongoing project, it is not working!
It does not throw any error but the loading screen is blank.
Like data from API loads without loading animation.
So, what I am doing wrong in this, or how to implement loader correctly?
Loader's code:
return Scaffold(
body: Container(
height: 130,
width: 135,
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.circular(17),
border: Border.all(color: Colors.blue)),
child: Column(
mainAxisAlignment: MainAxisAlignment.end,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
const Text(
"Loading...",
style: TextStyle(
fontSize: 13,
letterSpacing: 2.1,
color: Colors.blue,
),
),
Padding(
padding: const EdgeInsets.all(3.0),
child: Image.network(
"https://cdn.dribbble.com/users/42716/screenshots/3913441/media/4ef7d67070fee7ab75948280f51d369f.gif",
height: 100,
),
),
],
),
),
);
Here I am implementing code:
Future<List<VeReportModel>>? _vReport() async {
debugPrint("Do not exploit this code $fDate &&&&&&&& Thank you");
try {
if (await NetworkUtils.isNetworkAvailable()) {
//UIUtils.showProcessIndicator(); //TODO This is old Indicator I want a new one here
Loader();
ApiResponse? apiResponse = await RestApiClient(session: session)
.vReport(fDate, tDate, spedLimit, stLimit, vId!);
UIUtils.hideProcessIndicator(); //TODO Old Indicator disposed
Common.printWrapped('Map: _vEvent(): apiResponse=$apiResponse');
if (apiResponse!.successful && apiResponse.code == apiSuccessCode) {
if (apiResponse.data != null) {
List mapMessages = apiResponse.result;
debugPrint("mapMessage $mapMessages");
return mapMessages
.map((v) => VeReportModel.fromJson(v))
.toList();
}
}
} else {
UIUtils.hideProcessIndicator();
UIUtils.displayInternetError(context);
}
} catch (e,stack) {
UIUtils.hideProcessIndicator();
UIUtils.catchErrorMsg(context);
debugPrint('Error While acknowledging v report : $e');
GeneralException.handleError(e, stack: stack, module: moduleVeReport);
debugPrint('VeReport: Error while getting v list: $e');
}
return [];
}

Unable to display html file from local storage in webview

I have a Flutter project in which I am:
Downloading the zip file (full of html files)
Extracting the html files to a new directory (ebooks/02)
Saving the local file urls in a List
Displaying the urls in Webview & iterate through List for back & forth.
However, in the web view all I get is "Unable to load asset..."
Though any standard http url works fine in webview.
I tried from these two answers but no result: Answer1 & Answer2
The exception I get is :
E/flutter (10963): [ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: Unable to load asset: /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/04/00.html
I need to understand how to make the local html at the given path display in webview.
Any help would be appreciated.
Edit:
The webview code (currently trying to display only 1st url in list):
class _BookReaderState extends State<BookReader> {
List<String> urls = UserData.ebook;
WebViewController web;
final _key = UniqueKey();
String _url;
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
title: Text(
"Book Title Here",
style: GoogleFonts.roboto(
fontWeight: FontWeight.w900,
fontSize: 25.0,
color: Colors.white),
textAlign: TextAlign.center,
),
actions: [
Padding(
padding: EdgeInsets.only(right: 50),
child: IconButton(
icon: Image.asset('images/04_mobile-menu.png'),
color: Colors.red,
alignment: Alignment.centerLeft,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MyLibrary_Screen()));
}),
),
Padding(
padding: const EdgeInsets.only(left: 1.0),
child: IconButton(
icon: Image.asset('images/05_mobile-close.png'),
color: Colors.red,
alignment: Alignment.centerRight,
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => MyLibrary_Screen()));
}),
),
],
),
body: Column(
children: [
Padding(
padding: EdgeInsets.symmetric(horizontal: 10, vertical: 10),
child: Container(
width: 700,
height: 490,
child: FutureBuilder<String>(
future: _loadHtmlFromAssets(0),
builder: (context, snapshot) {
if (snapshot.hasData) {
return WebView(
initialUrl: new Uri.dataFromString(snapshot.data,
mimeType: 'text/html')
.toString(),
javascriptMode: JavascriptMode.unrestricted,
);
} else if (snapshot.hasError) {
return Text("${snapshot.error}");
}
return CircularProgressIndicator();
})),
),
Padding(
padding: EdgeInsets.only(top: 85),
child: Container(
height: 70,
color: Colors.blue,
child: RowSuper(
innerDistance: 50,
children: [
InkWell(
child: Image.asset(
"images/05_mobile-arrow-left.png",
alignment: Alignment.bottomLeft,
height: 170,
width: 90,
),
onTap: () => pageIncDec(1),
),
Text('Page ${urls.indexOf(_url) + 1} of ${urls.length}',
style: GoogleFonts.roboto(
fontWeight: FontWeight.w900,
fontSize: 33.0,
color: Colors.white)),
InkWell(
child: Image.asset(
"images/05_mobile-arrow-right.png",
alignment: Alignment.bottomRight,
height: 270,
width: 90,
),
onTap: () => pageIncDec(2),
),
],
),
),
),
],
));
}
pageIncDec(int i) async {
int n;
if (i == 1) {
setState(() {
urls.indexOf(_url) > 0 ? n = urls.indexOf(_url) - 1 : n = 0;
});
} else {
setState(() {
urls.indexOf(_url) < urls.length
? n = urls.indexOf(_url) + 1
: n = urls.length - 1;
});
}
_url = await _loadHtmlFromAssets(n);
web.loadUrl(_url);
print(_url);
}
Future<String> _loadHtmlFromAssets(int n) async {
String fileText = await rootBundle.loadString(urls[n]);
print(fileText);
String r = (Uri.dataFromString(fileText,
mimeType: 'text/html', encoding: Encoding.getByName('utf-8'))
.toString());
print(r);
return r;
}
Code to add files :
Directory dir =
Directory('${_appDocDir.path}/$folderName/${item.key_name}');
List<FileSystemEntity> listOfAllFolderAndFiles =
await dir.list(recursive: false).toList();
if (UserData.ebook != null) UserData.ebook.clear();
listOfAllFolderAndFiles.forEach((element) {
if (element.toString().contains("html")) {
String url = element.toString().replaceAll("File: ", "");
url = url.replaceAll("'", "");
UserData.ebook.add(url.toString());
}
UserData.eBookTitle = item.title;
});
print(UserData.ebook);
And result of printing UserData.ebook :
I/flutter ( 3465): [/data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/00.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/01.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/02.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/03.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/04.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/05.html, /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/06.html]
Checking:
//Checking if file exists
print("File ${UserData.ebook[0]} exists ? " +
File(UserData.ebook[0]).existsSync().toString());
Result:
I/flutter ( 3465): File /data/user/0/com.pts.school_ebook_reader_app_prag/app_flutter/ebooks/02/00.html exists ? true
Finally after trying all possible plugins realized that Flutter webview as of now cannot display local html files that are heavy on css & javascript side.
The same webview can only display external urls or basic html files(minus css & js).
I switched over to native android for this.
I think you should load html as normal file, not like asset, because it's not located in Assets directory and convert it to base64:
Future<String> _loadHtmlFromAssets(int n) async {
final file = File(urls[n]);
String fileText = await file.readAsString();
final base64 = base64Encode(utf8.encode(fileText));
return "data:text/html;base64,$base64";
}
Then show it like:
return WebView(
initialUrl: snapshot.data.toString(),
javascriptMode: JavascriptMode.unrestricted,
);
I know this may be a little late, but it's possible to add an HTML view with complex js and css, it can be done in two methods. The first and really bad looking way is to put all in one file, it will be visible both in iOS and Android and to load it via the WebView, the other method (I'm using this one to load an Angular local web component in an app) is to use the plugin webview_flutter_plus which is an extension of the normal WebView in flutter. This plugin requires to add in the pubspec.yaml all the files needed in the WebComponent, so you can add multiple complex css files and js files.
The tutorial in the plugin is pretty complete.
The only problem I'm facing is with iOS, which doesn't find the files, but that should be caused by a native problem, iOS try to load the files runtime and those are in a different location, so you need to find the correct path and replace it runtime in the html file (that was the solution I've implemented in a native project in swift).
Hope this helped for future projects.

Flutter: why I'm getting only 3 results in api call using chopper?

when call the api i get only 3 results when I use chopper but when use normal http package than I get more result
my chopper service file and I have generated the *.chopper.dart file
import 'package:chopper/chopper.dart';
part 'chopper_api_service.chopper.dart';
#ChopperApi(baseUrl: 'https://newsapi.org/v2')
abstract class ChopperApiService extends ChopperService {
#Get(path: '/top-headlines')
Future<Response> getNews({
#Query('apiKey') String apiKey = 'secret',
#Query('category') String category = 'health',
#Query('country') String country = 'in'
});
static ChopperApiService create() {
final client = ChopperClient(
baseUrl: 'https://newsapi.org/v2',
services: [
_$ChopperApiService(),
],
converter: JsonConverter(),
);
return _$ChopperApiService(client);
}
}
In UI where I'm trying to the result,
import 'dart:convert';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:chopper/chopper.dart';
import 'package:flutter/material.dart';
import 'package:lottie/lottie.dart';
import '../../../constants/url.dart';
import '../models/chopper_api_service.dart';
class ChopperNewsCard extends StatefulWidget {
#override
_ChopperNewsCardState createState() => _ChopperNewsCardState();
}
class _ChopperNewsCardState extends State<ChopperNewsCard> {
ChopperApiService chopperApiService;
Future<Response> apiResponse;
#override
void initState() {
super.initState();
chopperApiService = ChopperApiService.create();
apiResponse = chopperApiService.getNews();
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return FutureBuilder<Response>(
future: apiResponse,
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
final news = jsonDecode(snapshot.data.bodyString);
print(news); //<-----printing it
return Container(
height: height * 0.37,
width: double.infinity,
child: ListView.builder(
itemCount: news.length,
physics: AlwaysScrollableScrollPhysics(),
scrollDirection: Axis.horizontal,
shrinkWrap: true,
itemBuilder: (context, index) {
return Container(
width: width * 0.70,
padding: EdgeInsets.only(right: width * 0.05),
child: Card(
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15),
),
elevation: 3,
child: Column(
children: [
ClipRRect(
borderRadius: BorderRadius.circular(15),
child: CachedNetworkImage(
imageUrl:
news['articles'][index]['urlToImage'] == null
? Url.noImage
: news['articles'][index]['urlToImage'],//<--- this
fit: BoxFit.cover,
width: double.infinity,
height: height * 0.2,
placeholder: (context, url) =>
Center(child: CircularProgressIndicator()),
errorWidget: (context, url, error) =>
Icon(Icons.error_outline_sharp),
),
),
Padding(
padding: EdgeInsets.only(
right: width * 0.03,
left: width * 0.03,
top: width * 0.03),
child: Text(
news['articles'][index]['title'],
maxLines: 4,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize: 16,
),
),
),
],
),
),
);
},
),
);
} else {
return Center(
child: Lottie.asset('assets/lottie/loading.json',
height: width * 0.5, width: width * 0.5),);
}
},
);
}
}
when print it also shows only 3 results but in the totalResults category it says 70,
{status: ok, totalResults: 70, articles: [{source: {id: null, name: Deseret News}, author: Herb Scribner, title: Why COVID symptoms still appears if you take zinc, vitamin c - Deseret News, description: Do vitamin C and zinc help fight off COVID-19? A new sutdy says that’s not the case., url: https://www.deseret.com/u-s-world/2021/2/18/22288048/covid-19-symptoms-zinc-vitamin-c, urlToImage: https://cdn.vox-cdn.com/thumbor/6Vl9l5InMVmP9-Oqu_WVvgcThYw=/0x147:2510x1461/fit-in/1200x630/cdn.vox-cdn.com/uploads/chorus_asset/file/22294628/AP20357531088811.jpg, publishedAt: 2021-02-19T04:00:00Z, content: A new study suggests that vitamin C and zinc dont help fight off COVID-19, even when theyre taken at high doses.
Whats going on?
The study published in mid-February in JAMA Network Open found that … [+1522 chars]}, {source: {id: google-news, name: Google News}, author: null, title: Sask. health-care worker dies after positive COVID-19 test - CBC News: The National, description: null, url:<…>
now do I need add something in the query parameters to get more results
By default, newsapi shows 20 results per page. You can control that by using pageSize and page params.
Top headlines documentation
print(news); have limited output and will not print the entire map.
Use the following print statement to check how many object do you have in the articles list: print('Articles count: ${news['articles'].length}');
You need to change this code in order to get the item count:
child: ListView.builder(
itemCount: news['articles'].length,

An issue when getting data from an API in Flutter with Dart

I'm having an issue with my app, I'm creating a flutter app to track cryptocurrency prices.
The issue is that I get the data properly from the API, then I print it into the counsel but when I try to display it inside the app, it displays null.
Here is the code I use to get the data from the API
class CurrencyData { var decodedData;
Future getCoinsData() async {
http.Response response =
await http.get(coinUrl);
if (response.statusCode == 200) {
decodedData = jsonDecode(response.body);
} else {
print(response.statusCode);
throw 'Problem with the request, try again later!';
}
return decodedData;
}
}
Here is the code where I call the data to display it.
class _DashboardPageState extends State<DashboardPage> {
CurrencyData currencyData = CurrencyData();
var btcPrice;
var btcChange24h;
void cryptoCurrencyData() async {
var data = await currencyData.getCoinsData();
print(btcPrice = data['data'][0]['priceUsd']);
print(btcChange24h = data['data'][0]['changePercent24Hr']);
}
#override
void initState() {
super.initState();
cryptoCurrencyData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: SafeArea(
child: ListView(
children: <Widget>[
Column(
children: <Widget>[
// the top bar
Container(
padding: EdgeInsets.all(40),
constraints: BoxConstraints.expand(height: 175),
decoration: BoxDecoration(
color: Colors.lightBlue,
boxShadow: [
BoxShadow(
color: Colors.black26,
blurRadius: 20.0,
// has the effect of softening the shadow
spreadRadius:
5.0, // has the effect of extending the shadow
),
],
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(30),
bottomRight: Radius.circular(30),
),
),
child: Container(
padding: EdgeInsets.only(top: 25),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Center(
child: Text(
'Crypto Tracker',
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 30.0,
fontWeight: FontWeight.bold,
),
),
)
],
),
),
),
// the body part
CurrencyWidget(
currencyIconUrl: 'assets/images/btc.png',
currencyName: 'Bitcoin',
currencyShortName: 'BTC',
currencyPrice: btcPrice,
currencyChange24h: btcChange24h,
),
I get the data printed into the console but I also get Null displayed in the emulator as shown in the below screenshot.
The image where null is displayed
A screenshot of the data being printed in the console
Any idea what the issue may be?
The problem is that getting api data is async task so it takes time, while build method build screen in that time, so it is printing null.
1) You can call setState at the end of function which change null to actual data when it gets from API.
void cryptoCurrencyData() async {
var data = await currencyData.getCoinsData();
btcPrice = data['data'][0]['priceUsd']; // assign
btcChange24h = data['data'][0]['changePercent24Hr']; // aasign
print(btcPrice = data['data'][0]['priceUsd']);
print(btcChange24h = data['data'][0]['changePercent24Hr']);
setState(() {}); // added
}
2) However, FutureBuilder is more better option where you can show loading indicator or something which shows data is loading and display when arrives.
Note: in this way you don't need cryptoCurrencyData method and also you don't need to store value in different variable.
FutureBuilder(
future: currencyData.getCoinsData(),
builder: (_, sanpshot) {
if (!sanpshot.hasData) {
return CircularProgressIndicator();
}
return CurrencyWidget(
currencyIconUrl: 'assets/images/btc.png',
currencyName: 'Bitcoin',
currencyShortName: 'BTC',
currencyPrice: data['data'][0]['priceUsd'],
currencyChange24h: data['data'][0]['changePercent24Hr'],
);
},
),