0

I'm using cubit to manage state of widgets, and I want to make widget updated only when specific type of state is emitted.

part of 'TestData.dart';

@immutable
abstract class TestState {}

class TestInitial extends TestState {}

class TestValueUpdated extends TestState {
  TestValueUpdated(this.message);
  
  final String message;

  @override
  bool operator ==(Object other) {
    return other is TestValueUpdated && other.message == message;
  }

  @override
  int get hashCode => message.hashCode;
}

class TestScaleUpdated extends TestState {
  TestScaleUpdated(this.message);

  final String message;

  @override
  bool operator ==(Object other) {
    return other is TestScaleUpdated && other.message == message;
  }

  @override
  int get hashCode => message.hashCode;
}

I created state class called TestState, and this class currently having 3 states : initial, value updated, scale updated

class TestData extends Cubit<TestState> {

//Codes here

  Future<void> keepPlayStatus() async {
    emit(TestValueUpdated(getTimeStamp()+" / "+getMaxTime()+"  |  "+getPosition()));
  }

  Future<void> updateScaleValueMessage() async {
    emit(TestScaleUpdated((size * 100).round().toInt().toString() + " %"));
  }
}

and this class called TestData uses TestState and extends Cubit.

Basically, when user updates zoom value by pinching the screen, this class will emit TestScaleUpdated state, and when user plays something, it will emit TestValueUpdated state.

and in UI,

//somewhere of the codes, called widget A
child: BlocBuilder<TestData, TestState>(
  builder: (context, state) {
    if(state is TestValueUpdated) {
      return Text(
        state.message,
        textAlign: TextAlign.end,
        style: TextStyle(color: ThemeManager.getRGBfromHex(0x514745)),
      );
    } else {
      return Text(
        "00:00.000 / 00:04.800 | 1.1.1",
        textAlign: TextAlign.end,
        style: TextStyle(color: ThemeManager.getRGBfromHex(0x514745)),
      );
    }
  },
)

//the other part of the codes, called widget B
child: BlocBuilder<TestData, TestState>(
  builder: (context, state) {
    if(state is TestScaleUpdated) {
      return Text(
        state.message,
        textAlign: TextAlign.center,
        style: TextStyle(color: ThemeManager.getRGBfromHex(0x514745)) ,
      );
    } else {
      return Text(
        "100 %",
        textAlign: TextAlign.center,
        style: TextStyle(color: ThemeManager.getRGBfromHex(0x514745)) ,
      );
    }
  },
)

I tried this code. These 2 widgets update their status when TestData emits some state. Problem for this code is that, if user plays something, since TestScaleUpdated state won't be emitted, widget B's status goes back to initial state, showing "100 %" always.

If user updates scale, then TestValueUpdated won't be emitted, so widget A will always have initial state, showing "00:00.000 / 00:04.800 | 1.1.1".

So what I want to perform now is that, I want to make widget ignore status update. For example, in builder of BlocBuilder

(context, state) {
  if(state is TestScaleUpdated) {
    return Text("Scale!");
  else if(state is TestInitial) {
    return Text("Initial!");
  } else {
    //ignore, or keep widget's status
  }
}

Problem here, if I explain more detailed, is this : Let's assume that user played something, so widget A's text is changed to 00:10.000 / 00:40.000 | 2.0.0.

Then when user tries to change scale value, not only widget B affected, but also widget A gets affected. But since TestData emitted only TestScaleUpdated state, widget A's text gets back to 00:00.000 | 00:04.800 | 1.1.1 while it should keep its text, and status.

I want to make only widget B updated when TestScaleUpdated is emitted, and make only widget A updated when TestValueUpdated is emitted. Simply, managing 2 or more widgets differently with one cubit class.

Do I have to merge these 2 states : TestScaleUpdated, and TestValueUpdated into 1 state containing 2 message for each widget?

or can I keep status of widget if emitted state doesn't satisfy specific condition?

Mandarin Smell
  • 391
  • 2
  • 17

1 Answers1

1

I would create one state which has all the required information. But if you just want the widgets to rebuild only in certain situations, then you can do it like this for your Widget A:

BlocBuilder<TestData, TestState>(
  buildWhen: (oldState, newState) => newState is TestValueUpdated;
  builder: (context, state) {
      return Text(
        state is TestValueUpdated ? state.message : "00:00.000 / 00:04.800 | 1.1.1",
        textAlign: TextAlign.end,
        style: TextStyle(color: ThemeManager.getRGBfromHex(0x514745)),
      );
  },
)
Mäddin
  • 1,070
  • 6
  • 11
  • Umm, I should explain situation more detailed. Let's assume that widget A's text was `00:10:000 / 00:40.000 | 2.0.0`. But then, when user changes scale, widget A's text gets back to `00:00.000 / 00:04.800 | 1.1.1` while it should keep its time, and numbers. I want to make only widget B updated when `TestScaleUpdated` state is emitted. I can merge 2 states into 1 state, containing all required data both for widget A and B, but I don't want to create unnecessary *data*. Is merging states, making one that containing all data the only way? – Mandarin Smell May 20 '21 at 16:30
  • Merging states is usefull but maybe it is enough to implement my above solution, since widget A then rebuilds, for example, only when the state changes accordingly. But I would do both: Implementing the buildWhen-Function of BlocBuilder and having a state which is holding all the required data. – Mäddin May 20 '21 at 16:40
  • 1
    Oh, sorry, I saw `buildWhen` now. Yes, I wanted such thing. Thanks a lot, I will accept your answer – Mandarin Smell May 20 '21 at 16:42