Accessing and Modifying a variable from a different classes in flutter dart - flutter

I have a model class which I used to create a object from one of my main stateful class. I have a text field and button in my main class. But they both are completely different stateful class. That is, I have 3 different classes in a dart file (main page, textfield, button). I want to access and modify the object initiated in the build of main page in my textfield and button.
What I did: I have made my object on the top of all classes in my dart file assuming all classes have access to them. That was a success. All classes have access to that object, even value initiated to the object from main page are available in other classes (textfield, button).
Problem what I have now: Even though I have access to those values in the object, I can't modify it to latest value from FancyTextField class regardless StatusButton class updating.
What my project do: I will get some values from firestore database on my main page build and I will pass it to textfield and button in the other two classes., that way it resembles my values on it. And I will save the modified value from textfield and button to the object and upload it to firestore database from main page.
Complete code of the page:
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/painting.dart';
import 'package:flutter/services.dart';
import 'package:om/models/machine.dart';
import 'package:om/utils/kalaicons_icons.dart';
Machine machine;
class WorkshopTool extends StatefulWidget {
final String rotary;
WorkshopTool(this.rotary);
#override
_WorkshopToolState createState() => _WorkshopToolState(rotary);
}
class _WorkshopToolState extends State<WorkshopTool> {
String rotary;
bool _showOnScreen = true;
_WorkshopToolState(this.rotary);
#override
Widget build(BuildContext context) {
var screenSize = MediaQuery.of(context).size;
return FutureBuilder(
future: Firestore.instance
.collection('productionrpt')
.document(rotary)
.get(),
builder: (context, snapshot) {
if (!snapshot.hasData)
return Container(
height: screenSize.height - 50.0,
child: Center(
child: SizedBox(
height: 80.0,
width: 80.0,
child: CircularProgressIndicator(
valueColor:
AlwaysStoppedAnimation<Color>(Colors.green[600]),
strokeWidth: 15.0,
)),
));
machine = Machine.fromMapObjext(snapshot.data);
return Container(
height: screenSize.height - 50.0,
width: screenSize.width,
child: Stack(
children: <Widget>[
SingleChildScrollView(
child: Column(
children: <Widget>[
//To make a empty column space for stack on top
Container(
height: 80.0,
padding: EdgeInsets.only(bottom: 5.0, right: 15.0),
child: Align(
alignment: Alignment.bottomRight,
child: Text(
machine.date,
style: TextStyle(
color: Colors.black,
fontSize: 17.0,
fontStyle: FontStyle.italic,
fontWeight: FontWeight.bold),
),
),
),
FancyTextField('Production'),
FancyTextField('Damages'),
FancyTextField('Plan'),
SizedBox(
height: 20.0,
),
Padding(
padding: EdgeInsets.only(
bottom:
MediaQuery.of(context).viewInsets.bottom)),
],
),
),
Container(
height: 50.0,
decoration: BoxDecoration(
color: Colors.green[400],
borderRadius:
BorderRadius.vertical(top: Radius.circular(15.0))),
),
Align(
alignment: Alignment.bottomRight,
child: Padding(
padding: const EdgeInsets.all(20.0),
child: MaterialButton(
color: Colors.black,
padding: EdgeInsets.only(
top: 10.0, bottom: 10.0, left: 20.0, right: 20.0),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(15.0)),
child: Text(
'UPDATE',
style: TextStyle(
fontSize: 30.0,
fontWeight: FontWeight.bold,
color: Colors.white),
),
onPressed: () {
print('Saved to cloud : ${machine.production}');
firebasePutData();
}),
),
),
Align(
alignment: Alignment.bottomLeft,
child: Padding(
padding: EdgeInsets.all(20.0),
child: StatusButton(),
),
),
Align(
alignment: Alignment.topLeft,
child: IconButton(
icon: Icon(
Icons.close,
size: 40,
color: Colors.black,
),
onPressed: () {
print('Bottomsheet closed');
}),
),
Align(
alignment: Alignment.topCenter,
child: Padding(
padding: const EdgeInsets.all(10.0),
child: Text(
machine.rotary,
style: TextStyle(
color: Colors.black,
fontSize: 20.0,
decoration: TextDecoration.underline,
fontWeight: FontWeight.bold),
),
),
),
Padding(
padding: const EdgeInsets.all(4.0),
child: Align(
alignment: Alignment.topRight,
child: Switch(
value: _showOnScreen,
activeTrackColor: Colors.black54,
activeColor: Colors.black,
inactiveThumbColor: Colors.grey[600],
inactiveTrackColor: Colors.grey[500],
onChanged: (v) {
_showOnScreen = !_showOnScreen;
print('Switch tapped');
}),
),
),
],
),
);
});
}
void firebasePutData() {
Firestore.instance
.collection("productionrpt")
.document(rotary)
.updateData(machine.toMap());
print('Data updated');
}
} //End of main page STATE (a bottom sheet)
//#######################################################################################################
//############ FANCY TEXT FIELD FOR ENTERING MACHINE DATA #################
class FancyTextField extends StatefulWidget {
final String _title;
FancyTextField(
this._title,
);
#override
_FancyTextFieldState createState() => _FancyTextFieldState(this._title);
}
class _FancyTextFieldState extends State<FancyTextField> {
final String _title;
final TextEditingController _ctrl = TextEditingController();
_FancyTextFieldState(this._title);
#override
void initState() {
switch (_title) {
case 'Production':
_ctrl.text = machine.production.toString();
break;
case 'Plan':
_ctrl.text = machine.plan.toString();
break;
case 'Damages':
_ctrl.text = machine.damage.toString();
break;
}
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
height: 125.0,
margin: EdgeInsets.all(8.0),
decoration: BoxDecoration(
color: Colors.green[400],
borderRadius: BorderRadius.circular(15.0),
// boxShadow: [
// BoxShadow(
// blurRadius: 5, color: Colors.green[300], spreadRadius: 5)
// ]
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
_title,
style: TextStyle(
color: Colors.black,
fontSize: 23.0,
fontWeight: FontWeight.bold),
),
Container(
height: 50,
width: 300,
alignment: Alignment.center,
padding: const EdgeInsets.all(5.0),
margin: const EdgeInsets.only(
top: 10.0, bottom: 10, left: 30.0, right: 30.0),
decoration: BoxDecoration(
color: Colors.white70,
borderRadius: BorderRadius.circular(10),
),
child: TextField(
//maxLength: 5,
controller: _ctrl,
textAlign: TextAlign.center,
keyboardType: TextInputType.number,
style: TextStyle(
color: Colors.black,
fontSize: 30.0,
),
decoration: InputDecoration(
border: InputBorder.none,
),
onChanged: (v) {
switch (_title) {
case 'Production':
machine.production = int.parse(_ctrl.text);
break;
case 'Plan':
machine.plan = int.parse(_ctrl.text);
break;
case 'Damages':
machine.damage = int.parse(_ctrl.text);
break;
}
print('Prod: ${machine.production}');
},
),
),
],
),
);
}
} //END OF CLASS FANCY TEXT FIELD
//######################################################################################################
//####### A STATEFUL WIDGET FOR MACHINE STATUS BUTTON : running, off, breakdown ##########
class StatusButton extends StatefulWidget {
#override
_StatusButtonState createState() => _StatusButtonState();
}
class _StatusButtonState extends State<StatusButton> {
Color color;
IconData icon;
#override
Widget build(BuildContext context) {
switch (machine.stats) {
case 0:
color = Colors.grey[600];
icon = Icons.power_settings_new;
break;
case 1:
color = Colors.blue;
icon = Icons.power_settings_new;
break;
default:
color = Colors.red;
icon = Kalaicons.breakdown;
break;
}
return Container(
height: 70.0,
width: 70.0,
decoration: BoxDecoration(
color: color,
shape: BoxShape.circle,
),
child: IconButton(
icon: Icon(
icon,
color: Colors.white,
size: 50.0,
),
onPressed: () {
setState(() {
machine.stats > 1 ? machine.stats = 0 : machine.stats++;
print('Status button pressed: ${machine.stats}');
});
},
));
}
} //END OF CLASS STATUS BUTTON
My model:
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:intl/intl.dart';
class Machine {
int _production;
int _plan;
int _damage;
int _stats = 0;
String _date = '~Not available';
String _rotary;
// Machine(this._production, this._damage, this._date,
// [this._stats, this._plan]);
int get production => this._production;
int get plan => this._plan;
int get damage => this._damage;
int get stats => this._stats;
String get date => this._date;
String get rotary => this._rotary;
set production(int updatedValue) {
if (updatedValue != null) {
this._production = updatedValue;
}
}
set plan(int updatedValue) {
if (updatedValue != null) {
this._plan = updatedValue;
}
}
set damage(int updatedValue) {
if (updatedValue != null) {
this._damage = updatedValue;
}
}
set stats(int updatedValue) {
this._stats = updatedValue;
}
// set date(String updatedValue) {
// this._date = DateFormat.jm().format(DateTime.now());
//
// }
//Function to set a map list of new data for firebase
Map<String, dynamic> toMap() {
var map = Map<String, dynamic>();
map['production'] = this._production;
map['plan'] = this._plan;
map['damages'] = this._damage;
map['stats'] = this._stats;
map['date'] = DateFormat("MMMM dd, hh:mm a").format(DateTime.now());
return map;
}
//Constructor to extract firebase collections
Machine.fromMapObjext(DocumentSnapshot map) {
this._production = map['production'];
this._plan = map['plan'];
this._damage = map['damages'];
this._stats = map['stats'];
this._date = map['date'];
this._rotary = map['machine'];
}
}
UPDATE I RECENTLY NOTED: The value of StatusButton is gettiong updated to the object and to firestore. however value of updated FancyTextField only reflects inside that class itself. Not updating globally.

