Reputation: 131
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.
Upvotes: 1
Views: 4399
Reputation: 131
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
Upvotes: 2