kalaLokia
kalaLokia

Reputation: 131

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

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'];
  }
}

My app looks like this

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

Answers (1)

kalaLokia
kalaLokia

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

Related Questions