Lastly I found the issue myself rolling 3 days with it. Issue was happened because when keyboard pops, the widget also gets it state rebuild. Since I had my firebase data on FutureBuilder in the build, my old data was recalled from the firebase again and save it on top of newly edited data.
Why initial text I put on the TextField didn't changed ?
Because I had it set it on my initState of FancyTextField class, so when rebuilding widget I won't execute and my edited value stays as before.
Why StatusButton value updated without failing ?
Because when I tap on the button keyboard doesn't pops up and build wasn't rebuild again. But later I noticed, after changing my StatusButton status to someother value and tapping on TextField makes it to OLD value (that is the value that is in firebase currently). Since build is recreated. That's how I figured it out.
What I did to overcome this:
I simply removed my FutureBuilder which gets data from firebase, and created a Future for the same and initiated in the initState.
If anyone want, I can show the updated code here

Related

Flutter responsive Row or Row alternative suggestions

I'm pretty new to Flutter, and I wanted to create a folder effect with tabs for my portfolio website where you click on the tabs to change what displayed in the center of the folder. Right now the buttons are dynamically generated as children of a row widget. The problem is that at smaller screen widths the text is either too small or gets cut off altogether. I even tried to figure out how to do a sort of multi-line row but gave up.
What I would ideally like is that the buttons wrap such that any buttons that would make the parent too long are placed on a separate row. However, I'm open to any solution that allows all the tabs to fit on screen without the text in the buttons being super shrunk.
My current solutions as you can see is to just scale the text down at smaller screen widths so that its all at least visible. I'm guessing that I'm either going to have redesign the way I implement the effect, or there's some relatively simple solution that I'm not aware of. I also tried replacing the Row widget that wraps the FolderButtons to a Wrap with no other modifications and that just caused the text to disappear.
Note: The way its currently implemented assumes and depends upon the folder being a perfect square.
Below are Folder, FolderButton, and ScaleSize classes respectively:
class Folder extends StatefulWidget {
const Folder({super.key});
static Column? getStaticPages(String page, BuildContext context) {
Map<String, Column> pages = {
"Welcome": Column(
children: [
Text(
'Welcome',
style: TextStyle(color: Colors.deepPurpleAccent.shade100),
)
],
),
"Web Dev's Handbook": Column(
children: [
Text(
"Web Dev's Handbook",
style: TextStyle(color: Colors.deepPurpleAccent.shade100),
),
TextButton(
onPressed: () => {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => const Contents()))
},
child: const Text("Go"))
],
),
"Interactive Resume": Column(
children: [
Text(
'Interactive Resume',
style: TextStyle(color: Colors.deepPurpleAccent.shade100),
)
],
),
"Settings": Column(
children: [
Text(
'Settings',
style: TextStyle(color: Colors.deepPurpleAccent.shade100),
)
],
),
"Credits": Column(
children: [
Text(
'Credits',
style: TextStyle(color: Colors.deepPurpleAccent.shade100),
)
],
),
};
return pages[page];
}
static List<Map<String, dynamic>> staticTabs = [
{"title": "Welcome"},
{"title": "Web Dev's Handbook"},
{"title": "Interactive Resume"},
{"title": "Settings"},
{"title": "Credits"},
];
static List<FolderButton> generateTabs(int selectedTab, Function setTab) {
List<FolderButton> newTabs = [];
for (int x = 0; x < staticTabs.length; x++) {
bool selected;
if (selectedTab == x) {
selected = true;
} else {
selected = false;
}
newTabs.add(FolderButton(
title: staticTabs[x]["title"],
count: x,
selected: selected,
setTab: setTab));
}
return newTabs;
}
#override
State<Folder> createState() => _FolderState();
}
class _FolderState extends State<Folder> {
int _selectedTab = 0;
void _setTab(int count) {
setState(() {
_selectedTab = count;
});
}
#override
Widget build(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.only(left: 1, right: 1, top: 20),
child: SizedBox(
height: 750,
width: 750,
child: Column(
children: [
Flexible(
flex: 1,
child: Padding(
padding: const EdgeInsets.only(left: 7.0),
child: Row(
children: Folder.generateTabs(_selectedTab, _setTab),
),
),
),
Flexible(
flex: 15,
fit: FlexFit.tight,
child: Container(
decoration: BoxDecoration(
color: Colors.deepPurpleAccent,
borderRadius: BorderRadius.circular(5)),
child: Padding(
padding: const EdgeInsets.all(5.0),
child: Container(
width: 800,
decoration:
const BoxDecoration(color: Colors.deepPurple),
child: Folder.getStaticPages(
Folder.staticTabs[_selectedTab]["title"], context)),
),
),
),
],
),
),
),
);
}
}
class FolderButton extends StatefulWidget {
const FolderButton(
{super.key,
required this.title,
required this.count,
this.selected = false,
required this.setTab});
final String title;
final int count;
final bool selected;
final Function setTab;
static final theme = <String, dynamic>{
"button": <String, dynamic>{
"picked": <bool, ButtonStyle>{
true: TextButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5), topRight: Radius.circular(5)),
side: BorderSide(
color: Colors.deepPurpleAccent,
strokeAlign: StrokeAlign.outside))),
false: TextButton.styleFrom(
backgroundColor: Colors.deepPurple,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(5), topRight: Radius.circular(5)),
side: BorderSide(
color: Colors.deepPurple, strokeAlign: StrokeAlign.outside)),
),
}
},
// TODO Make it so I don't need to do it like this
"padding": <bool, dynamic>{
true: const EdgeInsets.only(top: 3, left: 3, right: 3),
false: const EdgeInsets.only(top: 3, left: 3, right: 3)
}
};
static Color? getTabShading(selected) {
if (selected) {
return Colors.deepPurpleAccent;
}
return Colors.deepPurple;
}
static EdgeInsetsGeometry getTabPadding(selected) {
return theme["padding"][selected];
}
#override
State<FolderButton> createState() => _FolderButtonState();
}
class _FolderButtonState extends State<FolderButton> {
void changeSelected() {}
#override
Widget build(BuildContext context) {
return Flexible(
child: Container(
height: 100,
// Button Container
decoration: BoxDecoration(
// Container Decorations
color: FolderButton.getTabShading(widget.selected),
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(5),
topRight: Radius.circular(5),
)),
// Button Padding
child: Padding(
padding: FolderButton.getTabPadding(widget.selected),
// Button
child: TextButton(
onPressed: () {
widget.setTab(widget.count);
},
// Style of button itself
style: FolderButton.theme["button"]?["picked"][widget.selected],
child: Text(
textAlign: TextAlign.center,
textScaleFactor: ScaleSize.textScaleFactor(context,
maxTextScaleFactor: 1.5),
// Text of the button
widget.title,
style: TextStyle(
color: Colors.deepPurpleAccent.shade100,
fontSize: 10,
height: 1))),
),
),
);
}
}
class ScaleSize {
static double textScaleFactor(BuildContext context,
{double maxTextScaleFactor = 2}) {
final width = MediaQuery.of(context).size.width;
double val = (width / 1400) * maxTextScaleFactor;
return max(1, min(val, maxTextScaleFactor));
}
}
Any general flutter tips, tricks, conventions, and/or all-around good ideas are appreciated.
Perhaps Wrap widget is what you need. It works just like a Row until you reach the limit of the horizontal size, and then places the next widget in a new "Row" below the previous.
Try using Expanded as a child for Row/Column or whatever you need there. I'm giving you a brief description from the flutter page. I think that for text that does not have a specific width it will be good.
https://api.flutter.dev/flutter/widgets/Expanded-class.html
The answer is simply to rebuild the component with Wrap as the parent to the Buttons as it wrap overflowing children below the rest. I will also be sure to maintain a bit more forethought in terms of responsive layout design while making use of the responsive framework package.

