Saving data between widgets in Flutter - flutter

hi i am making an app for restaurant but i need some help i have a listtilel and i would like to save those values in memory or firebase anywhere i would like to get which topics selected how should i do that
basicly i meant i want to get choosen datas from user and i would like to add it orders page if you have any suggestions please let me know thanks
import 'package:flutter/material.dart';
import 'package:resat/BurgerListView/data/toppics_model.dart';
import 'data/toppics.dart';
class decor extends StatefulWidget {
#override
MyAppState createState() {
return new MyAppState();
}
}
class MyAppState extends State<decor> {
List ketchup = [
'No',
'light',
'regular',
'extra',
];
List calori = ['0 Cal', '1 Cal', '2 Cal', '3 Cal'];
var i = 2;
final List<topics> _topics = categories;
#override
Widget build(BuildContext context) {
// TODO: implement build
return Container(
margin: EdgeInsets.all(6), //space between other listtiles
decoration: BoxDecoration(
border: Border.all(color: Colors.grey),
borderRadius: BorderRadius.all(Radius.circular(8))),
child: ListTile(
title: Row(children: [
Expanded(
child:
Text("Ketchup\n" + calori[i], textAlign: TextAlign.center,),),
Expanded(
child: (InkWell(
child: Text("-", textAlign: TextAlign.center),
onTap: () {
setState(() {
if (i <= 0){
i = i;
}else
i--;
print(i);
});
},
)),
),
Expanded(child: Text(ketchup[i], textAlign: TextAlign.center)),
Expanded(
child: (InkWell(
child: Text("+", textAlign: TextAlign.center),
onTap: () {
setState(() {
if (i > 2) {
i = i;
} else
i++;
print(i);
});
},
)),
),
]),
leading: Icon(Icons.pie_chart))
);
}
}

I can suggest you two ways to save your data across the different users.
Unsurprisingly it's an online database either via firebase or vis your own Web service APIs hosted on your server.
I don't suggest you offline database(SQLite) anyway because it will be limited to a single user.
The data you save and fetch will be limited to a single user.
So, try learning the flutter concepts from,
Firebase database
Web api implementation
Offline datbase

Related

What can I do to make my ListView stop incrementing the data every time I open it?

