Search code examples
flutterdartbloccubit

How to ignore state with cubit in flutter?


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?


Solution

  • 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)),
          );
      },
    )