How To Use Shared Preference In This Todo App Code?

import 'package:flutter/material.dart';
import '../main.dart';
import 'colors.dart';
import 'todo_item.dart';
import 'todo.dart';
import 'package:shared_preferences/shared_preferences.dart';
class Toodoo extends StatefulWidget {
const Toodoo({Key? key}) : super(key: key);
#override
State<Toodoo> createState() => _ToodooState();
}
class _ToodooState extends State<Toodoo> {
final todosList = ToDo.todoList();
List<ToDo> _foundToDo = [];
final _todoController = TextEditingController();
final GlobalKey<ScaffoldState> _key = GlobalKey();
String ""
#override
void initState() {
_foundToDo = todosList;
super.initState();
}
#override
Widget build(BuildContext context) {
return Scaffold(
key: _key,
appBar: AppBar(
leading: IconButton(
icon: const Icon(Icons.menu, color: Colors.black),
onPressed: () => _key.currentState!.openDrawer(),
),
backgroundColor: const Color(0xff346594),
title: const Text("ToDos", style: TextStyle(color: Colors.black)),
),
backgroundColor: tdBGColor,
body: Stack(
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 15,
),
child: Column(
children: [
searchBox(),
Expanded(
child: ListView(
children: [
Container(
margin: const EdgeInsets.only(
top: 50,
bottom: 20,
),
child: const Text(
'All ToDos',
style: TextStyle(
fontSize: 20,
fontWeight: FontWeight.w500,
),
),
),
for (ToDo todo in _foundToDo.reversed)
ToDoItem(
todo: todo,
onToDoChanged: _handleToDoChange,
onDeleteItem: _deleteToDoItem,
),
],
),
)
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: Row(children: [
Expanded(
child: Container(
margin: const EdgeInsets.only(
bottom: 20,
right: 20,
left: 20,
),
padding: const EdgeInsets.symmetric(
horizontal: 20,
vertical: 5,
),
decoration: BoxDecoration(
color: Colors.white,
boxShadow: const [
BoxShadow(
color: Colors.grey,
offset: Offset(0.0, 0.0),
blurRadius: 10.0,
spreadRadius: 0.0,
),
],
borderRadius: BorderRadius.circular(10),
),
child: TextField(
controller: _todoController,
decoration: const InputDecoration(
hintText: 'Add a new todo item',
border: InputBorder.none),
),
),
),
Container(
margin: const EdgeInsets.only(
bottom: 20,
right: 20,
),
child: ElevatedButton(
onPressed: () {
_addToDoItem(_todoController.text);
},
style: ElevatedButton.styleFrom(
backgroundColor: tdBlue,
minimumSize: const Size(60, 60),
elevation: 10,
),
child: const Text('+', style: TextStyle(fontSize: 40),),
),
),
]),
),
],
),
drawer: const Navigation(),
);
}
void _handleToDoChange(ToDo todo) {
setState(() {
todo.isDone = !todo.isDone;
});
}
void _deleteToDoItem(String id) {
setState(() {
todosList.removeWhere((item) => item.id == id);
});
}
void _addToDoItem(String toDo) async{
final sp = await SharedPreferences.getInstance();
setState(() {
todosList.add(ToDo(
id: DateTime.now().millisecondsSinceEpoch.toString(),
todoText: toDo,
));
});
sp.setString(id, todo)
_todoController.clear();
}
void _runFilter(String enteredKeyword) {
List<ToDo> results = [];
if (enteredKeyword.isEmpty) {
results = todosList;
} else {
results = todosList
.where((item) => item.todoText!
.toLowerCase()
.contains(enteredKeyword.toLowerCase()))
.toList();
}
setState(() {
_foundToDo = results;
});
}
Widget searchBox() {
return Container(
);
}
}
I am trying to save todo data locally, using shared preferences but don't know how to implement this, any help on this will be appreciated.Shared preferences is the best thing to use in such apps, so that's why I am using shared preference instead of firebase.
I have initialized Shared preferences in future but the thing is how to read and show the data with the controller given above the code.
Use Hive database or sqflite to save such kind of data(Good practice).You should use shared preference to store small bunch of data.
Yeah, shared preference is a good way to store data permanently on the local device. I can suggest you one way of doing this.
You need to create only one key (and value), and the value would be a stringified array. Every time user created new todo, you first need to pull the previous array, parse it to JSON, push the latest todo in that array, and set the key value again.
This array will also help you if you want to show the user all the todos by pulling the data only from one key, cause all the todos will the store in one array.
var todos = [
{
"id": "",
"todoText": "''"
},
{
"id": "",
"todoText": "''"
},
...
]
But you need to store stringified array, so you need to parse back to JSON after get data from shared preferences