My first Flutter project, which is a tricycle booking system, has just begun. Using the ListView widget, I wanted to display all of the active passengers that are saved in my Firebase Database. However, when I attempted to display it and place it in a List, all functions are working fine at first click. When you click the button to view the ListView a second time, all of the saved data are replicated. The list continues after my third click and grows by three. The image below illustrates what takes place when I repeatedly click on the ListView.
These are the blocks of code that are utilized for this functionality:
CODE for Functionality
retrieveOnlinePassengersInformation(List onlineNearestPassengersList) async
{
dList.clear();
DatabaseReference ref = FirebaseDatabase.instance.ref().child("passengers");
for(int i = 0; i<onlineNearestPassengersList.length; i++)
{
await ref.child(onlineNearestPassengersList[i].passengerId.toString())
.once()
.then((dataSnapshot)
{
var passengerKeyInfo = dataSnapshot.snapshot.value;
dList.add(passengerKeyInfo);
print("passengerKey Info: " + dList.toString());
});
}
}
CODE for the UI
body: ListView.builder(
itemCount: dList.length,
itemBuilder: (BuildContext context, int index)
{
return GestureDetector(
onTap: ()
{
setState(() {
chosenPassengerId = dList[index]["id"].toString();
});
Navigator.pop(context, "passengerChoosed");
},
child: Card(
color: Colors.grey,
elevation: 3,
shadowColor: Colors.green,
margin: EdgeInsets.all(8.0),
child: ListTile(
leading: Padding(
padding: const EdgeInsets.only(top: 2.0),
child: Icon(
Icons.account_circle_outlined,
size: 26.sp,
color: Color(0xFF777777),
),
),
title: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
Row(
children: [
Text(
dList[index]["first_name"] + " " + dList[index]["last_name"],
style: TextStyle(
fontFamily: "Montserrat",
fontSize: 18.sp,
fontWeight: FontWeight.bold,
color: Colors.black,
),
),
Icon(
Icons.verified_rounded,
color: Color(0xFF0CBC8B),
size: 22.sp,
),
],
),
],
),
),
),
);
},
),
Expected Result:
Actual Result AFTER CLICKING MANY TIMES:
Made a demo for you how to call function once on load
class CustomWidgetName extends StatefulWidget {
const CustomWidgetName({Key? key}) : super(key: key);
#override
State<CustomWidgetName> createState() => _CustomWidgetNameState();
}
class _CustomWidgetNameState extends State<CustomWidgetName> {
List? dList = [];
void myDataFunction() async {
// do your data fetch and add to dList
final newList = [];
setState(() {
dList = newList;
});
}
#override
void initState() {
super.initState();
myDataFunction(); // Call your async function here
}
#override
Widget build(BuildContext context) {
return Scaffold();
}
}
Try this solution.
Update SelectNearestActiveDriversScreen() like this:
class SelectNearestActiveDriversScreen extends StatefulWidget
{
DatabaseReference? referenceRideRequest;
final List list;
SelectNearestActiveDriversScreen({this.referenceRideRequest, required this.list});
#override
State<SelectNearestActiveDriversScreen> createState() => _SelectNearestActiveDriversScreenState();
}
In homepage.dart, declare List dList = [];, then change line 378 like this:
Navigator.push(context, MaterialPageRoute(builder: (c)=> SelectNearestActiveDriversScreen(list: dList)));
In SelectNearestActiveDriversScreen(), replace all dList with widget.list.
Finally, if you are using variables in a specific file declare them in that file(not in another file) or pass them in the constructor of the class / file / widget /screen you are calling.
If you would rather use global variables and state managers go for packages like GetX.

Why my Favorite button made using hive Database aint working?

