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))
]);
}
Related
First of all I don't know what i am facing, but I'll do my best to explain the situation.
I'm trying to build chat app and i have two sections on same page. These two different sections are rendering inside same ListView. Only thing that changing is the data which i am using to feed the ListView. I need to get the status of user in real time so i am putting tagged controllers for each tile which is rendering inside list view. Here comes the problem. The tiles rendered at the same index are not showing the true states of themselves until some state changes on that tile for example position of any Stack item.
Here is the code.
In this part I'm rendering ListView
ListView.builder(
itemCount: chatController.currentChats!.length,
itemBuilder: (context, index) {
return GetBuilder<UserOnlineController>(
global: false,
init: Get.find<UserOnlineController>(tag: chatController.currentUserID == chatController.currentChats![index].user1 ? chatController.currentChats![index].user2 : chatController.currentChats![index].user1),
builder: (userController) {
return Stack(
children: [
Positioned(
child: Container(
color: Colors.black,
width: Get.width,
height: Dimensions.h100,
child: Center(
child: Text(
"${userController.user!.name!}",
style: TextStyle(
color: Colors.white
),
),
),
)
)
],
);
}
);
}),
This is the part that I'm putting controllers and listening chats in real time.
void listenChats() async {
var chatController = Get.find<ChatController>();
var messagesController = Get.find<MessagesController>();
String userID = Get.find<SharedPreferenceService>().getUserID();
var currentUserDoc = (await firestoreService.getCollection('users').where('userID', isEqualTo: userID).get()).docs[0];
Stream<DocumentSnapshot> userStream = firestoreService.getCollection('users').doc(currentUserDoc.id).snapshots();
Stream<QuerySnapshot> chatStream = firestoreService.getCollection('chats').snapshots();
await for(var user in userStream){
var userObject = UserModel.fromJson(user.data() as Map<String,dynamic>);
await for(var chats in chatStream) {
List<Chat> activeChats = [];
List<Chat> unActiveChats = [];
List<Chat> newMatches = [];
List<Chat> allChats = [];
var filteredChats = chats.docs.where((chat) => userObject.chat!.active_chats!.contains(chat['chatID'])).toList();
filteredChats.forEach((chatDoc) {
var currentChat = Chat.fromJson(chatDoc.data() as Map<String,dynamic>);
if(currentChat.user1 == userID){
Get.put(
UserOnlineController(firestoreService: firestoreService, userID: currentChat.user2!),
tag: currentChat.user2!,
);
}
else{
Get.put(
UserOnlineController(firestoreService: firestoreService, userID: currentChat.user1!),
tag: currentChat.user1!
);
}
allChats.add(currentChat);
if(currentChat.isActive!){
if(currentChat.isStarted!){
activeChats.add(currentChat);
}
else{
newMatches.add(currentChat);
}
}
else{
unActiveChats.add(currentChat);
}
});
messagesController.generatePositions(activeChats.length, true);
messagesController.generatePositions(unActiveChats.length, false);
chatController.setAllChats(allChats);
chatController.setCurrentChats();
chatController.setChats(activeChats, unActiveChats, newMatches);
}
}
}
And this is the part that I'm using to control the UI state
void setAllChats(List<Chat> allChats) {
_allChats = allChats;
}
void setCurrentChats() {
_currentChats = _allChats!.where((chat) => chat.isActive! == isActiveMessages).toList();
update();
}
void setIsActiveMessages(bool state){
_isActiveMessages = state;
_currentChats = _allChats!.where((chat) => chat.isActive! == state).toList();
update();
}
In the above pictures all of these users are different but only true one is the third one at second screen shot.
Hello again this question basically explains all the details.
Multiple Instance with GetX tag not working in flutter
Basically you need to add key parameter.
GetBuilder<UserChatController>(
key: Key(currentUserControllerTag),
tag: currentUserControllerTag,
global: false,
init: Get.find<UserChatController>(tag: currentUserControllerTag),
builder: (controller) {
return controller.user != null ? Container(
width: Get.width,
height: Dimensions.h100,
child: Stack(
children: [
Positioned(
left: 0,
right: 0,
child: Container(
height: Dimensions.h100,
width: double.maxFinite,
color: Colors.black,
child:Center(
child: Text(
controller.user != null ? controller.user!.name! : "",
style: TextStyle(
color: Colors.white
),
),
)
))
],
),
) : Container();
},
)
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.
I want to insert a Icon/Action based on X Y percent position of image as follows:
This is Json file:
[
{
"seasonName": "Spring",
"isDaySelected": true,
"listButton": "Sky",
"pointXPercent": 66.0,
"pointYPercent": 12.0,
"pointName": "Bird",
"pointDialog": "this is a bird"
},
{
"seasonName": "Spring",
"isDaySelected": true,
"listButton": "Sky",
"pointXPercent": 53.6,
"pointYPercent": 27.4,
"pointName": "Cloud",
"pointDialog": "this is a cloud"
},
{
"seasonName": "Spring",
"isDaySelected": true,
"listButton": "Land",
"pointXPercent": 38.5,
"pointYPercent": 78.3,
"pointName": "Flower",
"pointDialog": "this is a flower"
},
{
"seasonName": "Spring",
"isDaySelected": false,
"listButton": "Land",
"pointXPercent": 55.3,
"pointYPercent": 79.8,
"pointName": "Meadow",
"pointDialog": "this is a meadow"
},
{
"seasonName": "Summer",
"isDaySelected": true,
"listButton": "Sky",
"pointXPercent": 38.9,
"pointYPercent": 23.5,
"pointName": "Sun",
"pointDialog": "this is the sun"
}
]
I want that when click on the TogglesButton "Sky" => get data from Json:
Get values seasonName = "Spring" (because TabBar is being
selected as "Spring")
Get values that satisfy (1) and have isDaySelected = "true" (because the TogglesButton isDaySelected is being selected as true)
Get values that satisfy (1) and (2) and listButton = "Sky"
Show the pointName values that satisfy (1) (2) (3) on image based on X Y percent. Ex:
pointName: "Bird" => pointXPercent = 66.0, pointYPercent = 12.0
pointName: "Cloud" => pointXPercent = 53.6, pointYPercent = 27.4
So pls help me, this is main file:
import 'package:ask/model/season_model.dart';
import 'package:ask/services/season_service.dart';
import 'package:flutter/material.dart';
class SeasonPage extends StatefulWidget {
SeasonPage() : super();
#override
_SeasonPageState createState() => _SeasonPageState();
}
class _SeasonPageState extends State<SeasonPage> {
List<Season> _season = [];
List<bool> isDaySelected = [true, false];
List<bool> listButton = [false, false, false];
final String springDay = 'https://i.imgur.com/MUuCuYI.png';
final String springNight = 'https://i.imgur.com/QxbAg8Y.png';
final String summerDay = 'https://i.imgur.com/9Qi6oLm.png';
final String summerNight = 'https://i.imgur.com/jrFGHvn.png';
final String autumnDay = 'https://i.imgur.com/yo0RWi6.png';
final String autumnNight = 'https://i.imgur.com/iPW4r2g.png';
final String winterDay = 'https://i.imgur.com/CnFDmEJ.png';
final String winterNight = 'https://i.imgur.com/lFNdvDe.png';
#override
void initState() {
super.initState();
SeasonServices.getSeason().then((seasons) {
setState(() {
_season = seasons;
});
});
}
#override
Widget build(BuildContext context) {
return Container(
child: DefaultTabController(
length: 4,
child: Scaffold(
appBar: AppBar(
title: Text('Season'),
bottom: TabBar(tabs: [
Tab(child: Text('Spring')),
Tab(child: Text('Summer')),
Tab(child: Text('Autumn')),
Tab(child: Text('Winter')),
]),
),
body: Column(children: [
Center(
child: ToggleButtons(
children: [Text('Day'), Text('Night')],
onPressed: (int index) {
setState(() {
for (int buttonIndex = 0; buttonIndex < isDaySelected.length; buttonIndex++) {
if (buttonIndex == index) {
isDaySelected[buttonIndex] = true;
} else {
isDaySelected[buttonIndex] = false;
}
}
});
},
isSelected: isDaySelected)),
SizedBox(height: 5),
Center(
child: ToggleButtons(
children: [Text('Sky'), Text('Mountain'), Text('Land')],
onPressed: (int index) {
setState(() {
for (int buttonIndex = 0; buttonIndex < listButton.length; buttonIndex++) {
if (buttonIndex == index) {
listButton[buttonIndex] = !listButton[buttonIndex];
} else {
listButton[buttonIndex] = false;
}
}
});
},
isSelected: listButton)),
Expanded(
child: TabBarView(children: [
isDaySelected[0] ? Image.network(springDay) : Image.network(springNight),
isDaySelected[0] ? Image.network(summerDay) : Image.network(summerNight),
isDaySelected[0] ? Image.network(autumnDay) : Image.network(autumnNight),
isDaySelected[0] ? Image.network(winterDay) : Image.network(winterNight),
]),
)
]))));
}
}
There are several ways to achive result
Use Stack and wrap it in IntrinsicHeight to set it height as you image height
Column(
children: <Widget>[
IntrinsicHeight(
child: Stack(
children: <Widget>[
Image.network('https://i.imgur.com/MUuCuYI.png'),
Align(
alignment: Alignment(.66 * 2 - 1, .12 * 2 - 1),
child: Text('bird'),
),
Align(
alignment: Alignment(.536 * 2 - 1, .274 * 2 - 1),
child: Text('cloud'),
),
],
),
),
],
),
This will be sized to Stack children max height and until network image loaded(finally you know size) it will be tall as max of bird or cloud heigh
Note that IntrinsicHeight is relatively expensive. Avoid using it where possible.
For more complex cases you can use LayoutBuilder
body: Column(
children: <Widget>[
Expanded(
child: LayoutBuilder(
builder: (context, constraints) {
return Stack(
children: <Widget>[
Positioned(
top: .12 * constraints.biggest.height,
left: .66 * constraints.biggest.width,
child: Text('bird'),
),
Positioned(
top: .274 * constraints.biggest.height,
left: .536 * constraints.biggest.width,
child: Text('cloud'),
),
],
);
},
),
),
],
),
PS Here we laying out by left&top of our bird&cloud
If you need to layout by center of birs&cloud - you have to know their sizes and do a little bit more math
You can use Align to choose the position in a stack like this:
Stack(children: [
child: Align(
alignment: Alignment(-.40, -.90),
child: MyPictureWidget()
),
]);
Nicer because you don't need to get the constraints. :) Alignment(0, 0) would be at the center
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
When I add new item to my list, it will overwrites earlier value. I want to append the list, but it is not happening
Container(
// color: Colors.red,
child: Row(
mainAxisAlignment: MainAxisAlignment.end,
children: <Widget>[
Container(
width: 50,
height: 50,
// color: Colors.blue,
child: FlatButton(onPressed: (){
if(_itemCount > 0){
setState(() {
_itemCount--;
});
}
}, child: Image(image: AssetImage("images/minus.png"),width: 20,height: 20,),),
),
Container(
child: Text("$_itemCount"),
),
Container(
width: 50,
height: 50,
// color: Colors.green,
child: FlatButton(onPressed: () async{
setState(() {
_itemCount++;
});
cartItemList = [{"index":widget.intex,"itemObj":widget.items,"quantity":_itemCount}];
print(addedItems(cartItemList));
final prefs = await SharedPreferences.getInstance();
await prefs.setStringList('itemList', addedItems(cartItemList));
}, child: Image(image: AssetImage("images/plus.png"),width: 20,height: 20,),),
),
],
),
),
I have a ListView, ListView items will fetch from API, when I click one item I want it add to a list, which I can save in sharedpreference. but every time I click on a button earlier one overwritten by new one.
below is the code to convert the data to JSON format
List<String> addedItems(List<dynamic> cartList){
try {
var res = cartList.map((v) => json.encode(v)).toList();
return res;
} catch (err) {
// Just in case
return [];
}
},
Output is
When I add first item
[{"itemObj":{"item_price":22.0,"item_name":"DINE SPECIAL BREAKFAST","item_img":" ","item_code":"001","item_discount":0.0,"item_id":552,"category_id":12},"quantity":1}]
When I add same item again
[{"itemObj":{"item_price":22.0,"item_name":"DINE SPECIAL BREAKFAST","item_img":" ","item_code":"001","item_discount":0.0,"item_id":552,"category_id":12},"quantity":2}]
(quantity increased)
When I add a new item
[{"itemObj":{"item_price":20.0,"item_name":"English Breakfast","item_img":" ","item_code":"002","item_discount":0.0,"item_id":71,"category_id":12},"quantity":1}]
(Where are the DINE SPECIALs?)
But I want output like
[{"itemObj":{"item_price":22.0,"item_name":"DINE SPECIAL BREAKFAST","item_img":" ","item_code":"001","item_discount":0.0,"item_id":552,"category_id":12},"quantity":2},{"item_price":20.0,"item_name":"English Breakfast","item_img":" ","item_code":"002","item_discount":0.0,"item_id":71,"category_id":12},"quantity":1}]
you set list every time you click button like this
cartItemList = [{"index":widget.intex,"itemObj":widget.items,"quantity":_itemCount}];
maybe you need to do is
cartItemList.add({"index":widget.intex,"itemObj":widget.items,"quantity":_itemCount});