How to get data from firestore to List on flutter?

I wrote the code to get data from List to chips and when click chips the colour changed to blue. But I want to fetch data from firestore instead "words list".
Instead this words list ...
Database collection image
I want to display "WordName" field in the chips.
My code..
class uitry extends StatefulWidget {
const uitry({Key? key}) : super(key: key);
#override
State<uitry> createState() => _uitryState();
}
class _uitryState extends State<uitry> {
List<String> wordList = [
'Shopping',
'Brunch',
'Music',
'Road Trips',
'Tea',
'Trivia',
'Comedy',
'Clubbing',
'Drinking',
'Wine',
];
List<String> selectedWord = [];
List<String>? deSelectedWord = [];
#override
Widget build(BuildContext context) {
double height = MediaQuery.of(context).size.height;
double width = MediaQuery.of(context).size.width;
return Scaffold(
body: Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage(Config.app_background4), fit: BoxFit.fill),
),
child: SafeArea(
child: Center(
child: Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.only(top: 14, right: 0),
child: Column(
children: [
SizedBox(
width: width * 0.94,
height: height * 0.30,
child: Column(
children: <Widget>[
const SizedBox(height: 16),
Wrap(
children: wordList.map(
(word) {
bool isSelected = false;
if (selectedWord!.contains(word)) {
isSelected = true;
}
return GestureDetector(
onTap: () {
if (!selectedWord!.contains(word)) {
if (selectedWord!.length < 50) {
selectedWord!.add(word);
deSelectedWord!.removeWhere(
(element) => element == word);
setState(() {});
print(selectedWord);
}
} else {
selectedWord!.removeWhere(
(element) => element == word);
deSelectedWord!.add(word);
setState(() {
// selectedHobby.remove(hobby);
});
print(selectedWord);
print(deSelectedWord);
}
},
child: Container(
margin: const EdgeInsets.symmetric(
horizontal: 5, vertical: 4),
child: Container(
padding: const EdgeInsets.symmetric(
vertical: 5, horizontal: 12),
decoration: BoxDecoration(
color: isSelected
? HexColor('#0000FF')
: HexColor('#D9D9D9'),
borderRadius: BorderRadius.circular(18),
border: Border.all(
color: isSelected
? HexColor('#0000FF')
: HexColor('#D9D9D9'),
width: 2)),
child: Text(
word,
style: TextStyle(
color: isSelected
? Colors.black
: Colors.black,
fontSize: 14,
fontWeight: FontWeight.w600),
),
),
),
);
},
).toList(),
),
],
),
),
],
),
),
],
))),
),
);
}
}
How get that from firestore? I hope You can understand what I ask. Thank you!
I would do the following:
Initialize your list of words to an empty list
Use the initState method of the stateful widget to make a call to firestore to fetch all the documents that have the wordName property and get the word from the result and set it to a new list
Assign the new list to the wordList property and setState to re-render.
This would be it to get the words and set the chips with fetched words.
Keep in mind that since you are making an async call to firestore you should show some form of loading to tell the user you are fetching the data otherwise you would show and empty chip list until you fetch the data.