I am trying to create a favorite button for my app. Which work is to change and save color, while the user press it, So I decided to use hive db for it. The problem is, when i tap on the button; the color get changed, but when i move to other page or hot start/reload the page, the color changed back to it former self automatically.How to solve this problem and create a favorite button successfully.
class p1 extends StatefulWidget {
#override
_p1State createState() => _p1State();
}
class _p1State extends State<p1> {
Box box;
_p1State();
#override
void initstate(){
super.initState();
// Get reference to an already opened box
box = Hive.box(FAVORITES_BOX);
}
#override
void dispose() {
// Closes all Hive boxes
Hive.close();
super.dispose();
}
get_info(){
var info = box.get(_isFavorite);
}
var _isFavorite = true;
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body:Stack(
children:<Widget>[
Image(
image:AssetImage("Image/Chowsun1.jpg"),
fit:BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
Align(alignment: Alignment.center,
child: Text(' Rehman '
,style: TextStyle(fontSize: 35.0,
color: Colors.white,
fontFamily: "Explora",
fontWeight: FontWeight.w900 ) )
),
Stack ( children: [Positioned(
top:90,
right: 20,
child:const Text(' 1 ',
style: TextStyle(
fontSize: 25.0,
color: Colors.white,
fontFamily: "Comforter"
),
),
)], ),
Align(
alignment: Alignment.bottomCenter,
child: (
IconButton(
icon: Icon(
Icons.favorite,
color:_isFavorite ? Colors.white: Colors.red
),
onPressed: () {
setState(() {
_isFavorite= !_isFavorite;
});
box.put(!_isFavorite, _isFavorite);
get_info();
}
)
)
)])
),
);
}
}
There are a lot of things that don't make sense in this code.
I believe that the flow should be like this.
Your Widget first initialize the hive box and check if there is any data to refer to.
If there is a data already written, load it, or else, set a default value, which I bet is false. Because everything is not favorite before you make it so.
When you click Favorite button, it updates _isFavorite value and put it in the open Box with a key which must be a unique value that can represent the selected item right
There are problems in your code:
You initialized the Box in initState() but you didn't consider if there is data already in Box. So you have to check and if there is data you can use, you have to update _isFavorite accordingly.
You close Box every time your widget is disposed but I don't see your widget opens it again when you're back to the widget. So just don't close it. It seems like you'll use it very often.
You put the data with a key, which is the old data whose data type is boolean. It's binary so it can't be used as an unique key.
So if I were you, I would fix the code like following:
import 'package:flutter/material.dart';
import 'package:hive/hive.dart';
class p1 extends StatefulWidget {
#override
_p1State createState() => _p1State();
}
class _p1State extends State<p1> {
late Box box;
late bool _isFavorite;
#override
void initState() {
super.initState();
// Get reference to an already opened box.
// This should be open before you re-enter this widget.
box = Hive.box('FAVORITES_BOX');
// Try getting data that already exists
final data = box.get(someKeyYouAlreadyUsed);
// if there is no data about favorite, assign false to _isFavorite
_isFavorite = data ?? false;
}
// Don't close the Hive Box if you're planning to come back and use it soon.
// #override
// void dispose() {
// // Closes all Hive boxes
// Hive.close();
// super.dispose();
// }
// I deleted this function. It doesn't do anything.
// get_info() {
// var info = box.get(_isFavorite);
// }
#override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Stack(children: <Widget>[
const Image(
image: AssetImage("Image/Chowsun1.jpg"),
fit: BoxFit.cover,
width: double.infinity,
height: double.infinity,
),
const Align(
alignment: Alignment.center,
child: Text(' Rehman ',
style: TextStyle(
fontSize: 35.0,
color: Colors.white,
fontFamily: "Explora",
fontWeight: FontWeight.w900))),
Stack(
children: const [
Positioned(
top: 90,
right: 20,
child: Text(
' 1 ',
style: TextStyle(
fontSize: 25.0,
color: Colors.white,
fontFamily: "Comforter"),
),
)
],
),
Align(
alignment: Alignment.bottomCenter,
child: (IconButton(
icon: Icon(Icons.favorite,
color: _isFavorite ? Colors.white : Colors.red),
onPressed: () {
setState(() {
_isFavorite = !_isFavorite;
});
box.put(someUniqueValueToRepresentThisItem, _isFavorite);
})))
])),
);
}
}
I hope this would work for you.
You are setting the state of button on the basis of _isFavorite variable value instead of the value which came from the hive database (your get info function). After inserting the value in hive db you must set the state of button using hive db value instead of the _isFavorite variable.

Show counter to number of elements hidden when overflow occurs in flutter row widget

