Deven Joshi

How to Add a Messenger-like Chess Game to Your Flutter Chat App

Learn how to add a playable chess game to your Flutter app.

Add to Pieces

Learn how you can add a playable chess game to your Flutter chat app.

Setting Up Your Chat Functionality

Tags: flutter,  dart,  apikey

Initialize Stream Chat Flutter, connect a user, and watch a channel for changes.
Display the channel messages using the MessageListView widget.
Add a MessageInput widget to be able to send a message to the aforementioned channel.

import 'package:flutter/material.dart';
import 'package:stream_chat_flutter/stream_chat_flutter.dart';

void main() async {
  WidgetsFlutterBinding.ensureInitialized();

  final client = StreamChatClient(
    'YOUR_API_KEY',
    logLevel: Level.INFO,
  );

  await client.connectUser(
    User(id: 'YOUR_USER_ID'),
    '''YOUR_USER_TOKEN''',
  );

  final channel = client.channel('messaging', id: 'YOUR_CHANNEL_ID');

  await channel.watch();

  runApp(
    MyApp(
      client: client,
      channel: channel,
    ),
  );
}

class MyApp extends StatelessWidget {

  const MyApp({
    Key? key,
    required this.client,
    required this.channel,
  }) : super(key: key);

  final StreamChatClient client;

  /// Instance of the Channel
  final Channel channel;

  @override
  Widget build(BuildContext context) => MaterialApp(
        theme: ThemeData.light(),
        darkTheme: ThemeData.dark(),
        builder: (context, widget) => StreamChat(
          client: client,
          child: widget,
        ),
        home: StreamChannel(
          channel: channel,
          child: const ChannelPage(),
        ),
      );
}

class ChannelPage extends StatefulWidget {
  const ChannelPage({
    Key? key,
  }) : super(key: key);

  @override
  State createState() => _ChannelPageState();
}

class _ChannelPageState extends State {
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
        appBar: const ChannelHeader(),
        body: Column(
          children: [
            const Expanded(
              child: MessageListView(),
            ),
            MessageInput(
              attachmentLimit: 3,
            ),
          ],
        ),
      );
  }
}

Related links:

  1. https://medium.com/@dev.n/how-to-add-a-messenger-like-chess-game-to-your-flutter-chat-app-965f1af25aa
  2. https://www.becomebetterprogrammer.com/typescript-pick-type/
  3. https://getstream.io/chat/docs/sdk/flutter/guides/adding_custom_attachments/
  4. https://www.facebook.com/messenger/posts/check-this-out-you-can-now-play-chess-inside-of-messenger-to-start-a-game-type-f/889510314501983/
  5. https://getstream.io/chat/sdk/flutter/

Model Class for Attachment in Message

Tags: flutter,  reactjs, javascript, dart

The Chess class in the flutter_chess_board packages gives us a .fengetter which converts the current game into FEN format. You can convert this back to a Chess object using Chess.fromFEN().

import 'package:flutter_chess_board/flutter_chess_board.dart';

class ChessAttachment {
  final Chess game;
  final String whiteUserId;


ChessAttachment({required this.game, required this.whiteUserId});

factory ChessAttachment.fromJson(Map json) {
    return ChessAttachment(
      game: Chess.fromFEN(json['game'] as String),
      whiteUserId: json['white_user_id'] as String,
    );
  }


Map toJson() {
    return {
      'game': game.fen,
      'white_user_id': whiteUserId,
    };
  }


ChessAttachment copyWith({
    Chess? game,
    String? whiteUserId,
  }) {
    return ChessAttachment(
      game: game ?? this.game,
      whiteUserId: whiteUserId ?? this.whiteUserId,
    );
  }
}


Related links:

  1. https://medium.com/@dev.n/how-to-add-a-messenger-like-chess-game-to-your-flutter-chat-app-965f1af25aa
  2. https://www.becomebetterprogrammer.com/typescript-pick-type/
  3. https://getstream.io/chat/docs/sdk/flutter/guides/adding_custom_attachments/
  4. https://www.facebook.com/messenger/posts/check-this-out-you-can-now-play-chess-inside-of-messenger-to-start-a-game-type-f/889510314501983/
  5. https://getstream.io/chat/sdk/flutter/

Setting up Message Input with Action Button

Tags: qt,  dart, flutter, opengl, c++

The UI required for playing chess requires a way to trigger the start of a game. This will take the form of a button in the MessageInput actions argument.

GlobalKey _mipKey = GlobalKey();

