I'm making an app that can display and print images in a pdf package.
Create a pdf with the pdf package and print it with the printing package.
To print, Uint8List data must be sent to save() function of pdf. However, the loading screen stops because the size of my pdf is not small.
I think you should use compute() to solve this problem.
draw pdf
Future<pdfWidget.Document> _drawEnsembleScorePrint(BuildContext context) async {
DrawScore drawScore = DrawScore();
pdfWidget.Document scorePdf = pdfWidget.Document(version: PdfVersion.pdf_1_5, compress: true);
print('drawEnsemble print start');
for(int nCurPage=0; nCurPage<scorePngList.length; nCurPage++) {
File imageFile = File(scorePngList[nCurPage].path);
final image = pdfWidget.MemoryImage(imageFile.readAsBytesSync());
final watermarkingImage = await imageFromAssetBundle('assets/images/ELF_CI.png');
final underElfimage = await imageFromAssetBundle('assets/images/ELF_CI2.png');
scorePdf.addPage(
pdfWidget.Page(
pageFormat: PdfPageFormat.a4,
///2480 * 3508
build: (pdfWidget.Context pContext) {
return pdfWidget.Stack(
children: [
drawScore.drawWatermarking(context, watermarkingImage, 1.0),
pdfWidget.Container(
width: 2480,
height: 3508,
child: pdfWidget.Image(image, fit: pdfWidget.BoxFit.fill),
),
pdfWidget.Positioned(
top: 100,
left: 2190,
child: pdfWidget.Container(
width: 201,
height: 100,
color: PdfColor.fromInt(0xFFFFFFFF),
),
),
// pdfWidget.Positioned(
// top: 100,
// left: 2190,
// child: pdfWidget.Container(
// width: 201,
// height: 100,
// alignment: pdfWidget.Alignment.centerRight,
// child: pdfWidget.Text(
// httpCommunicate.nDispNumber.toString(),
// style: pdfWidget.TextStyle(
// font: context.read<CustomFontProvider>().SOURCE_HANSANS_MEDIUM,
// fontSize: 48,
// ),
// ),
// ),
// ),
// drawScore.drawWatermarking(context, watermarkingImage, httpCommunicate),
pdfWidget.Positioned(
top: 3424,
left: 24,
child: pdfWidget.Container(
width: 2432,
height: 83,
alignment: pdfWidget.Alignment.topCenter,
child: pdfWidget.Text(
'${nCurPage + 1} / ${scorePngList.length}',
style: pdfWidget.TextStyle(
// font: context.read<CustomFontProvider>().SOURCE_HANSANS_NORMAL,
fontSize: 36,
),
),
),
),
pdfWidget.Positioned(
top: 3424,
left: 24,
child: pdfWidget.Container(
width: 2432,
height: 83,
alignment: pdfWidget.Alignment.topLeft,
child: pdfWidget.Text(
strUserID,
style: pdfWidget.TextStyle(
// font: context.read<CustomFontProvider>().SOURCE_HANSANS_NORMAL,
fontSize: 36,
color: PdfColor.fromInt(0xFF000000)
),
),
),
),
pdfWidget.Positioned(
top: 3424,
left: 24,
child: pdfWidget.Container(
width: 2432,
height: 83,
alignment: pdfWidget.Alignment.topRight,
child: pdfWidget.Image(underElfimage, width: 190, height: 72),
),
),
],
);
}
),
);
}
return scorePdf;
}
call draw pdf func
_realDrawEnsembleScore(BuildContext context, HttpCommunicate httpCommunicate) async {
DrawScore drawScore = DrawScore();
pdfWidget.Document scorePdf = pdfWidget.Document(version: PdfVersion.pdf_1_5, compress: true);
if(httpCommunicate.bIsPreViewScore == true){
// scorePdf = await compute(_drawEnsemblePreview, 0);
scorePdf = await _drawEnsemblePreview(context);
}
else{
// scorePdf = await compute(_drawEnsembleScorePrint, 0);
scorePdf = await _drawEnsembleScorePrint(context);
}
return scorePdf;
}
call realDrawEnsembleScore func
Future<pdfWidget.Document> addScorePDF(BuildContext context, HttpCommunicate httpCommunicate, bool bIsTiff)async{
DrawScore drawScore = DrawScore();
pdfWidget.Document scorePdf = pdfWidget.Document(version: PdfVersion.pdf_1_5, compress: true);
final cutpaperImage = await imageFromAssetBundle('assets/images/CutPaper.png');
final watermarkingImage = await imageFromAssetBundle('assets/images/ELF_CI.png');
final underElfimage = await imageFromAssetBundle('assets/images/ELF_CI2.png');
if(!bIsTiff){
scorePdf = await _realDrawScore(context, httpCommunicate);
}
else{
scorePdf = await _realDrawEnsembleScore(context, httpCommunicate);
}
return scorePdf;
}
compute code
pdfWidget.Document? scorePdf;
scorePdf = await context.read<PDFProvider>().addScorePDF(context, httpCommunicate, true);
Uint8List uintData = await compute(_testfunction, 0);
////
Future<Uint8List> _testfunction(int x) async {
pdfWidget.Document scorePdf = pdfWidget.Document(version: PdfVersion.pdf_1_5, compress: true);
print("_test function start");
Uint8List data;
data = g_scorePdf!.save();
return data;
}
But _testfunction is never called.
g_scorePdf is not null, but Save() throws an error.
You need to make sure the function you are calling is a top-level function. I would also avoid sending BuildContext as an argument to the isolate.
Future<Uint8List> _testfunction(int x) async {
pdfWidget.Document scorePdf = pdfWidget.Document(version: PdfVersion.pdf_1_5, compress: true);
for (int i = 0; i < 3; i++) {
scorePdf.addPage(
pdfWidget.Page(build: (pdfWidget.Context context) {
return pdfWidget.Stack(
children: [
pdfWidget.Positioned(
top: 1000,
left: 1000,
child: pdfWidget.Text('top 1000, left 1000'),
),
],
);
}),
);
}
debugPrint('Done');
return await scorePdf.save();
}
class MyStatefulWidget extends StatefulWidget {
const MyStatefulWidget({super.key});
#override
State<MyStatefulWidget> createState() => _MyStatefulWidgetState();
}
class _MyStatefulWidgetState extends State<MyStatefulWidget> {
Future<Uint8List> addPdfTest(BuildContext context) async {
Uint8List data = await compute(_testfunction, 1);
return data;
}
#override
Widget build(BuildContext context) {
return Scaffold(
extendBody: true,
body: Center(
child: GestureDetector(
onTap: () async {
await addPdfTest(context);
},
child: Container(color: Colors.red),
),
),
);
}
}
You can read more about using compute here and here.
pdf package link for anyone else that's interested: https://pub.dev/packages/pdf
Related
I am facing an issue when I pull to refresh, I need that after pull to refresh gesture new articles available will be visible in the news page, but this doesn't happen.
I created the cache system, but once I pull to refresh new data, the news page doesn't load new articles.
What can I do to solve this issue?
News page
class _NewsPageState extends State<NewsPage> {
/// News service
final ApiNewsPage categoryNews = ApiNewsPage();
late bool isLoading;
/// Start Refresh indicator upload new articles function
final NewArticlesPage updateArticles = NewArticlesPage();
ScrollController scrollController = ScrollController();
//final List<ArticleModel> _posts = [];
//
#override
void initState() {
super.initState();
refreshArticles();
}
/// Call this when the user pull down the screen
Future<void> refreshArticles() async {
Future.delayed(const Duration(seconds: 2), () {
setState(() {
updateArticles.updateArticles();
print("Uploading new articles");
//_posts.add();
});
return updateArticles.updateArticles();
});
}
/// End Refresh indicator upload new articles function
///
///
#override
Widget build(BuildContext context) {
return RefreshIndicator(
displacement: 0,
color: assofacileMainColor,
backgroundColor: Colors.white,
onRefresh: refreshArticles,
child: Container(
child: FutureBuilder<List?>(
future: categoryNews.getNewsArticles(),
builder: (context, snapshot) { // AsyncSnapshot
if (snapshot.hasData) {
if (snapshot.data?.length == 0) {
return const NoArticle();
}
return ListView.builder(
controller: scrollController,
itemCount: snapshot.data?.length++,
physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (context, i) {
return Card(
margin: const EdgeInsets.all(8),
elevation: 5,
shadowColor: Colors.black26,
color: Colors.white,
child: InkWell(
child: ClipRRect(
borderRadius: BorderRadius.circular(10),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
SizedBox(
height: 190,
width: double.infinity,
child:
Image(
image: AdvancedNetworkImage(
snapshot.data![i]["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["medium"]["source_url"],
useDiskCache: true,
cacheRule: const CacheRule(maxAge: Duration(days: 1)),
),
fit: BoxFit.cover,
),
// CachedNetworkImage(
// cacheManager: CacheManager(
// Config(snapshot.data![i]["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["medium"]["source_url"],
// stalePeriod: const Duration(days: 1),
// )
// ),
// //cacheManager: DioCacheManager.instance,
// imageUrl: snapshot.data![i]["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["medium"]["source_url"],
// // checkIfUrlContainsPrefixHttps(
// // _post != null
// // ? _post[0].urlImageSource
// // : "https:" + snapshot.data![i]["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["thumbnail"]["source_url"],
// // ),
// //snapshot.data![i]["_embedded"]["wp:featuredmedia"][0]["link"],
// //"https:" + snapshot.data![i]["_embedded"]['wp:featuredmedia'][0]["media_details"]["sizes"]["medium"]["source_url"],
// fit: BoxFit.cover,
// placeholder: (context, url) => Image.asset("assets/gif/shimmer.gif",
// width: double.infinity,
// height: 190,
// fit: BoxFit.cover,
// ),
// errorWidget: (context, url, error) => Image.asset("assets/images/unloadedImage.png",
// width: 250, height: 250),
// ),
),
// Title article
Column(
children: [
Padding(
padding: const EdgeInsets.only(left:16, top: 16, bottom: 16),
child: Row(
children: [
Expanded(
child: Text(
snapshot.data![i]["title"]["rendered"]
.replaceAll("’", "'")
.replaceAll("<p>", "")
.replaceAll("</p>", ""),
style: const TextStyle(
fontSize: 18,
fontWeight: FontWeight.w600,
fontFamily: "Raleway",
),
overflow: TextOverflow.ellipsis,
maxLines: 2,
//softWrap: false,
),
),
],
),
)
],
),
],
),
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ArticlePage(data: snapshot.data?[i]),
),
);
},
),
);
},
);
} else if (snapshot.hasError) {
return const NoInternet();
} else {
/// Shimmer
return ShimmerEffect();
}
}
),
),
);
}
}
Fetch and create cache
class ApiNewsPage {
final String url = newsJsonLink;
Future<List?> getNewsArticles() async {
String nameDB = "articledata.json";
var dir = await getTemporaryDirectory();
File file = File(dir.path + "/" + nameDB);
if(file.existsSync()) {
print("Loading Articles from cache");
var jsonDB = file.readAsStringSync();
List response = json.decode(jsonDB);
return response;
} else {
var response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
//await File(nameDB).exists();
var jsonResponse = response.body;
List newArticles = json.decode(jsonResponse);
//File(nameDB).deleteSync(recursive: true);
/// save json in local file
file.writeAsStringSync(jsonResponse, flush: true, mode: FileMode.write);
print("Fetching new articles from internet");
return newArticles;
}
}
}
}
// Create new db
class NewArticlesPage {
final String url = newsJsonLink;
Future<List?> updateArticles() async {
try {
var response = await http.get(Uri.parse(url));
if (response.statusCode == 200) {
print("Fetching new articles from internet");
return jsonDecode(response.body);
} else {
return Future.error("Impossibile ricevere i dati, prova a controllare la connessione");
}// ignore: non_constant_identifier_names
} catch (SocketException) {
return Future.error("Impossibile caricare gli articoli");
}
}
}
hello guys!
i am using flutter story view package to implement story functionality in my app and i am using camera plugin to record video and upload, however the content type of the uploaded video is application/octet-stream when i receive it on my server and only when it is sent from ios. for android everything is fine and i get the content type as video/mp4.
can you guys please help me.
i have not done anything fancy i have just used the basic functionality of start recording and stop recording of the camra plugin.
// ignore_for_file: use_build_context_synchronously
List<CameraDescription>? cameras;
class CameraScreen extends StatefulWidget {
const CameraScreen({Key? key}) : super(key: key);
#override
State<CameraScreen> createState() => _CameraScreenState();
}
class _CameraScreenState extends State<CameraScreen> {
CameraController? _cameraController;
Future<void>? cameraValue;
bool flash = false;
bool iscamerafront = true;
static const _maxSeconds = 30;
ValueNotifier<bool> visible = ValueNotifier(false);
ValueNotifier<bool> isRecoring = ValueNotifier(false);
TimerProvider? _timerProvider;
#override
void initState() {
super.initState();
_timerProvider = Provider.of(context, listen: false);
_cameraController = CameraController(cameras![0], ResolutionPreset.veryHigh,
imageFormatGroup: ImageFormatGroup.bgra8888);
cameraValue = _cameraController?.initialize();
_cameraController?.prepareForVideoRecording();
lockCamera();
}
lockCamera() async {
await _cameraController!.lockCaptureOrientation();
}
#override
void dispose() {
super.dispose();
visible.dispose();
isRecoring.dispose();
_cameraController?.dispose();
}
#override
Widget build(BuildContext context) {
print("camera_screen");
final size = MediaQuery.of(context).size;
return Scaffold(
extendBodyBehindAppBar: true,
appBar: AppBar(
centerTitle: true,
title: ValueListenableBuilder<bool>(
valueListenable: visible,
builder: (context, value, child) {
return Visibility(
visible: value,
child: Container(
padding: const EdgeInsets.all(10),
width: 50,
height: 50,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.black.withOpacity(0.5)),
child: Center(
child: Consumer<TimerProvider>(
builder: (context, value, child) {
if (value.seconds == 0) {
if (_cameraController!.value.isRecordingVideo) {
stopRecording();
}
}
return Text(
value.seconds.toString(),
style: CustomStyles.fixAppBarTextStyle
.copyWith(color: Colors.white),
);
}),
),
));
}),
backgroundColor: Colors.transparent,
leadingWidth: 100,
leading: InkWell(
onTap: () {
Navigator.pop(context);
},
child: Center(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
"Cancel",
style: CustomStyles.fixMediumBodyTextStyle
.copyWith(color: Colors.white),
),
)),
),
),
body: SafeArea(
top: false,
child: Stack(
children: [
FutureBuilder(
future: cameraValue,
builder: (context, snapshot) {
_cameraController?.lockCaptureOrientation();
if (snapshot.connectionState == ConnectionState.done) {
return Transform.scale(
scale: size.aspectRatio *
_cameraController!.value.aspectRatio <
1
? 1 /
(size.aspectRatio *
_cameraController!.value.aspectRatio)
: size.aspectRatio *
_cameraController!.value.aspectRatio,
child: Center(child: CameraPreview(_cameraController!)),
);
} else {
return const Center(
child: CircularProgressIndicator.adaptive(),
);
}
}),
Positioned(
bottom: 0.0,
child: Container(
padding: const EdgeInsets.only(top: 5, bottom: 5),
width: Dimensions.screenWidth,
child: Column(
children: [
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.black.withOpacity(0.5)),
child: Center(
child: IconButton(
icon: Icon(
flash ? Icons.flash_on : Icons.flash_off,
color: Colors.white,
size: 28,
),
onPressed: () {
setState(() {
flash = !flash;
});
flash
? _cameraController!
.setFlashMode(FlashMode.torch)
: _cameraController!
.setFlashMode(FlashMode.off);
}),
),
),
ValueListenableBuilder<bool>(
valueListenable: isRecoring,
builder: (context, value, child) {
return GestureDetector(
onLongPress: () {
startRecording();
},
onLongPressUp: () {
stopRecording();
},
onTap: () {
if (value == false) {
takePhoto(context);
}
},
child: value == true
? const CircleAvatar(
radius: 50,
backgroundColor: Colors.white30,
child: CircleAvatar(
radius: 35,
backgroundColor: Colors.red,
),
)
: const CircleAvatar(
radius: 35,
backgroundColor: Colors.white30,
child: CircleAvatar(
radius: 25,
backgroundColor: Colors.white,
),
));
}),
Container(
padding: const EdgeInsets.all(4),
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.black.withOpacity(0.5)),
child: IconButton(
icon: const Icon(
Icons.flip_camera_ios,
color: Colors.white,
size: 28,
),
onPressed: () async {
setState(() {
iscamerafront = !iscamerafront;
});
int cameraPos = iscamerafront ? 0 : 1;
_cameraController = CameraController(
cameras![cameraPos], ResolutionPreset.high);
cameraValue = _cameraController?.initialize();
}),
),
],
),
addVerticalSpace(6),
const Text(
"Hold for Video, tap for photo",
style: TextStyle(
color: Colors.white,
),
textAlign: TextAlign.center,
),
addVerticalSpace(5),
],
),
),
),
],
),
),
);
}
void startRecording() async {
visible.value = true;
_timerProvider?.startCountDown(_maxSeconds);
isRecoring.value = true;
await _cameraController?.startVideoRecording();
}
void stopRecording() async {
XFile videopath = await _cameraController!.stopVideoRecording();
_timerProvider?.stopTimer();
isRecoring.value = false;
Navigator.push(
context,
MaterialPageRoute(
builder: (builder) => CameraResult(
image: File(videopath.path),
isImage: false,
))).then((value) {
visible.value = false;
});
}
void takePhoto(BuildContext context) async {
XFile file = await _cameraController!.takePicture();
SystemSound.play(SystemSoundType.click);
final img.Image? capturedImage =
img.decodeImage(await File(file.path).readAsBytes());
final img.Image orientedImage = img.flipHorizontal(capturedImage!);
File finalImage =
await File(file.path).writeAsBytes(img.encodeJpg(orientedImage));
Navigator.push(
context,
CupertinoPageRoute(
builder: (builder) => CameraResult(
image: finalImage,
isImage: true,
))).then((value) {
visible.value = false;
});
}
}
the upload function is as bellow
{File? shouts,
File? thumbnail,
int? duration,
bool? isImage,
required String userId,
required OnUploadProgressCallback onUploadProgress}) async {
assert(shouts != null);
try {
var url = Constants.POSTSHOUTURL;
final httpClient = FileService.getHttpClient();
final request = await httpClient.postUrl(Uri.parse(url));
int byteCount = 0;
var multipart;
if (isImage == false) {
multipart = await http.MultipartFile.fromPath(
'story-media', shouts!.path,
contentType: MediaType("video", "mp4"));
} else {
multipart = await http.MultipartFile.fromPath(
'story-media',
shouts!.path,
);
}
var multipart2 =
await http.MultipartFile.fromPath('thumbnail', thumbnail!.path);
var requestMultipart = http.MultipartRequest('POST', Uri.parse(url));
requestMultipart.fields["userid"] = userId.toString();
requestMultipart.fields["duration"] = duration.toString();
requestMultipart.headers['Content-type'] = 'multipart/form-data';
requestMultipart.files.add(multipart);
requestMultipart.files.add(multipart2);
var msStream = requestMultipart.finalize();
var totalByteLength = requestMultipart.contentLength;
request.contentLength = totalByteLength;
request.headers.add(HttpHeaders.authorizationHeader,
"Bearer ${Hive.box<UserData>(Constants.userDb).get(Hive.box<UserData>(Constants.userDb).keyAt(0))!.token}");
request.headers.set(HttpHeaders.contentTypeHeader,
requestMultipart.headers[HttpHeaders.contentTypeHeader]!);
Stream<List<int>> streamUpload = msStream.transform(
StreamTransformer.fromHandlers(
handleData: (data, sink) {
sink.add(data);
byteCount += data.length;
if (onUploadProgress != null) {
onUploadProgress(byteCount, totalByteLength);
// CALL STATUS CALLBACK;
}
},
handleError: (error, stack, sink) {
throw error;
},
handleDone: (sink) {
sink.close();
// UPLOAD DONE;
},
),
);
await request.addStream(streamUpload);
final httpResponse = await request.close();
var statusCode = httpResponse.statusCode;
if (statusCode ~/ 100 == 2) {
onUploadProgress(0, 0);
return await FileService.readResponseAsString(httpResponse);
}
return "";
} on SocketException {
throw FetchDataException("No internet to upload Shout!");
}
}```
i have used necessary info.plist setting also
Faced a problem. I started to paginate the list so that 10 elements are displayed, when I reach the bottom of the list using controller.position.extentAfter < 30 I check how far we have gone down and if at the very bottom I change the value of isLoadMoreRunning and show CircularProgressIndicator. I will also add +10 elements to the limit variable for each call to display. I seem to have done everything right, but pagination does not work for me, it shows the first 10 elements, and then nothing passes, new elements are not loaded when I scrolled to the very bottom. What could be the problem?
home
late ScrollController controller;
bool isFirstLoadRunning = false;
bool isLoadMoreRunning = false;
bool hasNextStation = true;
int limit = 10;
void _firstLoadStations() async {
final StationCubit stationCubit = BlocProvider.of<StationCubit>(context);
setState(() {
isFirstLoadRunning = true;
});
try {
stationsList =
await stationCubit.getAllPublicChargingStations(limit: limit);
} catch (error) {
print(error);
}
setState(() {
isFirstLoadRunning = false;
});
}
void _loadMoreStations() async {
final StationCubit stationCubit = BlocProvider.of<StationCubit>(context);
if (hasNextStation == true &&
isFirstLoadRunning == false &&
controller.position.extentAfter < 30) {
setState(() {
isLoadMoreRunning = true;
});
limit += 10;
try {
var fetchedStations =
await stationCubit.getAllPublicChargingStations(limit: limit);
if (fetchedStations.isNotEmpty) {
setState(() {
stationsList.addAll(fetchedStations);
});
} else {
setState(() {
hasNextStation = false;
});
}
} catch (error) {
print(error);
}
setState(() {
isLoadMoreRunning = false;
});
}
// _foundAddressesInStationList = stationsList;
}
#override
void initState() {
_firstLoadStations();
controller = ScrollController()
..addListener(() {
_loadMoreStations();
});
_foundAddresses = _allAddresses;
_foundStation = _allStation;
super.initState();
}
#override
void dispose() {
controller.removeListener(() {
_loadMoreStations();
});
super.dispose();
}
#override
Widget build(BuildContext context) {
final Size size = MediaQuery.of(context).size;
final double paddingTop = MediaQuery.of(context).padding.top;
final StationCubit stationCubit = BlocProvider.of<StationCubit>(context);
return Container(
width: size.width,
height: size.height,
child: _child(size, paddingTop, stationCubit),
);
}
Widget _child(Size size, double paddingTop, StationCubit stationCubit) =>
BlocBuilder<StationCubit, StationState>(
builder: (context, state) => Padding(
padding: const EdgeInsets.symmetric(horizontal: 8),
child: Column(
children: [
const SizedBox(height: 17),
Expanded(
child: SingleChildScrollView(
child: Column(
children: [
_addresses(size, stationCubit),
],
),
),
),
],
),
),
);
Widget _addresses(Size size, StationCubit stationCubit) => ConstrainedBox(
constraints: BoxConstraints(
maxHeight: MediaQuery.of(context).size.height / 2,
),
child: SizedBox(
width: size.width,
child: ClipRRect(
borderRadius: BorderRadius.circular(24),
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 8.0, sigmaY: 8.0),
child: Container(
child: SingleChildScrollView(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
isFirstLoadRunning
? const CircularProgressIndicator(
color: Colors.white)
: const Text(
'Addresses',
style: constants.Styles.smallBookTextStyleWhite,
),
const SizedBox(height: 25),
ListViewSearch(
stationList: stationsList,
controller: controller,
),
const SizedBox(height: 20),
if (isLoadMoreRunning == true)
const Padding(
padding: EdgeInsets.only(top: 10, bottom: 40),
child: Center(
child: CircularProgressIndicator(),
),
),
if (hasNextStation == false)
Container(
padding: const EdgeInsets.only(top: 30, bottom: 40),
color: Colors.amber,
child: const Center(
child:
Text('You have fetched all of the content'),
),
),
],
),
)),
),
),
),
);
}
cubit
Future<List<PublicChargingStationModel>> getAllPublicChargingStations(
{required int limit}) async {
var result =
await StationRepository().getAllPublicChargingStations(limit: limit);
return result;
}
repository
Future<List<PublicChargingStationModel>> getAllPublicChargingStations(
{int? limit}) async {
try {
var apiKeyMap = await ApiKey.getCryptoApiKeyMap();
apiKeyMap!.addAll({'limit': limit.toString()});
final Uri url = Uri.parse(
'${ApiConfig.schema}://${ApiConfig.domain}/${ApiConfig.uriPrefix}/stations',
).replace(queryParameters: apiKeyMap);
final response = await http.get(url);
if (response.statusCode == 200) {
final data = jsonDecode(response.body)['data'] as List;
return data
.map((json) => PublicChargingStationModel.fromJson(json))
.toList();
}
return List<PublicChargingStationModel>.empty();
} catch (_) {
print(_);
return List<PublicChargingStationModel>.empty();
}
}
you need set SingleChildScrollView parameter controller: controller.
I am getting a blue splash Animation problem when I am trying to swift between in the list of an image of the PageView
but when I am using simple Image then its working fine But when I am trying to get an image from SQLite Database then I am getting the blue Splash refresh Problem in animation
Working Animation with asset Image => https://i.imgur.com/2XJDpRx.mp4
Any help would be deeply appreciated!
Below is the SQLite Database
import 'dart:io';
import 'package:scoped_model/models/person.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper with ChangeNotifier {
static DatabaseHelper _databaseHelper;
static Database _database;
DatabaseHelper._namedConstructor();
static String _dbFileName = "animationWork.db";
static int _dbVersion = 1;
static String _personTableName = "person";
factory DatabaseHelper() {
// Singleton Design Structure - For multiple use of a single Object
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper._namedConstructor();
return _databaseHelper;
} else {
return _databaseHelper;
}
}
Future<Database> _getDatabase() async {
// Singleton Design Structure - For multiple use of a single Object
if (_database == null) {
_database = await _initializeDatabase();
return _database;
} else {
return _database;
}
}
_initializeDatabase() async {
var databasePath = await getDatabasesPath();
var path = join(databasePath, _dbFileName);
bool exists = await databaseExists(path);
if (!exists) {
// exists == false
try {
print("Trying to create a new database cause it doesn\'t exist.");
await Directory(dirname(path)).create(recursive: true);
} catch (error) {
print('Database could not be created at path $path');
print("Error is : $error");
}
ByteData data = await rootBundle.load(join("assets", _dbFileName));
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
await File(path).writeAsBytes(bytes, flush: false);
} else {
print("Database exists.");
}
print(
"Opening database anyway, whether it was already there or has just been created.");
return await open database(path, version: _dbVersion, readOnly: false);
}
// GET "person" table from DB
// The method below returns the "person" table from the database.
// "person" table is a list of maps of Person objects
/*[
{"personID" : 1, "personDisplayName" : ""Meral", "personPhoneNumber" : "+905333654710", "personPhoto" : "AFH474JDFOWÊBB"},
{"personID" : 2, "personDisplayName" : ""Özge", "personPhoneNumber" : "+905325474445", "personPhoto" : "AFH474JDFOWÊBB"},
{"personID" : 3, "personDisplayName" : ""Semahat", "personPhoneNumber" : "+905325474445", "personPhoto" : "AFH474JDFOWÊBB"}
] */
Future<List<Map<String, dynamic>>> getPersonTable() async {
var db = await _getDatabase();
var result = db.query(_personTableName);
return result;
}
// CONVERT "person" table from DB to all Person list => List of Person objects
/*
The method below converts the "person" table - which consists of a list of maps of Person objects -
into a list of Person objects.
*/
Future<List<Person>> getAllPersonsList() async {
List<Map<String, dynamic>> listOfMapsOfPersonFromDatabase =
await getPersonTable();
var allPersonObjectsList = List<Person>();
var reversedList = List<Person>();
for (Map personMap in listOfMapsOfPersonFromDatabase) {
allPersonObjectsList.add(Person.fromMap(personMap));
}
if (allPersonObjectsList.length > 1) {
reversedList = List.from(allPersonObjectsList.reversed);
print("database getAllPersonList'te if uzunluk büyüktür 1'deyim");
for (var item in allPersonObjectsList) {
print(" ${item.personDisplayName}");
}
return reversedList;
} else {
print(
"database getAllPersonList'te else, uzunluk eşittir 1 ya da daha küçük'teyim");
print("allPersonObjectsList from db = $allPersonObjectsList");
return allPersonObjectsList;
}
}
// ADD Person to DB
Future<int> addPersonToPersonTableAtDb(Person person) async {
print(
"addPersonToPersonTableAtDb bloğundayım. Gelen personDisplayName = ${person.personDisplayName}");
var db = await _getDatabase();
var result = await db.insert(_personTableName, person.personToMap());
notifyListeners();
return result;
}
// UPDATE Person at DB
Future<int> updatePersonAtDb(Person personToUpdate) async {
var db = await _getDatabase();
var result = await db.update(_personTableName, personToUpdate.personToMap(),
where: "personID = ?", whereArgs: [personToUpdate.personID]);
notifyListeners();
return result;
}
// DELETE Person from DB
Future<int> deletePersonFromDb(int personID) async {
var db = await _getDatabase();
var result = db
.delete(_personTableName, where: "personID = ?", whereArgs: [personID]);
notifyListeners();
return result;
}
}
below is the Animation Screen Code
import 'dart:io';
import 'package:scoped_model/database/database_helper.dart';
import 'package:scoped_model/design_elements/size_config.dart';
import 'package:scoped_model/design_elements/smart_design.dart';
import 'package:scoped_model/models/person.dart';
import 'package:scoped_model/utils/format_photo.dart';
import 'package:dashed_circle/dashed_circle.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
//there is some way to improve the way we have to do this skvkjsdvjdjsjvdsjhljshdljfhjdsnvjzvjzjvnjsljdvljsdlvnsdv
import 'add_contact_screen.dart';
class AnimationScreen extends StatefulWidget {
List<Person> allPersonsFromDB;
AnimationScreen({this.allPersonsFromDB});
_AnimationScreenState createState() => _AnimationScreenState();
}
class _AnimationScreenState extends State<AnimationScreen>
with TickerProviderStateMixin {
//
int builtTime = 0;
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
TextEditingController _textEditingController = TextEditingController();
PageController _pageController;
var heightAppBar = AppBar().preferredSize.height;
DatabaseHelper databaseHelper;
List<Person> allPersonsFromDBReordered;
List<Person> personsToPresent;
int pageIndex = 0;
int personIndex = 0;
Animation dGap;
Animation dBase;
Animation dReverse;
Animation<Color> dColorAnimation;
AnimationController dController;
#override
void initState() {
super.initState();
print("AppBar height = ${AppBar().preferredSize.height}");
databaseHelper = DatabaseHelper();
_pageController =
PageController(initialPage: pageIndex, viewportFraction: .51);
allPersonsFromDBReordered = List<Person>();
personsToPresent = List<Person>();
animateDashedCircle();
getPersonsList();
}
bool isInteger(num value) => value is int || value == value.roundToDouble();
#override
void dispose() {
dController.dispose();
_pageController.dispose();
super.dispose();
}
Future<void> getPersonsList() async {
print('getPersonList called');
databaseHelper.getAllPersonsList().then((value) {
if (value.length != 0) {
setState(() {
print("setState 1 çağırıldı.");
personsToPresent = value;
print("Length of personsToPresent = ${personsToPresent.length}");
});
} else {
print("database'deki personList uzunluğu sıfır");
setState(() {
personsToPresent = [];
});
print('database deki Person listesi boş.');
}
});
}
void animateDashedCircle() {
dController = AnimationController(
vsync: this, duration: Duration(milliseconds: 1200));
dBase = CurvedAnimation(parent: dController, curve: Curves.ease);
dReverse = Tween<double>(begin: 0.0, end: -1.0).animate(dBase);
dColorAnimation =
ColorTween(begin: Colors.deepOrange, end: Colors.deepPurple)
.animate(dController);
dGap = Tween<double>(begin: 3.0, end: 0.0).animate(dBase);
dController.forward();
}
#override
Widget build(BuildContext context) {
builtTime++;
SizeConfig().init(context);
print(
"Screen height = ${MediaQuery.of(context).size.height}, , $builtTime kez build edildi.");
return Scaffold(
key: _scaffoldKey,
appBar: PreferredSize(
preferredSize: Size.fromHeight(SizeConfig.blockSizeVertical * 7),
child: AppBar(
backgroundColor: Colors.blueAccent,
centerTitle: true,
actions: [
Row(
children: [
Padding(
padding:
EdgeInsets.all(SmartDesign.getPadding(context, 8) / 2),
child: GestureDetector(
child: Icon(
Icons.person_add,
color: Colors.white,
size: SmartDesign.getPadding(context, 16) * 1.25,
),
onTap: () {
print('Add new person tapped.');
/* BURAYI YAZDIN BIRAKTIN ******** */
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ContactListScreen()))
.then((value) {
getPersonsList();
setState(() {
pageIndex = 0;
_pageController.jumpToPage(pageIndex);
});
});
},
/* BURAYI YAZDIN BIRAKTIN ******* */
),
),
Padding(
padding:
EdgeInsets.all(SmartDesign.getPadding(context, 8) / 2),
child: GestureDetector(
child: Icon(
Icons.list,
color: Colors.white,
size: SmartDesign.getPadding(context, 24) * 1.25,
),
onTap: () {},
),
),
],
)
],
title: Text(
'DashedCircle',
textAlign: TextAlign.end,
style: TextStyle(color: Colors.white),
),
),
),
body: Center(
child: Container(
color: Colors.white,
child: PageView.builder(
// clipBehavior: Clip.none,
itemCount:
personsToPresent.length <= 0 ? 1 : personsToPresent.length,
physics: BouncingScrollPhysics(),
controller: _pageController,
onPageChanged: (page) {
if (isInteger(page)) {
print("integer page index = $page");
animateDashedCircle();
setState(() {
pageIndex = page;
});
}
print('PageIndex : $page');
},
itemBuilder: (context, index) {
return Container(
child: Padding(
padding: EdgeInsets.only(
top: SmartDesign.getPadding(context, 16),
left: SmartDesign.getPadding(context, 6),
right: SmartDesign.getPadding(context, 6)),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
index == pageIndex
? Container(
child: AnimatedBuilder(
animation: dController,
builder: (_, child) {
return RotationTransition(
turns: dReverse,
child: DashedCircle(
gapSize: dGap.value,
dashes: 50,
color: dColorAnimation.value,
child: AnimatedBuilder(
animation: dController,
builder: (_, child) {
return RotationTransition(
turns: dBase,
child: Padding(
padding: EdgeInsets.all(
(SmartDesign.getPadding(
context, 6) /
2)),
child: personsToPresent.length <=
0
? CircleAvatar(
//radius: 90,
radius:
MediaQuery.of(context)
.size
.width /
7,
backgroundImage: AssetImage(
"assets/images/blueAvatar2_Half.png"))
: personsToPresent[index]
.personPhoto ==
null
? CircleAvatar(
//radius: 90,
radius: MediaQuery.of(
context)
.size
.width /
7,
backgroundImage:
AssetImage(
"assets/images/blue_avatar.png"),
/*child: Center(
child: Text(
'Initials')),*/
)
: CircleAvatar(
//radius: 90,
radius: MediaQuery.of(
context)
.size
.width /
7,
backgroundImage: FormatPhoto
.memoryImageFromBase64String(
personsToPresent[
pageIndex]
.personPhoto),
),
),
);
},
child: Placeholder(
key: Key('colorAnimated')),
),
),
);
},
child: Placeholder(key: Key('animated')),
),
//color: Colors.red,
)
: personsToPresent[index].personPhoto == null
? Container(
child: Padding(
padding: EdgeInsets.all(
(SmartDesign.getPadding(context, 6) /
2)),
child: CircleAvatar(
//radius: 90,
radius:
MediaQuery.of(context).size.width / 7,
backgroundImage: AssetImage(
"assets/images/green_avatar.png"),
),
),
)
: Container(
child: Padding(
padding: EdgeInsets.all(
(SmartDesign.getPadding(context, 6) /
2)),
child: CircleAvatar(
//radius: 90,
radius:
MediaQuery.of(context).size.width /
7,
backgroundImage: FormatPhoto
.memoryImageFromBase64String(
personsToPresent[index]
.personPhoto)),
),
),
Padding(
padding: EdgeInsets.only(
top: (SmartDesign.getPadding(context, 8)),
left: (SmartDesign.getPadding(context, 6) / 1.5),
right: (SmartDesign.getPadding(context, 6) / 1.5),
),
child: Column(
children: [
Text(
personsToPresent.length <= 0
? ""
: "${personsToPresent[index].personDisplayName}",
style: TextStyle(
fontWeight: FontWeight.bold,
fontSize:
MediaQuery.of(context).size.width / 23,
color: Colors
.black // Font size iPhone 11'e göre 18 bulmak için
),
textAlign: TextAlign.center,
),
],
),
),
//_buildCard(index),
],
),
),
);
}, // itemBuilder(){}
),
),
),
);
}
}
I added a Video file to Show the error problem => https://i.imgur.com/ilrURiW.mp4
Every time your AnimationScreen builds it keeps on reloading the image with FormatPhoto.memoryImageFromBase64String(...).
To fix this, when you load your users in getPersonsList and when you are creating your Person objects, you should call the function FormatPhoto.memoryImageFromBase64String(...) and assign it to personPhoto or a new variable. Then use that as the image like this:
CircleAvatar(
radius: MediaQuery.of(context).size.width / 7,
// or personsToPresent[pageIndex].photoThatWasLoaded
backgroundImage: personsToPresent[pageIndex].personPhoto,
)
I am fetching data from my api previously i am suing hardcoded json data so its working perfectly in app but now when i am using the API data its showing this error
RangeError (index): Invalid value: Valid value range is empty: 0
class MyHomePage extends StatefulWidget {
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
bool showApp = false;
var _questions = new List<Questions>();
_getQuestions() {
API.getUsers().then((response) {
setState(() {
Iterable list = json.decode(response.body);
print(list);
print(list);
_questions = list.map((model) => Questions.fromJson(model)).toList();
print(_questions);
showApp = true;
});
});
}
initState() {
super.initState();
_getQuestions();
}
int index = 0;
bool shouldShow = false;
#override
Widget build(BuildContext context) {
int size = _questions.length;
void nextQuestion() {
if (index < size - 1)
setState(() {
index++;
});
print(index);
}
double percentage1Calculate() {
int wouldClick = 12;
int ratherClick = 13;
double percentage1 = wouldClick / (wouldClick + ratherClick) * 100;
return percentage1;
}
double percentage2Calculate() {
int wouldClick = 2;
int ratherClick = 3;
double percentage2 = ratherClick / (wouldClick + ratherClick) * 100;
return percentage2;
}
void percengtageTrigger(){
setState(() {
shouldShow = true;
});
Timer timer = Timer(Duration(milliseconds: 1350), () {
setState(() {
shouldShow = false;
});
});
}
final PrimaryColor = const Color(0xff404040);
final PreferredSizeWidget appBar = AppBar(
centerTitle: true,
title: Text(
'Would you Rather',
style: TextStyle(fontFamily: 'FredokaOne'),
),
backgroundColor: PrimaryColor,
);
double stackHeight = (MediaQuery.of(context).size.height -
appBar.preferredSize.height -
MediaQuery.of(context).padding.top);
double stackWidth = MediaQuery.of(context).size.width;
return Scaffold(
backgroundColor: Color(0xff404040),
appBar: appBar,
body: Stack(
children: [
GestureDetector(
onTap: () {
percengtageTrigger();
},
child: Container(
height: stackHeight * 0.5,
width: stackWidth,
color: Colors.blue,
child: Column(
children: <Widget>[
shouldShow
? Container(
padding: const EdgeInsets.only(top: 10, right: 10),
height: stackHeight * 0.1,
color: Colors.blue,
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(
'${percentage1Calculate().toStringAsFixed(0)}%',
style: TextStyle(
color: Colors.white,
fontSize: 23,
fontFamily: 'NewsCycle',
),
),
],
))
: Container(
height: stackHeight * 0.1,
color: Colors.blue,
width: double.infinity,
),
Container(
color: Colors.blue,
height: stackHeight * 0.4,
width: double.infinity,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 20),
child: Text(
_questions[index].would, //here its showing error
style: TextStyle(
color: Colors.white,
fontSize: 23,
fontFamily: 'NewsCycle',
),
),
),
],
)),
],
),
),
),
GestureDetector(
onTap: () {
percengtageTrigger();
},
child: Align(
alignment: Alignment.bottomCenter,
child: Container(
height: stackHeight * 0.5,
width: stackWidth,
color: Colors.red,
child: Column(
children: <Widget>[
shouldShow
? Container(
padding:
const EdgeInsets.only(top: 10, right: 10),
height: stackHeight * 0.1,
color: Colors.red,
width: double.infinity,
child: Column(
mainAxisSize: MainAxisSize.max,
crossAxisAlignment: CrossAxisAlignment.end,
children: <Widget>[
Text(
'${percentage2Calculate().toStringAsFixed(0)}%',
style: TextStyle(
color: Colors.white,
fontSize: 23,
fontFamily: 'NewsCycle',
),
),
],
))
: Container(
height: stackHeight * 0.1,
color: Colors.red,
width: double.infinity,
),
Container(
color: Colors.red,
height: stackHeight * 0.4,
width: double.infinity,
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 40),
child: Text(
_questions[index].rather,
style: TextStyle(
color: Colors.white,
fontSize: 23,
fontFamily: 'NewsCycle',
),
),
),
],
)),
],
),
),
),
),
Align(
alignment: Alignment.center,
child: Container(
width: stackWidth,
height: stackHeight * 0.015,
color: Color(0xff404040),
),
),
Align(
alignment: Alignment.center,
child: Container(
width: stackWidth,
height: stackHeight * 0.15,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Color(0xff404040),
),
child: Align(
alignment: Alignment.center,
child: GestureDetector(
onTap: () {
nextQuestion();
},
child: Text(
"SKIP",
style: TextStyle(
color: Colors.white,
fontFamily: 'FredokaOne',
fontSize: 27),
),
),
)),
),
],
));
}
}
Also comment in code where its showing error. I dont know how to solve it but i think the issue is causing because API data is not loaded before its calling the index data maybe ?
Try to use Futurebuild function but its just keep loading the function and showing the indicator not showing the Container when its loaded in termail its keep printing the value as infinite loop.
class _MyHomePageState extends State<MyHomePage> {
bool showApp = false;
var _questions = new List<Questions>();
Future<List> _getQuestions() async {
final response = await API.getUsers();
setState(() {
Iterable list = json.decode(response.body);
print(list);
print(list);
_questions = list.map((model) => Questions.fromJson(model)).toList();
print(_questions);
showApp = true;
});
return Future.value(_questions);
}
int index = 0;
bool shouldShow = false;
#override
Widget build(BuildContext context) {
int size = _questions?.length;
void nextQuestion() {
if (index < size - 1)
setState(() {
index++;
});
print(index);
}
double percentage1Calculate() {
int wouldClick = 12;
int ratherClick = 13;
double percentage1 = wouldClick / (wouldClick + ratherClick) * 100;
return percentage1;
}
double percentage2Calculate() {
int wouldClick = 2;
int ratherClick = 3;
double percentage2 = ratherClick / (wouldClick + ratherClick) * 100;
return percentage2;
}
void percengtageTrigger() {
setState(() {
shouldShow = true;
});
Timer timer = Timer(Duration(milliseconds: 1350), () {
setState(() {
shouldShow = false;
});
});
}
final PrimaryColor = const Color(0xff404040);
final PreferredSizeWidget appBar = AppBar(
centerTitle: true,
title: Text(
'Would you Rather',
style: TextStyle(fontFamily: 'FredokaOne'),
),
backgroundColor: PrimaryColor,
);
double stackHeight = (MediaQuery.of(context).size.height -
appBar.preferredSize.height -
MediaQuery.of(context).padding.top);
double stackWidth = MediaQuery.of(context).size.width;
return FutureBuilder(
initialData: null, //initial default data if you have some
future: _getQuestions(),
builder: (BuildContext context,
AsyncSnapshot<List> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
print("Data found, You can continue");
return Center(child: Text('Datafound'));
} else if (snapshot.hasError) {
return Center(child: Text('HaSError'));
}
} else {
print("loading");
return CircularProgressIndicator();
}
});
}
}
It seems like the problem is what you are suspecting. The data is not available before the build method starts executing and thus we are encountering an out of range error. The solution to this problem would be to use a FutureBuilder in your build method.
Instead of getting the data in initState, wrap the code inside your build method in FutureBuilder and set the getUser() as the future parameter in the FutureBuilder. Take a look the code snippet below
#override
Widget build(BuildContext context) {
return FutureBuilder(
initialData:null //initial default data if you have some
future: API.getUsers(),
builder:(BuildContext context,AsyncSnapshot snapshot){
if(snapshot.ConnectionState==ConnectionState.none||snapshot.ConnectionState==ConnectionState.waiting){
print("data has not been fetched yet");
return CircularProgressIndicator();
}
else{
if(snapshot.hasData){
print("Data found, You can continue");
//decode your json here and initialize the variables you need
return Scaffold(
// your widgets
);
}else{
print("No data found");
return Text("No data found");
}
}
}
);
}
In your case, you'd do something like this
import 'package:flutter/material.dart';
class _MyHomePageState extends State<MyHomePage> {
bool showApp = false;
var _questions = new List<Questions>();
// Future<List> _getQuestions() async {
// final response = await API.getUsers();
// setState(() {
// Iterable list = json.decode(response.body);
// print(list);
// print(list);
// _questions = list.map((model) => Questions.fromJson(model)).toList();
// print(_questions);
// showApp = true;
// });
// return Future.value(_questions);
// }
int index = 0;
bool shouldShow = false;
#override
Widget build(BuildContext context) {
int size = _questions?.length;
void nextQuestion() {
if (index < size - 1)
setState(() {
index++;
});
print(index);
}
double percentage1Calculate() {
int wouldClick = 12;
int ratherClick = 13;
double percentage1 = wouldClick / (wouldClick + ratherClick) * 100;
return percentage1;
}
double percentage2Calculate() {
int wouldClick = 2;
int ratherClick = 3;
double percentage2 = ratherClick / (wouldClick + ratherClick) * 100;
return percentage2;
}
void percengtageTrigger() {
setState(() {
shouldShow = true;
});
Timer timer = Timer(Duration(milliseconds: 1350), () {
setState(() {
shouldShow = false;
});
});
}
final PrimaryColor = const Color(0xff404040);
final PreferredSizeWidget appBar = AppBar(
centerTitle: true,
title: Text(
'Would you Rather',
style: TextStyle(fontFamily: 'FredokaOne'),
),
backgroundColor: PrimaryColor,
);
double stackHeight = (MediaQuery.of(context).size.height -
appBar.preferredSize.height -
MediaQuery.of(context).padding.top);
double stackWidth = MediaQuery.of(context).size.width;
return FutureBuilder(
initialData: null, //initial default data if you have some
future: API.getUsers(),
builder: (BuildContext context, AsyncSnapshot<List> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (snapshot.hasData) {
var response = snapshot.data;
print("Data found, You can continue");
Iterable list = json.decode(response.body);
print(list);
print(list);
_questions =
list.map((model) => Questions.fromJson(model)).toList();
print(_questions);
showApp = true;
return Center(child: Text('Datafound'));
} else if (snapshot.hasError) {
return Center(child: Text('HaSError'));
}
} else {
print("loading");
return CircularProgressIndicator();
}
});
}
}