Can anyone please help to implement this feature of Gmail that shows the counter to number of emails hidden when the email list becomes large ? I want to implement this in row widget where instead of being scrollable extra elements count is shown when overflow occurs.Gmail shows +15 counter for hidden emails
I was Curious to give a try to achieve the same effect, as asked.
Just in case, If anyone want a start for writing a custom one, then below code may help.
Here is my Code, Feel free to give any suggestions,
(For Now delete button in chips is not working bcoz of some logic problem, I will make it work another day)
import 'package:flutter/material.dart';
class Demo3 extends StatefulWidget {
#override
_Demo3State createState() => _Demo3State();
}
class _Demo3State extends State<Demo3> {
String temp = "";
bool showChips = false;
List<Widget> chipsList = new List();
TextEditingController textEditingController = new TextEditingController();
final _focusNode = FocusNode();
int countChipsToDeleteLater = 0;
#override
void initState() {
super.initState();
_focusNode.addListener(() {
print("Has focus: ${_focusNode.hasFocus}");
if (!_focusNode.hasFocus) {
showChips = false;
setState(() {});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: GestureDetector(
onTap: () {
FocusScope.of(context).requestFocus(new FocusNode());
},
child: new Container(
height: 500,
child: new Center(
child: Container(
width: 300,
child: !showChips
? Row(
children: [
buildTextField(),
showNumberWidgetIfAny(),
],
)
: Center(
child: Wrap(
children: [
Wrap(
children: buildChips(),
),
buildTextField(),
],
),
),
),
),
),
),
);
}
buildChips() {
return chipsList;
}
buildTextField() {
return Container(
width: 200,
child: new TextField(
showCursor: true,
focusNode: _focusNode,
autofocus: true,
cursorColor: Colors.black,
style: new TextStyle(fontSize: 22.0, color: Colors.black),
controller: textEditingController,
// decoration: InputDecoration.collapsed(
// hintText: "",
// ),
onChanged: (value) {
if (value.contains(" ")) {
checkWhatToStoreInChips(value, countChipsToDeleteLater);
textEditingController.clear();
setState(() {
showChips = true;
});
countChipsToDeleteLater++;
}
},
),
);
}
checkWhatToStoreInChips(String val, int chipsIndex) {
temp = "";
for (int i = 0; i < val.length; i++) {
if (val[i] == " ") {
break;
}
temp = temp + val[i];
}
addToChips(temp, chipsIndex);
}
addToChips(String tmp, int chipsIndex) {
chipsList.add(Chip(
// onDeleted: () {
// if (chipsList.length == 0) {
// countChipsToDeleteLater = 0;
// }
// chipsList.removeAt(chipsIndex);
// print(chipsList.length);
// print(chipsIndex);
// setState(() {});
// },
avatar: CircleAvatar(
backgroundColor: Colors.grey.shade800,
child: Text(tmp[0]),
),
label: Text(temp),
));
}
showNumberWidgetIfAny() {
int len = chipsList.length;
if (len >= 1) {
return GestureDetector(
onTap: () {
showChips = true;
setState(() {});
},
child: new Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.blue,
),
child: Padding(
padding: const EdgeInsets.all(8.0),
child: new Text(
"${chipsList.length.toString()} ",
style: new TextStyle(color: Colors.white, fontSize: 22),
),
),
),
);
}
return Container();
}
}
How it works:
Write something in text field, then press space, showChips boolean will become true
onChanged will detect the space and will send the string to a function.
That function will extract the string before space and then will add the string to a chip,
Finally the chip will be added to a chipslist.
We will have a boolean variable to check if the textfield is in focus and when to show the textfield and numberwidget (a widget which will keep count of the total chips, same like you asked in your question) or when to show the chipslist and textfield wraped in a wrap widget.
You can play around by changing the decoration of textfield to collapsed, to it look like the same as gmail.
Check this package, if you want to use custom package for ease.
I was facing a similar issue. I found a way to implement the Overflow count text.
Sample image
You basically have to paint the overflow text, and get its width like below
final TextPainter textPainter = TextPainter(
text: TextSpan(text: text, style: style),
textDirection: TextDirection.ltr,
textScaleFactor: WidgetsBinding.instance.window.textScaleFactor,
)..layout();
var textSize = textPainter.size;
textSize.width;
Then subtract that from the width available. Lets call it x.
Then create a sum of width for each row item(using TextPainter.layout() method mentioned above), till its value is less than x.
This way you'll know how many items can be shown in the row.
I have created a Flutter library to help with this.

How to update a widget state from another widget in Flutter using global Key?