@override
Widget build(BuildContext context) {
  return Scaffold(
    appBar: const ChannelHeader(),
    body: Column(
      children: [
        const Expanded(
          child: MessageListView(),
        ),
    MessageInput(
          key: _mipKey,
          attachmentLimit: 3,
          actions: [
           IconButton(
             onPressed: () {},
              icon: const Icon(Icons.videogame_asset_outlined),
              padding: const EdgeInsets.all(0),
              constraints: const BoxConstraints.tightFor(
                height: 24,
                width: 24,
              ),
              splashRadius: 24,
            ),
          ],
        ),
      ],
    ),
  );
}


Related links:

  1. https://medium.com/@dev.n/how-to-add-a-messenger-like-chess-game-to-your-flutter-chat-app-965f1af25aa
  2. https://www.becomebetterprogrammer.com/typescript-pick-type/
  3. https://getstream.io/chat/docs/sdk/flutter/guides/adding_custom_attachments/
  4. https://www.facebook.com/messenger/posts/check-this-out-you-can-now-play-chess-inside-of-messenger-to-start-a-game-type-f/889510314501983/
  5. https://getstream.io/chat/sdk/flutter/

Adding an Attachment to the Message Input State

Tags: typescript,  flutter, dart

Creating a new Chess object to store our chess game is a good start. You can get the current user ID to set the player playing white (you can change this in your implementation to have someone else as white or the current player playing as black). Finally, you can create a ChessAttachment model object which takes in the two aforementioned objects.The last section attached a GlobalKey to the MessageInput. This key is now used for accessing the current state of the MessageInput and adding an attachment.

IconButton(
  onPressed: () {
    var newGame = Chess();
    var userId = StreamChat.of(context).currentUser!.id;
    var attachment = ChessAttachment(game: newGame, whiteUserId: userId);


_mipKey.currentState?.addAttachment(
      Attachment(
        type: 'chess',
        uploadState: const UploadState.success(),
        extraData: attachment.toJson(),
      ),
    );
  },
  icon: const Icon(Icons.videogame_asset_outlined),
  padding: const EdgeInsets.all(0),
  constraints: const BoxConstraints.tightFor(
    height: 24,
    width: 24,
  ),
  splashRadius: 24,
),

Related links:

  1. https://medium.com/@dev.n/how-to-add-a-messenger-like-chess-game-to-your-flutter-chat-app-965f1af25aa
  2. https://www.becomebetterprogrammer.com/typescript-pick-type/
  3. https://getstream.io/chat/docs/sdk/flutter/guides/adding_custom_attachments/
  4. https://www.facebook.com/messenger/posts/check-this-out-you-can-now-play-chess-inside-of-messenger-to-start-a-game-type-f/889510314501983/
  5. https://getstream.io/chat/sdk/flutter/

Adding a Custom Chessboard Thumbnail

Tags: typescript, unit-testing, dart

The MessageInput contains an attachmentThumbnailBuilders property to which a Map is supplied where the keys are the attachment types and the values are the attachment builder methods. Adding the attachmentThumbnailBuilders property and defining the builder for the chess attachment type.

MessageInput(
  key: _mipKey,
  attachmentLimit: 3,
  actions: [
    IconButton(
      onPressed: () {
        var newGame = Chess();
        var userId = StreamChat.of(context).currentUser!.id;
        var attachment =
            ChessAttachment(game: newGame, whiteUserId: userId);


_mipKey.currentState?.addAttachment(
          Attachment(
            type: 'chess',
            uploadState: const UploadState.success(),
            extraData: attachment.toJson(),
          ),
        );
      },
      icon: const Icon(Icons.videogame_asset_outlined),
    ),
  ],
  attachmentThumbnailBuilders: {
    'chess': (context, attachment) {
      return SizedBox(
        height: 75,
        width: 75,
        child: ChessBoard(
          controller: ChessBoardController(),
        ),
      );
    },
  },
),

Related links:

  1. https://medium.com/@dev.n/how-to-add-a-messenger-like-chess-game-to-your-flutter-chat-app-965f1af25aa
  2. https://www.becomebetterprogrammer.com/typescript-pick-type/
  3. https://getstream.io/chat/docs/sdk/flutter/guides/adding_custom_attachments/
  4. https://www.facebook.com/messenger/posts/check-this-out-you-can-now-play-chess-inside-of-messenger-to-start-a-game-type-f/889510314501983/
  5. https://getstream.io/chat/sdk/flutter/