Flutter- Why I can't see the data inside the Dropdown

I'm new to Flutter and I can't understand why I can't see the data inside the DropDownButton even tho the lists that I use to create the DropDownButton have the data inside them. Can anyone explain to me why is this happening? The only clue I have is that the DropDownButton starts the creation before I create the list from which is taking the data.
The problem is that my dropdown list is empty.
I provide the entire code below.
Code :
import 'package:flutter/material.dart';
import 'ListOfClienti.dart';
class CreateClient extends StatefulWidget {
#override
_CreateClientState createState() => _CreateClientState();
}
class _CreateClientState extends State<CreateClient> {
String ClientCod = '';
String currentClient = '';
List<String> listNameOfClients = [];
List<DropdownMenuItem<String>> actualList2 = [];
void getClientsName() {
for (var i = 0; i <= ListDatabase.length - 1; i++) {
var name = ListDatabase[i].nome;
print(name);
listNameOfClients.add(name);
}
}
void createListWithClientName() {
for (String oneByOneClient in listNameOfClients) {
var VariableToInsert2 = DropdownMenuItem(
child: Text(oneByOneClient),
value: oneByOneClient,
);
actualList2.add(VariableToInsert2);
}
}
//Method that allows me to create the DropDownButton
DropdownButton<String> createNameMachine() {
return DropdownButton(
items: actualList2,
style: TextStyle(
color: Colors.black,
fontFamily: 'Keqima',
fontSize: 15,
),
value: currentClient,
onChanged: (clientSelected) {
setState(() {
currentClient = clientSelected;
});
},
);
}
#override
Widget build(BuildContext context) {
return Container(
color: Color(0xff757575),
child: Container(
decoration: BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20),
),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Padding(
padding: EdgeInsets.all(16),
child: TextField(
decoration: InputDecoration(
border: OutlineInputBorder(),
labelText: 'Inserisci il codice cliente',
),
onChanged: (textInsideTheField) {
ClientCod = textInsideTheField;
},
),
),
Padding(
padding: EdgeInsets.all(16),
child: Row(
children: <Widget>[
FlatButton(
onPressed: () {
getClientsName();
createListWithClientName();
print(actualList2.length);
},
child: Text(
'Clienti : ',
style: TextStyle(
fontSize: 20,
fontFamily: 'Keqima',
),
),
),
SizedBox(
width: 20,
),
createNameMachine(),
],
),
),
],
),
),
);
}
}
To fix this problem I had to change to things :
Thing: I had to change the List from this List listNameOfClients = []; to this List listNameOfClients = [''];
I had to integrate the setState and inside to call the functions.
setState(() {
getClientsName();
createListWithClientName();
});