I have a main widget screen contain two main widgets a Header (marked with red) and a list (marked with purple)
here is my code for that :
class ScreenClient extends StatefulWidget {
_ClientState createState() => _ClientState();
}
class _ClientState extends State<ScreenClient> {
#override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
ClientHeader(), // this is my header widget red
Expanded(
child: ClientList(), // this is my list widget purple
),
],
);
}
}
the header widget has three options as you can see Tous Bloqué and ayant Retard , what I'm trying to achieve is pass the value of the clicked option to the list widget marked with purple (because those options are filters and the list elements should be shown based on the chosen option)
I have a hard time understanding state management packages and from what I understand Global Keys can do the trick but How ? .
here is my header widget code :
class ClientHeader extends StatefulWidget {
_HeaderClientState createState() => _HeaderClientState();
}
class _HeaderClientState extends State<ClientHeader> {
String nomSituation;
String option = "Tous";
#override
Widget build(BuildContext context) {
return Container(
child: Row(
children: <Widget>[
GestureDetector(
child: Text(
"Tous",
style: TextStyle(
color: option == "Tous" ? Colors.white : Colors.grey[400],
),
),
onTap: () {
setState(() {
option = "Tous";
});
},
),
GestureDetector(
child: Text(
"Bloqué",
style: TextStyle(
color: option == "Bloqué" ? Colors.white : Colors.grey[400],
),
),
onTap: () {
setState(() {
option = "Bloqué";
//add send value to ClientList widet ?
});
},
),
GestureDetector(
child: Text(
"Ayant Retard",
style: TextStyle(
color:
option == "Ayant Retard" ? Colors.white : Colors.grey[400],
),
),
onTap: () {
setState(() {
option = "Ayant Retard";
});
},
),
],
),
);
}
}
I suggest you can watch 2 examples in this video Pragmatic State Management in Flutter (Google I/O'19)about state mangement. This video helped me a lot when I learn flutter in the begining. They explain how to control the StatefulWidget from the other one:
Make state global, controlled by another widget (from 5m30s)
Use Provider, which is a very popular solution in Flutter, to control share the value between 2 widgets (from 15m05s)
You you have more time, you can study more fancy state management method like Bloc, MobX (List of state management approaches) or even the advance version of Provider named riverpod just pushish few months ago, which try to resolve some cons when using Provider.

In Dart/Flutter, how do I use a variable from a method so I can ouput it to a text field

Hope somebody can help - I hit this dead end a few weeks ago and think that I've tried everything within my limited knowledge.
I've set up a database that works OK - that is I can add data on one screen, review the data and edit the data on another screen. Now I want to sum one of the columns (beef) which I've been able to do as proven in the 'debugPrint' to the console. I want to access this variable 'beefTotal' from the 'sumBeef' method and print show this in a text field in the UI. I just can't manage it though. It just returns null.
Thanks in advance for any help.
import 'package:flutter/material.dart';
import 'package:take_note/utils/database_helper.dart';
class Info extends StatefulWidget {
#override
State<StatefulWidget> createState() => _InfoState();
}
DatabaseHelper helper = DatabaseHelper();
var database = DatabaseHelper();
class _InfoState extends State<Info> {
List beefTotal;
#override
Widget build (BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Beef Info"),
backgroundColor: Colors.lightBlueAccent,
),
body: Container(
child: Column(
children: <Widget>[
Expanded(
child: Center(
child: RaisedButton(
onPressed: (){
sumBeef();
},
),
),
),
Expanded(
child: Center(
child: Text("Total Beef is: £ $beefTotal", style: TextStyle(
color: Colors.lightBlueAccent,
fontSize: 30.0,
fontWeight: FontWeight.w400
),),
),
),
],
),
)
);
}
void sumBeef () async {
beefTotal = await database.addBeef();
debugPrint("Total beef: $beefTotal");
}
}
The code below is from a class called DatabaseHelper which the method sumBeef() uses
Future<List<Map<String, dynamic>>> addBeef()async{
Database db = await this.database;
var result = await db.rawQuery("SELECT SUM(beef) FROM $table");
return result;
}
```[enter image description here][1]
[1]: https://i.stack.imgur.com/L46Gj.png
Just call
setState({
});
void sumBeef () async {
beefTotal = await database.addBeef();
setState(() {});
debugPrint("Total beef: $beefTotal");
}
and your good! anytime you make a change you have to call setState method to update the ui (rebuild) in flutters case