Instantiate ChessBoard and ChessBoardController

Tags: swift,  ios, dart

You can also instantiate a ChessBoardController using the game in the ChessAttachment. This now displays the current game position on the board. Additionally, the whiteUserId parameter helps us determine which side of the board faces which user. We can change the orientation of the board if the ID does not match:

return ChessBoard(
   controller: chessBoardController,
   boardOrientation: StreamChat.of(context).currentUser!.id == chessAttachment.whiteUserId ? PlayerColor.white : PlayerColor.black,
);

Related links:

  1. https://medium.com/@dev.n/how-to-add-a-messenger-like-chess-game-to-your-flutter-chat-app-965f1af25aa
  2. https://www.becomebetterprogrammer.com/typescript-pick-type/
  3. https://getstream.io/chat/docs/sdk/flutter/guides/adding_custom_attachments/
  4. https://www.facebook.com/messenger/posts/check-this-out-you-can-now-play-chess-inside-of-messenger-to-start-a-game-type-f/889510314501983/
  5. https://getstream.io/chat/sdk/flutter/

Full MessageListView Code Non-Reactive

Tags: javascript,  dart

An example of the code for the chessboard with no reactivity implemented.

MessageListView(
  messageBuilder: (context, details, list, defaultWidget) {
    return defaultWidget.copyWith(
      customAttachmentBuilders: {
        'chess': (context2, message, list) {
          var attachment = message.attachments
              .firstWhere((e) => e.type == 'chess');
          var chessAttachment =
          ChessAttachment.fromJson(attachment.extraData);
          var chessBoardController =
          ChessBoardController.fromGame(chessAttachment.game);


return ChessBoard(
            controller: chessBoardController,
            boardOrientation:
            StreamChat.of(context).currentUser!.id ==
                chessAttachment.whiteUserId
                ? PlayerColor.white
                : PlayerColor.black,
          );
        },
      },
    );
  },
),


Related links:

  1. https://medium.com/@dev.n/how-to-add-a-messenger-like-chess-game-to-your-flutter-chat-app-965f1af25aa
  2. https://www.becomebetterprogrammer.com/typescript-pick-type/
  3. https://getstream.io/chat/docs/sdk/flutter/guides/adding_custom_attachments/
  4. https://www.facebook.com/messenger/posts/check-this-out-you-can-now-play-chess-inside-of-messenger-to-start-a-game-type-f/889510314501983/
  5. https://getstream.io/chat/sdk/flutter/

Message List View with ChessBoardController with Listener

Tags: javascript, dart

The current code can add a ChessAttachment to a message, display the thumbnail, and display the attachment as a chessboard in the MessageListView. When a user now plays a move, the board needs to update the attachment with the new position on the board, which also updates the other device automatically. To do this, the ChessBoardController allows listening to updates on the board position. When this happens, we can update the message with the new attachment data.

MessageListView(
  messageBuilder: (context, details, list, defaultWidget) {
    return defaultWidget.copyWith(
      customAttachmentBuilders: {
        'chess': (context2, message, list) {
          var attachment = message.attachments
              .firstWhere((e) => e.type == 'chess');
          var chessAttachment =
          ChessAttachment.fromJson(attachment.extraData);
          var chessBoardController =
          ChessBoardController.fromGame(chessAttachment.game);


chessBoardController.addListener(
                () {
              StreamChannel.of(context).channel.updateMessage(
                message.copyWith(
                  attachments: [
                    attachment.copyWith(
                      uploadState: const UploadState.success(),
                      extraData: chessAttachment
                          .copyWith(
                        game: chessBoardController.game,
                      )
                          .toJson(),
                    ),
                  ],
                ),
              );
            },
          );


return ChessBoard(
            controller: chessBoardController,
            boardOrientation:
            StreamChat.of(context).currentUser!.id ==
                chessAttachment.whiteUserId
                ? PlayerColor.white
                : PlayerColor.black,
          );
        },
      },
    );
  },
),


Related links:

  1. https://medium.com/@dev.n/how-to-add-a-messenger-like-chess-game-to-your-flutter-chat-app-965f1af25aa
  2. https://www.becomebetterprogrammer.com/typescript-pick-type/
  3. https://getstream.io/chat/docs/sdk/flutter/guides/adding_custom_attachments/
  4. https://www.facebook.com/messenger/posts/check-this-out-you-can-now-play-chess-inside-of-messenger-to-start-a-game-type-f/889510314501983/
  5. https://getstream.io/chat/sdk/flutter/