flutter radiovalue not changing

I'm trying to get a very simple set of radiobuttons up, which is why it's so frustrating that they aren't working. I've tried setting this up in a similar class, and it's worked. I know for a fact that setstate is being called, but for some reason it's not updating the individual radio button. Which makes me think that this is some weird issue related to state.
Anyways, all help would be appreciated. My main class is the second part of the code below.
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../bloc/thembloc.dart';
import './components/textfield.dart';
class SignUp extends StatefulWidget {
#override
_SignUpState createState() => _SignUpState();
}
class _SignUpState extends State<SignUp> {
/*
ui for signup
includes multiple textfields.
includes all of the information that we'll need
to collect for an user to register an account.
todo: wrap everything in a form, encrypt it and send it to a private server.
*/
#override
Widget build(BuildContext context) {
double _height = MediaQuery.of(context).size.height;
double _width = MediaQuery.of(context).size.width;
final double _margin = 16.0;
final double _promptWidth = _width - 32.0;
final double _promptHeight = _height - 32.0;
final double _textFieldWidth = _promptWidth - 32.0;
int subscriberValue;
void switchSubscriber(int value) {
setState(() {
subscriberValue = value;
});
}
return BlocBuilder(
bloc: BlocProvider.of<ThemeBloc>(context),
builder: (context, ThemeState state) {
return Scaffold(
resizeToAvoidBottomInset: false,
resizeToAvoidBottomPadding: false,
appBar: AppBar(
centerTitle: true,
title: Text(
"smartmoney",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.display2,
),
// appbar
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.only(
bottomLeft: Radius.circular(8.0),
bottomRight: Radius.circular(8.0))),
leading: IconButton(
icon: Icon(
Icons.arrow_back,
color: BlocProvider.of<ThemeBloc>(context).currentState.themedata.buttonColor,
),
onPressed: () {
print("going back");
},
),
backgroundColor: BlocProvider.of<ThemeBloc>(context).currentState.themedata.canvasColor,
),
body: Container(
height: _height,
width: _width,
color: BlocProvider.of<ThemeBloc>(context).currentState.themedata.backgroundColor,
child: Column(
children: <Widget>[
Padding(
padding: EdgeInsets.only(top: _margin),
child: Container(
decoration: BoxDecoration(
borderRadius: BorderRadius.all(Radius.circular(8.0)),
color: BlocProvider.of<ThemeBloc>(context).currentState.themedata.canvasColor,
boxShadow: [
BoxShadow(
spreadRadius: 0.0,
color: Colors.black38,
blurRadius: 6.0,
offset: Offset(0.0, 3.0)),
]),
width: _promptWidth,
height: _promptHeight - 48 - _margin,
child: Column(
children: <Widget>[
Text("Let's get started",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.display2,
),
Text("Enter your information to create an account",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.subtitle,
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "First name",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Last name",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Email",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Password",
),
),
Padding(
padding: EdgeInsets.only(top: 8.0),
child: StyledTextField(
textFieldWidth: _textFieldWidth,
helperText: "Phone number",
),
),
Text("Subscriber type",
style: BlocProvider.of<ThemeBloc>(context).currentState.themedata.primaryTextTheme.display1,
),
Radio(
groupValue: subscriberValue,
value: 0,
onChanged: (int value) => switchSubscriber(value),
),
Radio(
groupValue: subscriberValue,
value: 1,
onChanged: (int value) => switchSubscriber(value),
)
],
),
),
)
],
),
),
);
});
}
}
import 'package:flutter/material.dart';
import './bloc/thembloc.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'ui/signin.dart';
import 'ui/signup.dart';
import 'ui/onboarding.dart';
import './ui/testing/whatthefuck.dart';
void main() {
runApp(
MaterialApp(
home: SmartMoney(),
)
// SmartMoney()
);
}
class SmartMoney extends StatefulWidget {
#override
_SmartMoneyState createState() => _SmartMoneyState();
}
class _SmartMoneyState extends State<SmartMoney> {
final _themeBloc = ThemeBloc();
#override
Widget build(BuildContext context) {
return BlocProvider(
bloc: _themeBloc,
child: SignUp(),
);
}
}
The problem is because you defined your variable subscriberValue inside your build method. You're using setState calls that recall build method and in every recall of build you're losing the value of subscriberValue. I advise you to always use variables that will control the state of your widget as class members.
class _SignUpState extends State<SignUp> {
// HAS TO BE CLASS MEMBER AND IT'S GOOD AN INITIAL VALUE TOO..
int subscriberValue =1; // asuming that 1 is default radio button option
#override
Widget build(BuildContext context) {
//... some codes ...
//int subscriberValue; REMOVE THIS LINE. YOU'RE LOSING THE VALUE IN EVERY setState call
//You can define this method outside from build too.
void switchSubscriber(int value) {
setState(() {
subscriberValue = value;
});
}
}