@override
Widget build(BuildContext context) {
  return BlocBuilder < TimerBloc, TimerState > (
    buildWhen: (prev, state) => prev.runtimeType != runtimeType,
    builder: (context, state) {
      return Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
//for example here: if (state is TimerInitial)...[
              FloatingActionButton(
                child: Icon(Icons.play_arrow),
                onPressed: () => context
                .read < TimerBloc > ()
                .add(TimerStarted(duration: state.duration)),
              ),
            ],
            if (state is TimerRunInProgress)...[
                FloatingActionButton(
                  child: Icon(Icons.pause),
                  onPressed: () => context.read < TimerBloc > ().add(TimerPaused()),
                ),
                FloatingActionButton(
                  child: Icon(Icons.replay),
                  onPressed: () => context.read < TimerBloc > ().add(TimerReset()),
                )
              ],
              if (state is TimerRunPause)...[
                FloatingActionButton(
                  child: Icon(Icons.play_arrow),
                  onPressed: () =>
                  context.read < TimerBloc > ().add(TimerResumed()),
                ),
                FloatingActionButton(
                  child: Icon(Icons.replay),
                  onPressed: () => context.read < TimerBloc > ().add(TimerReset()),
                ),
              ],
        ],
      );
    });
}

So, I am going through this bloc tutorial https://bloclibrary.dev/#/fluttertimertutorial. And I've stumbled upon strange usage of elipsis '...' in code. It is the more stranger for me, because curly brackets for the if clause are omitted here?

Edit: Originally I removed some code for more clarity but now I realize that I might be omitting some context, so I am posting now full code of this widget build method.


Solution 1: BLKKKBVSIK

This is the spread operator (...) and the null-aware spread operator (...?), introduced in Dart 2.4. Those operators allow you to insert multiple values into a collection.

var list = [1, 2, 3];
var list2 = [0, ...list];
assert(list2.length == 4);

In your example, it allows the list in your if to be inserted in the children property of your Row.

Also, there are no curly brackets because the if contains only 1 statement.

If you're curious, you can learn more about the spread operators here: https://dart.dev/guides/language/language-tour


Solution 2: Amon Chepri

Marking BLKKKBVSIK's as accepted answer. It took me a while to get it (mainly because of wrong analyzer warning about dead code. Just ignore it folks, it's a bug.) but playing with the following code in dartPad was enlightening:

void main() {
  print([
    if (true) ...[1],
    if (false) ...[2, 3],
    if (true) ...[4, 5],
  ]); 
}