<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Govind Maheshwari</title>
    <description>The latest articles on DEV Community by Govind Maheshwari (@govindmh14).</description>
    <link>https://dev.to/govindmh14</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F525136%2Fb1883dde-7435-4739-a603-3fc3cb8bda5f.png</url>
      <title>DEV Community: Govind Maheshwari</title>
      <link>https://dev.to/govindmh14</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/govindmh14"/>
    <language>en</language>
    <item>
      <title>Adding Live Video Calling to Tic-Tac-Toe With Flutter and Dyte</title>
      <dc:creator>Govind Maheshwari</dc:creator>
      <pubDate>Tue, 09 Jan 2024 19:32:30 +0000</pubDate>
      <link>https://dev.to/dyte/adding-live-video-calling-to-tic-tac-toe-with-flutter-and-dyte-3elb</link>
      <guid>https://dev.to/dyte/adding-live-video-calling-to-tic-tac-toe-with-flutter-and-dyte-3elb</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Welcome to an exciting journey into the world of interactive gaming! In this blog post, we'll explore how to develop a captivating multiplayer Tic-Tac-Toe game using Flutter, a powerful and versatile framework for building cross-platform applications. But that's not all — we'll take it a step further by integrating the &lt;a href="https://dyte.io/video-sdk"&gt;Dyte video SDK&lt;/a&gt;, allowing users to connect with their friends and engage in real-time battles of strategy and wit.&lt;/p&gt;

&lt;p&gt;Engage in the timeless classic of Tic-Tac-Toe, reimagined with a modern twist. With Flutter's flexibility and Dyte's seamless video calling capabilities, you can create an immersive gaming experience that brings people together, no matter the distance. So, get ready to delve into the exciting world of game development as we guide you through building a multiplayer Tic-Tac-Toe game with the added thrill of live video communication.&lt;/p&gt;

&lt;p&gt;Throughout this tutorial, we'll provide step-by-step instructions, code snippets, and valuable insights to empower you in crafting your Flutter application. Whether you're a seasoned developer or just starting your programming journey, this guide will equip you with the knowledge and tools to create an engaging multiplayer game that captivates and entertains your users.&lt;/p&gt;

&lt;p&gt;So, let's dive in and discover how you can leverage the power of Flutter and the Dyte video SDK to breathe new life into the classic game of Tic-Tac-Toe, bringing joy and connection to players worldwide.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisites
&lt;/h2&gt;

&lt;p&gt;You'll need a few key elements to start creating your multiplayer Tic-Tac-Toe game using the &lt;a href="https://dyte.io/flutter-video-sdk"&gt;Dyte video SDK&lt;/a&gt; in Flutter. Firstly, make sure you have Flutter installed on your system. You can follow your operating system's official Flutter installation guide to set it up successfully.&lt;/p&gt;

&lt;p&gt;To help you hit the ground running, we've prepared an initial project setup with a pre-built UI for the Tic-Tac-Toe game. You can access the project code and user interface files &lt;a href="https://github.com/dyte-io/collaborative-tic-tac-toe/tree/initial"&gt;here&lt;/a&gt;. This initial setup provides a solid foundation to build upon, saving you time and effort in creating the game's basic structure.&lt;/p&gt;

&lt;p&gt;Now visit the official Dyte website at &lt;a href="https://dyte.io/"&gt;dyte.io&lt;/a&gt; and navigate to the signup page to create an account and explore the various features and functionalities offered by Dyte.&lt;/p&gt;

&lt;p&gt;Next, you must incorporate the Dyte video SDK into your &lt;a href="https://dyte.io/flutter-video-sdk"&gt;Flutter&lt;/a&gt; project. The Dyte SDK allows seamless integration of video calling functionality, enabling real-time communication between players.&lt;/p&gt;

&lt;p&gt;Using the following command, you can add the &lt;code&gt;dyte_core&lt;/code&gt; plugin in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;flutter pub add dyte_core&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;We are going to use Getx for state management. GetX is a powerful state management solution for Flutter that offers simplicity, performance, and scalability. With GetX, you can easily manage the state of your Tic-Tac-Toe game and handle navigation, dependencies, and more.&lt;/p&gt;

&lt;p&gt;In the initial screen, you will find three files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The first one is the &lt;code&gt;main.dart&lt;/code&gt; file, which contains the landing page.&lt;/li&gt;
&lt;li&gt;The second file is &lt;code&gt;game_screen.dart&lt;/code&gt; — this will hold the UI part for our Tic-Tac-Toe game.&lt;/li&gt;
&lt;li&gt;The third file is &lt;code&gt;room_state.dart&lt;/code&gt;. This dart file holds all the logic for dyte video calling and the Tic-Tac-Toe game state.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Open project is terminal and runs the &lt;code&gt;flutter pub get&lt;/code&gt; command to load all the required plugins.&lt;/p&gt;

&lt;p&gt;Currently, the game is not in a proper working state, but we will make it happen by the end of this blog.&lt;/p&gt;

&lt;p&gt;To proceed, let's open the &lt;code&gt;room_state.dart&lt;/code&gt; file. Inside this file, you will find a set of code snippets.&lt;/p&gt;

&lt;p&gt;Initially, you will come across variable initializations accompanied by comments that provide insights into their purpose and usage.&lt;/p&gt;

&lt;p&gt;To receive updates from the &lt;a href="https://dyte.io/flutter-video-sdk"&gt;Dyte video SDK&lt;/a&gt;, we need to add some listeners to the RoomStateNotifier class. This can be accomplished by implementing the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RoomStateNotifier&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;GetxController&lt;/span&gt;
&lt;span class="kd"&gt;implements&lt;/span&gt;
&lt;span class="n"&gt;DyteMeetingRoomEventsListener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;DyteParticipantEventsListener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;DyteChatEventsListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By registering these listeners, we ensure that our application is notified of any changes or updates in the room state from the &lt;a href="https://dyte.io/video-sdk"&gt;Dyte video SDK&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Upon adding the listener to the &lt;code&gt;RoomStateNotifier&lt;/code&gt; class, you may encounter errors indicating that specific override methods are missing. To resolve these errors, you can utilize the quick-fix functionality provided by your IDE.&lt;/p&gt;

&lt;h2&gt;
  
  
  Initiating the Dyte meeting
&lt;/h2&gt;

&lt;p&gt;Dyte &lt;a href="https://dyte.io/flutter-video-sdk"&gt;video SDK&lt;/a&gt; offers override methods that allow us to receive updates on our call. In this application, we will be utilizing the following override methods:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;onMeetingInitCompleted()&lt;/code&gt;: This method is called when the meeting initialization is completed, providing us with relevant information about the meeting.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onMeetingRoomJoinCompleted()&lt;/code&gt;: When the user successfully joins a meeting room, this method is invoked, allowing us to handle any necessary actions or updates.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onMeetingRoomLeaveCompleted()&lt;/code&gt;: Invoked when the user leaves the meeting room. This method enables us to perform any required cleanup or follow-up tasks.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onParticipantJoin(DyteJoinedMeetingParticipant participant)&lt;/code&gt;: This method is called when a new participant joins the meeting, providing information about the joined participant.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onParticipantLeave(DyteJoinedMeetingParticipant participant)&lt;/code&gt;: When a participant leaves the meeting, this method is triggered, supplying details about the departing participant.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;onNewChatMessage(DyteChatMessage message)&lt;/code&gt;: Whenever a new chat message is received, this method is invoked, allowing us to process and handle the message accordingly.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, attach the listener to the &lt;code&gt;RoomStateNotifier&lt;/code&gt; class to start receiving updates from the &lt;a href="https://dyte.io/flutter-video-sdk"&gt;Dyte video SDK&lt;/a&gt;. Furthermore, we initiate the video call by invoking the &lt;code&gt;init(meetingInfo)&lt;/code&gt; method provided by the &lt;code&gt;dyteClient&lt;/code&gt; instance. This action triggers the video call, enabling users to join the meeting and engage in real-time communication with other participants. The &lt;code&gt;dyteClient&lt;/code&gt; variable is of type &lt;code&gt;DyteMobileClient&lt;/code&gt;, which serves as a manager for interacting with a Dyte server.&lt;/p&gt;

&lt;p&gt;Here is the code snippet for &lt;a href="https://docs.dyte.io/api?v=v2"&gt;adding the listener&lt;/a&gt; and &lt;a href="https://docs.dyte.io/api?v=v2"&gt;initiating a Dyte meeting&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;RoomStateNotifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;username&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addMeetingRoomEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addParticipantEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addChatEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;meetingInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DyteMeetingInfoV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="nl"&gt;authToken:&lt;/span&gt;&lt;span class="s"&gt;'---TOKEN HERE—--'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nl"&gt;enableAudio:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nl"&gt;enableVideo:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meetingInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Joining the Dyte meeting
&lt;/h2&gt;

&lt;p&gt;Once the Dyte meeting is successfully initialized, a callback will be triggered in the &lt;code&gt;onMeetingInitCompleted()&lt;/code&gt; function. This callback indicates that the meeting has been set up correctly and is ready for joining the room.&lt;/p&gt;

&lt;p&gt;The following code needs to be implemented within the &lt;code&gt;onMeetingInitCompleted()&lt;/code&gt; function to facilitate joining the call and configuring the username within the room.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onMeetingInitCompleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDisplayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;joinRoom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;onMeetingRoomJoinCompleted()&lt;/code&gt; callback function is triggered when the room join process is completed. In this callback, we set the roomJoin variable to true, indicating that the local user has successfully joined the room.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onMeetingRoomJoinCompleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;roomJoin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similarly, in the &lt;code&gt;onMeetingRoomLeaveCompleted()&lt;/code&gt; callback, we handle the removal of listeners from this class. This ensures that the necessary cleanup tasks are performed when leaving the Dyte meeting, preventing any potential memory leaks or unwanted behaviors. By implementing this callback, we can properly manage the lifecycle of the class and maintain a streamlined and efficient application flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onMeetingRoomLeaveCompleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;roomJoin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeMeetingRoomEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeParticipantEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeChatEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RoomStateNotifier&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When an opponent joins the room, the &lt;code&gt;onParticipantJoin()&lt;/code&gt; function is triggered, providing us with a callback. At this point, we can proceed to initiate the game. However, before starting, it is necessary to assign symbols for local and remote peers. We will call the existing &lt;code&gt;assignSymbol()&lt;/code&gt; function available within the same file to accomplish this. By invoking this function, we can ensure that each player is assigned their respective symbols, setting the stage for an engaging and fair gameplay experience.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onParticipantJoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DyteJoinedMeetingParticipant&lt;/span&gt; &lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//not a local user&lt;/span&gt;
       &lt;span class="n"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="n"&gt;assignSymbol&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use their unique user IDs to assign local and remote peers symbols. We can ensure consistent symbol assignment across the room by sorting these IDs. In this implementation, we designate the character "O" to the user at the 0 index and "X" to the other peer. As user IDs are unique and consistent within the room, this approach guarantees that each player receives their designated symbol, enhancing clarity and fairness during gameplay.&lt;/p&gt;

&lt;h2&gt;
  
  
  Leaving the Dyte meeting
&lt;/h2&gt;

&lt;p&gt;If a remote peer leaves the room during an ongoing game, we must ensure that the local peer also leaves to maintain a synchronized and consistent experience. To handle this scenario, we will utilize the &lt;code&gt;onParticipantLeave&lt;/code&gt; override function.&lt;/p&gt;

&lt;p&gt;When a remote peer leaves the room, we will display a dialog to the user, providing them with a clear choice to leave the room. The dialog will have the &lt;code&gt;barrierDismissible&lt;/code&gt; parameter set to false, meaning the user cannot dismiss the dialog by tapping outside.&lt;/p&gt;

&lt;p&gt;Once the user clicks the "Leave" button within the dialog, a method will be invoked to trigger the local peer's departure from the room. This ensures that both participants gracefully exit the room, maintaining the integrity of the game session.&lt;/p&gt;

&lt;p&gt;By implementing this flow, we provide a seamless and intuitive experience for users, allowing them to easily handle situations where a remote peer leaves the game unexpectedly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;leaveRoom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the code for &lt;code&gt;onParticipantLeave&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onParticipantLeave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DyteJoinedMeetingParticipant&lt;/span&gt; &lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="n"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;barrierDismissible:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;onWillPop:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;"Opponent Left this game."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;textConfirm:&lt;/span&gt; &lt;span class="s"&gt;"Leave"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;middleText:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;confirmTextColor:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;onConfirm:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;leaveRoom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Using Dyte’s chat component
&lt;/h2&gt;

&lt;p&gt;To facilitate real-time updates of the game whenever the user takes their turn, we will leverage the chat feature provided by the &lt;a href="https://dyte.io/flutter-video-sdk"&gt;Dyte video SDK&lt;/a&gt;. In this approach, we will send the &lt;code&gt;displayExOh&lt;/code&gt; array as text through the chat functionality, ensuring it is transmitted to the remote peer's device. Utilizing the Dyte SDK's &lt;a href="https://dyte.io/chat-sdk"&gt;chat feature&lt;/a&gt;, we establish a seamless communication channel between the two peers, enabling the synchronization of game progress and retrieving the updated &lt;code&gt;displayExOh&lt;/code&gt; array on the remote peer's side. This mechanism ensures a consistent and interactive gaming experience, allowing both players to sync throughout the game.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendTextMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;displayExOh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we make use of the &lt;code&gt;onNewChatMessage&lt;/code&gt; override function. This function lets us receive the &lt;code&gt;displayExOh&lt;/code&gt; array in text format through the chat functionality. We then convert this text to the original array format, enabling us to update the user interface (UI) accordingly. By implementing this functionality, we ensure that any updates made by the remote peer are received and reflected in real-time on the local user's UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onNewChatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DyteChatMessage&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;DyteTextMessage&lt;/span&gt; &lt;span class="n"&gt;textMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;DyteTextMessage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;textMessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replaceFirst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"["&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;replaceFirst&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"]"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;", "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;displayExOh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;temp&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;localUserTurn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;boxCount&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;displayExOh&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;where&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;p0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;p0&lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;checkWinner&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Managing audio/video of participants
&lt;/h2&gt;

&lt;p&gt;We will be utilizing two additional functions, &lt;code&gt;toggleVideo()&lt;/code&gt; and &lt;code&gt;toggleAudio()&lt;/code&gt;, to manage the local peer's video and audio within the room. These functions allow us to dynamically control the starting and stopping of the local peer's video and audio streams during the video call session. By invoking &lt;code&gt;toggleVideo()&lt;/code&gt;, we can initiate or pause the local peer's video transmission, while &lt;code&gt;toggleAudio()&lt;/code&gt; enables us to start or mute the local peer's audio feed. These functionalities provide flexibility and control to the user, allowing them to manage their video and audio presence according to their preferences and requirements within the room.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;toogleVideo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isVideoOn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disableVideo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enableVideo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="n"&gt;isVideoOn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;toogleAudio&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isAudioOn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disableAudio&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enableAudio&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;isAudioOn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Setting up the Tic-Tac-Toe game
&lt;/h2&gt;

&lt;p&gt;Now, let's navigate to the &lt;code&gt;gameScreen.dart&lt;/code&gt; file. This file contains the UI code for our game and the video call controls UI. However, to display the video tiles correctly, we need to add some additional code. This code will handle the rendering and layout of the video tiles, ensuring they are displayed correctly on the game screen. By incorporating this code, we can seamlessly integrate the game UI and the video call interface, providing users with a comprehensive and immersive experience.&lt;/p&gt;

&lt;p&gt;Let's search for the comment "&lt;code&gt;// Dyte Meeting Video View&lt;/code&gt;" in the &lt;code&gt;gameScreen.dart&lt;/code&gt; file. Within the corresponding section, we will proceed to check whether the user has joined the Dyte meeting or not by using the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;roomJoin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By implementing this code snippet, we can differentiate between the scenarios where the user has successfully joined the Dyte meeting and where they have not. This conditional logic allows us to handle each situation appropriately, ensuring a smooth and coherent user experience throughout the game.&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;roomJoin&lt;/code&gt; variable is true, it indicates that the user has successfully joined the Dyte meeting. To render the user's video tile, we can utilize the &lt;code&gt;VideoView&lt;/code&gt; widget provided by the &lt;a href="https://dyte.io/video-sdk"&gt;Dyte video SDK&lt;/a&gt;. This widget lets us display the video feed for local and remote peers within the game interface. By incorporating the &lt;code&gt;VideoView&lt;/code&gt; widget, we can seamlessly integrate the video streams from the local and remote participants, enriching the interactive experience and fostering real-time communication between the players.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Local user video tile and name&lt;/span&gt;
&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
      &lt;span class="n"&gt;SizedBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;ClipRRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
           &lt;span class="nl"&gt;borderRadius:&lt;/span&gt; &lt;span class="n"&gt;BorderRadius&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;circular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
           &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;VideoView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
              &lt;span class="nl"&gt;isSelfParticipant:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;),&lt;/span&gt;
     &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt;    &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;),)&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To render the local peer's video feed, we must pass the &lt;code&gt;isSelfParticipant&lt;/code&gt; parameter as true, as shown in the code snippet above. This informs the VideoView widget that the video being rendered is from the local participant.&lt;/p&gt;

&lt;p&gt;On the other hand, for rendering the remote peer's video feed, we can utilize the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;// Remote user video tile and name&lt;/span&gt;
&lt;span class="n"&gt;Column&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="nl"&gt;mainAxisAlignment:&lt;/span&gt; &lt;span class="n"&gt;MainAxisAlignment&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
&lt;span class="n"&gt;SizedBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;ClipRRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;borderRadius:&lt;/span&gt; &lt;span class="n"&gt;BorderRadius&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;circular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;VideoView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;meetingParticipant:&lt;/span&gt;
    &lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;color:&lt;/span&gt;        &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;),)&lt;/span&gt;
   &lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;),&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To fulfill the requirement, we need to include a &lt;code&gt;meetingParticipant&lt;/code&gt; parameter with the value of &lt;code&gt;remotePeer&lt;/code&gt;, which we have stored in the &lt;code&gt;onParticipantJoin&lt;/code&gt; override function.&lt;/p&gt;

&lt;p&gt;Utilizing the &lt;code&gt;meetingParticipant&lt;/code&gt; parameter and accessing the &lt;code&gt;remotePeer&lt;/code&gt; value ensures that the correct participant's video stream is rendered within the VideoView widget.&lt;/p&gt;

&lt;p&gt;And &lt;a href="https://github.com/dyte-io/collaborative-tic-tac-toe"&gt;here’s&lt;/a&gt; the source code for the project.&lt;/p&gt;

&lt;p&gt;Throughout this blog post, we explored the seamless integration of these powerful tools, enabling you to create an immersive and interactive gaming experience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;You've crafted a visually appealing and responsive user interface by leveraging Flutter's cross-platform capabilities. The &lt;a href="https://dyte.io/video-sdk"&gt;Dyte video SDK&lt;/a&gt; has brought players closer together, allowing them to enjoy real-time Tic-Tac-Toe battles of strategy and wit, regardless of their physical location. With GetX, you've efficiently managed the game's state, providing users with a smooth and enjoyable gaming experience.&lt;/p&gt;

&lt;p&gt;But this is just the beginning of your game development journey. There are endless possibilities for expanding and enhancing your Tic-Tac-Toe game. Consider implementing game statistics, player rankings, or additional game modes to keep your users engaged and entertained.&lt;/p&gt;

&lt;p&gt;As you continue to explore and experiment with Flutter and the &lt;a href="https://dyte.io/flutter-video-sdk"&gt;Dyte video SDK&lt;/a&gt;, remember to embrace the joy of learning and be open to trying new ideas. The world of game development is constantly evolving, offering limitless opportunities for innovation.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Get better insights on leveraging &lt;a href="https://dyte.io/"&gt;Dyte&lt;/a&gt;'s technology and discover how it can revolutionize your app's communication capabilities with its &lt;a href="https://dyte.io/video-sdk"&gt;SDKs&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Congratulations! You've reached the end of this exciting journey into building a multiplayer Tic-Tac-Toe game using Flutter, the &lt;a href="https://dyte.io/flutter-video-sdk"&gt;Dyte video SDK&lt;/a&gt;, and GetX for state management.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Add Video Calling to Chess With Flutter, Dyte, and GetX</title>
      <dc:creator>Govind Maheshwari</dc:creator>
      <pubDate>Tue, 09 Jan 2024 19:26:04 +0000</pubDate>
      <link>https://dev.to/dyte/add-video-calling-to-chess-with-flutter-dyte-and-getx-23i6</link>
      <guid>https://dev.to/dyte/add-video-calling-to-chess-with-flutter-dyte-and-getx-23i6</guid>
      <description>&lt;p&gt;Discover the fusion of tradition and innovation as we explore the world of chess, reimagined through Dyte video calling in the Flutter framework. Break the distance barriers and get your tactical hat on because it's getting real, in real-time, like never before.&lt;/p&gt;

&lt;p&gt;In this blog, we'll (grand)master adding video calling to chess, all within the flexible Flutter framework. Prepare to take your strategic battles beyond the board, embracing virtual gameplay and personal connections.&lt;/p&gt;

&lt;p&gt;We'll capture your pieces and walk you through every step of this tutorial. You can expect clear, easy-to-follow instructions, short code examples, and valuable tips. We aim to give you the confidence and skills to create your unique Flutter app. Whether you're an experienced coder or starting out doesn't matter. This guide is designed for all sorts of players.&lt;/p&gt;

&lt;p&gt;So, let's jump right in and harness the capabilities of Flutter and &lt;a href="https://dyte.io/"&gt;Dyte&lt;/a&gt; to give a fresh perspective to the timeless board game. Our journey will infuse joy and connection into players all around the globe. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Requirements&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You'll need critical elements to create your multiplayer chess game using the Dyte video calling API in Flutter. Firstly, make sure you have Flutter installed on your system. You can follow your operating system's &lt;a href="https://docs.flutter.dev/"&gt;official Flutter installation guide&lt;/a&gt; to set it up successfully.&lt;/p&gt;

&lt;p&gt;To help you hit the ground running, we've prepared an initial project setup with a pre-built user interface (UI) for the chess game. You can access the project code and user interface files &lt;a href="https://github.com/dyte-io/collaborative-chess/tree/initial"&gt;here&lt;/a&gt;. This initial setup provides a solid foundation to build upon, saving you time and effort in creating the game's basic structure.&lt;/p&gt;

&lt;p&gt;Next, you must visit the official &lt;a href="https://dyte.io/"&gt;Dyte website&lt;/a&gt; and navigate to the signup page to create an account and explore the various features and functionalities Dyte offers.&lt;/p&gt;

&lt;p&gt;You'll then need to incorporate the Dyte video calling SDK into your Flutter project. The Dyte plugin will seamlessly integrate video calling functionality, enabling real-time communication between players.&lt;/p&gt;

&lt;p&gt;You can add the &lt;code&gt;dyte_core&lt;/code&gt; plugin in the &lt;code&gt;pubspec.yaml&lt;/code&gt; file using the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;flutter pub add dyte_core
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To add chess functionality, we are using the &lt;a href="https://pub.dev/packages/bishop"&gt;&lt;code&gt;bishop&lt;/code&gt;&lt;/a&gt;, &lt;a href="https://pub.dev/packages/squares"&gt;&lt;code&gt;squares&lt;/code&gt;&lt;/a&gt;, and &lt;a href="https://pub.dev/packages/square_bishop"&gt;&lt;code&gt;square_bishop&lt;/code&gt;&lt;/a&gt; plugins.&lt;/p&gt;

&lt;p&gt;We are going to use &lt;code&gt;Getx&lt;/code&gt; for state management. GetX is a powerful state management solution for Flutter that offers simplicity, performance, and scalability. With GetX, you can easily manage the state of your chess game and handle navigation, dependencies, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Basic chess concepts&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Before we add video calling to our game of wits, we need to understand some chess concepts before writing code.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Chessboard and Squares&lt;/strong&gt;: The chessboard consists of 64 squares arranged in an 8x8 grid. Each square alternates between light and dark colors.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Pieces and their movement&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;King:&lt;/strong&gt; Moves one square in any direction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Queen:&lt;/strong&gt; Moves diagonally, horizontally, or vertically any number of squares.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rook:&lt;/strong&gt; Moves horizontally or vertically any number of squares.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bishop:&lt;/strong&gt; Moves diagonally any number of squares.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Knight:&lt;/strong&gt; Moves in an L-shape; two squares in one direction and one square perpendicular to it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pawn:&lt;/strong&gt; Moves forward one square but captures diagonally.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. Checkmate&lt;/strong&gt;: If a player's king is in check and has no legal moves to escape, it's checkmate, and the game ends.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. FEN&lt;/strong&gt;: In (Forsyth-Edwards Notation) FEN notation, each chessboard square is represented by a character, with uppercase letters denoting white pieces and lowercase letters denoting black pieces. The characters used are as follows:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;K/k:&lt;/strong&gt; King&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Q/q:&lt;/strong&gt; Queen&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;R/r:&lt;/strong&gt; Rook&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;N/n:&lt;/strong&gt; Knight&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;B/b:&lt;/strong&gt; Bishop&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;P/p:&lt;/strong&gt; Pawn&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1-8:&lt;/strong&gt; Empty squares (number of empty squares in a row)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;FEN also includes information about the player to move, castling rights, en passant target square, halfmove clock (the number of halfmoves since the last pawn move or capture), and fullmove number (the number of the current move).&lt;/p&gt;

&lt;p&gt;FEN notation is commonly used in various chess-related applications, such as recording and sharing positions, analyzing games, and setting up positions for practice or analysis. It provides a standardized way to communicate chess positions regardless of language or platform.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;**Note:** For rendering pieces on board we will require to generate FEN after every move.&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Building Game&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now that you understand the chess terminology, let's move in the right direction and navigate to the lib folder. There, you will discover four files playing crucial roles to bring your game to life. Each file contributes uniquely to the seamless functionality and immersive experience you're crafting. Let's explore the significance of these files in shaping your game's architecture and interaction.&lt;/p&gt;

&lt;p&gt;We have the &lt;code&gt;main.dart&lt;/code&gt; file starting at the beginning. This Dart file serves as the entry point for your application. It's the first thing that gets executed when your app launches. In this file, you'll typically find the setup for your app's main structure, including the landing page. The landing page is what users initially see when they open your app. It's the gateway that sets the tone for the entire user experience (UX), providing a decisive first impression of what your app offers.&lt;/p&gt;

&lt;p&gt;The second file is named &lt;code&gt;game_screen.dart&lt;/code&gt;. This Dart file takes center stage in our chess game's UI aspect. Here, you'll find the design and layout components that visually represent the chess game to the user. This file shows how the game appears on the screen from the chessboard to the player interface. It's the bridge between the underlying game logic and what the user sees, ensuring a visually appealing and user-friendly experience for your players.&lt;/p&gt;

&lt;p&gt;Moving on to the third file, called &lt;code&gt;room_state.dart&lt;/code&gt;. This Dart file is the home for all the essential logic related to Dyte video calling and the state of the chess game. Here, you'll find the backbone of your application's functionality, connecting the dots between video communication and the intricate workings of chess. This file is a pivotal hub where the magic of video interaction and the strategy of chess converge to create a seamless and engaging UX.&lt;/p&gt;

&lt;p&gt;The fourth is the &lt;code&gt;http_request.dart&lt;/code&gt; file. The &lt;code&gt;HttpRequest&lt;/code&gt; class in this Dart file is designed to manage API requests. It's responsible for handling tasks such as creating rooms and adding participants to these rooms. This integral class plays a crucial role in facilitating interactions with the backend of your application.&lt;/p&gt;

&lt;p&gt;To get your project up and running, open your terminal and execute the command &lt;code&gt;flutter pub get&lt;/code&gt;. This command is essential as it fetches and loads all the required plugins and dependencies for your project. It ensures your project has everything needed to function correctly so you can seamlessly build your engaging multiplayer chess game.&lt;/p&gt;

&lt;p&gt;While the game might not be fully functional yet, we're committed to transforming it into a fully operational masterpiece by the time you complete this blog.&lt;/p&gt;

&lt;p&gt;Let's focus on two essential features: room creation and participant addition. These functionalities serve as the cornerstone of our game, enabling us to establish fresh gaming rooms and effortlessly invite friends to join in on the fun. Through room creation, we can set the stage for exciting matches. At the same time, the participant addition feature lets us share these rooms with our buddies, fostering a sense of camaraderie and friendly competition.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;API Request&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Let's navigate to the &lt;code&gt;http_request.dart&lt;/code&gt; file. Within this file, you'll discover the code responsible for room creation and participant addition through API requests. It's crucial to note that you'll need to include your organization ID and API key from the Dyte dashboard in this process. These credentials are essential for establishing a secure and authenticated connection with the Dyte services.&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;Code snippet for room creation&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;createMeeting&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;millisecondsSinceEpoch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$_baseUrl&lt;/span&gt;&lt;span class="s"&gt;/meetings"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
   &lt;span class="nl"&gt;headers:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'Authorization'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
   &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;"title"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"chess-&lt;/span&gt;&lt;span class="si"&gt;$id&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;Map&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jsonDecode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;showSnackbar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetSnackBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="p"&gt;));&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;strong&gt;Code snippet for add participant&lt;/strong&gt;
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="n"&gt;Future&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;addParticipant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;roomId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DateTime&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;millisecondsSinceEpoch&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
 &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Response&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;post&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="kt"&gt;Uri&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$_baseUrl&lt;/span&gt;&lt;span class="s"&gt;/meetings/&lt;/span&gt;&lt;span class="si"&gt;$roomId&lt;/span&gt;&lt;span class="s"&gt;/participants"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;headers:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="s"&gt;'Authorization'&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;_token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"Content-Type"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"application/json"&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nl"&gt;body:&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;encode&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="s"&gt;"name"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s"&gt;"Preset_name"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"group_call_host"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
           &lt;span class="s"&gt;"custom_participant_id"&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="s"&gt;"player-&lt;/span&gt;&lt;span class="si"&gt;$id&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
  &lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;statusCode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;201&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kt"&gt;Map&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;jsonDecode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;body&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;"data"&lt;/span&gt;&lt;span class="p"&gt;][&lt;/span&gt;&lt;span class="s"&gt;"token"&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;showSnackbar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GetSnackBar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="n"&gt;e&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
 &lt;span class="p"&gt;));&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For a more comprehensive understanding of the API requests and responses, please refer to the &lt;a href="https://docs.dyte.io/api#/"&gt;Dyte API guide&lt;/a&gt;. This guide provides detailed insights into working with the Dyte API for various operations.&lt;/p&gt;

&lt;p&gt;You can explore &lt;a href="https://docs.dyte.io/api/#/operations/create_meeting"&gt;Dyte API: Create a meeting&lt;/a&gt; for room creation and &lt;a href="https://docs.dyte.io/api/#/operations/add_participant"&gt;Dyte API: Add a participant&lt;/a&gt; for, well, adding participants.&lt;/p&gt;

&lt;p&gt;These resources will provide in-depth information on the API endpoints, parameters, and expected responses, enabling you to seamlessly integrate these functionalities into your Flutter application for a fully-fledged multiplayer chess experience.&lt;/p&gt;

&lt;p&gt;Now, let’s open the &lt;code&gt;main.dart&lt;/code&gt; file for connecting room creation and adding participants to the UI.&lt;/p&gt;

&lt;p&gt;Our initial focus is on establishing a room for the game. You'll encounter two buttons in the code and UI. One button lets you join an existing game, while the other enables you to create a new one.&lt;/p&gt;

&lt;p&gt;When the "Create Game" button is pressed, we execute the following code to create a room:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;roomId&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;createMeeting&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code snippet triggers the creation of a room where the chess game will unfold. It's the starting point for crafting the environment where players engage in strategic battles on the virtual chessboard.&lt;/p&gt;

&lt;p&gt;After successfully creating the room, we get the room ID. We will then pass this room ID to the &lt;code&gt;addParticipant&lt;/code&gt; function, which will facilitate the token acquisition. This token is a vital element for the video calling functionality. Here's how you achieve this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kt"&gt;String&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;HttpRequest&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addParticipant&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We will transmit this acquired token to the &lt;code&gt;RoomStateNotifier&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;When joining an existing game, our approach involves prompting the user for a room ID. This room ID will then be utilized in the &lt;code&gt;addParticipant&lt;/code&gt; function to obtain the necessary token. Once secured, this token is subsequently passed to the &lt;code&gt;RoomStateNotifier&lt;/code&gt; for effective integration into the ongoing gaming experience.&lt;/p&gt;

&lt;p&gt;Let's open the &lt;code&gt;room_state.dart&lt;/code&gt; file to move forward. Once inside, you'll find a collection of code snippets pivotal to our progress. These snippets hold the key to implementing the Dyte video calling functionality and managing the state of our chess game. So, let's dive in and dissect these snippets to uncover the magic that will bring our multiplayer chess game to life!&lt;/p&gt;

&lt;p&gt;As you begin exploring, you'll notice a series of variable initializations. These are accompanied by insightful comments that shed light on their intended roles and how they contribute to the program's functionality.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Initiating the Dyte video meeting&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To keep track of updates from the Dyte plugin, we must incorporate listeners into the &lt;code&gt;RoomStateNotifier&lt;/code&gt; class. Achieving this involves implementing the following code snippets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;RoomStateNotifier&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="n"&gt;GetxController&lt;/span&gt;
&lt;span class="kd"&gt;implements&lt;/span&gt;
&lt;span class="n"&gt;DyteMeetingRoomEventsListener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;DyteParticipantEventsListener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="n"&gt;DyteChatEventsListener&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="p"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By incorporating these listeners, we establish a mechanism where our application stays informed about any alterations or updates occurring in the room state through the Dyte plugin. This real-time awareness is crucial to ensure our game stays in sync with the dynamic changes within the video communication framework.&lt;/p&gt;

&lt;p&gt;Once you've integrated the listener into the &lt;code&gt;RoomStateNotifier&lt;/code&gt; class, you might encounter errors that signal the absence of specific override methods. You can use the quick fix feature available in your integrated development environment (IDE) to tackle these errors. This tool can assist you in swiftly resolving the issues by generating the required override methods, ensuring your code remains error-free and fully functional.&lt;/p&gt;

&lt;p&gt;The Dyte plugin equips us with various essential override methods that enable us to effectively capture updates concerning our calls. In the context of our application, we will be leveraging the following override methods to enhance our UX:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. onMeetingInitCompleted()&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
This method triggers when the initialization of a meeting concludes. It furnishes pertinent details about the meeting, facilitating informed handling of meeting-related information.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. onMeetingRoomJoinCompleted()&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
This method springs into action when a user successfully enters a meeting room. It manages any imperative actions or updates required upon room entry.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. onMeetingRoomLeaveCompleted()&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
This method is the moment a user departs from a meeting room, offering the opportunity to execute any essential cleanup or follow-up procedures.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. onParticipantJoin(DyteJoinedMeetingParticipant participant)&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
This method is triggered whenever a new participant joins the meeting, delivering comprehensive information about the recently joined participant.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. onParticipantLeave(DyteJoinedMeetingParticipant participant)&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
This method comes into play as a participant exits the meeting, providing vital insights into the departing participant's details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;6. onNewChatMessage(DyteChatMessage message)&lt;/strong&gt;:&lt;br&gt;&lt;br&gt;
If a fresh chat message arrives, this method is invoked. It empowers us to process and manage incoming messages effectively.&lt;/p&gt;

&lt;p&gt;Harnessing these override methods allows us to capture key events within our video calls and enhance our application's overall interactivity and engagement.&lt;/p&gt;

&lt;p&gt;Let's attach the listener to the &lt;code&gt;RoomStateNotifier&lt;/code&gt; class to start receiving updates from the Dyte API. Furthermore, we initiate the video call by invoking the init(meetingInfo) method provided by the &lt;code&gt;dyteClient&lt;/code&gt; instance. This action triggers the process of starting the video call, enabling users to join the meeting and engage in real-time communication with other participants. The &lt;code&gt;dyteClient&lt;/code&gt; variable is of type &lt;code&gt;DyteMobileClient&lt;/code&gt;, which serves as a manager for interacting with a Dyte server.&lt;/p&gt;

&lt;p&gt;Here is the code snippet for adding the listener and initiating the meeting:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;RoomStateNotifier&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;meetingId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;roomId&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;meetingId&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addMeetingRoomEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addParticipantEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;addChatEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;meetingInfo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;DyteMeetingInfoV2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="nl"&gt;authToken:&lt;/span&gt; &lt;span class="n"&gt;token&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nl"&gt;enableAudio:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="nl"&gt;enableVideo:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;meetingInfo&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the meeting is successfully initialized, a callback will be triggered in the &lt;code&gt;onMeetingInitCompleted()&lt;/code&gt; function. This callback indicates that the meeting has been set up properly and is ready for joining the room.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Joining the Dyte meeting&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To join the call and configure the username within the room, the following code must be implemented within the &lt;code&gt;onMeetingInitCompleted()&lt;/code&gt; function.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onMeetingInitCompleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setDisplayName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;joinRoom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the room join process is completed, the &lt;code&gt;onMeetingRoomJoinCompleted()&lt;/code&gt; callback function is triggered. In this callback, we set the &lt;code&gt;roomJoin&lt;/code&gt; variable to true, indicating that the local user has successfully joined the room.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onMeetingRoomJoinCompleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;roomJoin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Leaving the Dyte meeting&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Similarly, in the &lt;code&gt;onMeetingRoomLeaveCompleted()&lt;/code&gt; callback, we handle the removal of listeners from this class. This ensures that the necessary clean-up tasks are performed when leaving the meeting, preventing any potential memory leaks or unwanted behaviors. By implementing this callback, we can adequately manage the class's lifecycle and maintain a streamlined and efficient application flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onMeetingRoomLeaveCompleted&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;roomJoin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeMeetingRoomEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeParticipantEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;removeChatEventsListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;delete&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;RoomStateNotifier&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
&lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Remote peer(s) join the Dyte meeting&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;When an opponent joins the room, the &lt;code&gt;onParticipantJoin()&lt;/code&gt; function is triggered, providing us with a callback. At this point, we can proceed to initiate the game. However, it is necessary to assign color to local and remote peers before starting.&lt;/p&gt;

&lt;p&gt;To accomplish this, we will call the existing &lt;code&gt;assignColour()&lt;/code&gt; function available within the same file. By invoking this function, we can ensure that each player is assigned their respective symbols, setting the stage for an engaging and fair gameplay experience.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onParticipantJoin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DyteJoinedMeetingParticipant&lt;/span&gt; &lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="c1"&gt;//not a local user&lt;/span&gt;
       &lt;span class="n"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
       &lt;span class="n"&gt;assignColour&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We use their unique user IDs to assign local and remote peers colors. We can ensure consistent symbol assignment across the room by sorting these IDs. In this implementation, we designate the symbol "White" to the user at the 0 index and "Black" to the other peer. As user IDs are unique and consistent within the room, this approach guarantees that each player receives their designated symbol, enhancing clarity and fairness during gameplay.&lt;/p&gt;

&lt;p&gt;If a remote peer leaves the room during an ongoing game, we must ensure that the local peer also leaves to maintain a synchronized and consistent experience. We will use the &lt;code&gt;onParticipantLeave&lt;/code&gt; override function to handle this scenario.&lt;/p&gt;

&lt;p&gt;When a remote peer leaves the room, we will display a dialog to the user, giving them a clear choice to leave the room. The dialog will have the &lt;code&gt;barrierDismissible&lt;/code&gt; parameter set to false, meaning the user cannot dismiss the dialog by tapping outside.&lt;/p&gt;

&lt;p&gt;Once the user clicks the "Leave" button within the dialog, a method will be invoked to trigger the local peer's departure from the room. This ensures that both participants gracefully exit the room, maintaining the integrity of the game session.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;leaveRoom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here is the code for onParticipantLeave:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onParticipantLeave&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DyteJoinedMeetingParticipant&lt;/span&gt; &lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;participant&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;
    &lt;span class="n"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="n"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
      &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="nl"&gt;barrierDismissible:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;onWillPop:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;"Opponent Leave this game."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;textConfirm:&lt;/span&gt; &lt;span class="s"&gt;"Leave"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;middleText:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;confirmTextColor:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="nl"&gt;onConfirm:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
          &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;leaveRoom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
          &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
      &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;makes their move, we are harnessing the chat feature provided by the Dyte plugin. Within this strategy, we employ the &lt;code&gt;makeSquareMove(move)&lt;/code&gt; function from the bishop library, a built-in tool. This function possesses a boolean return type; if the move is invalid, it yields false. Otherwise, it is true. Upon confirming a valid move, we update the ChessBoard's state by fetching the latest &lt;code&gt;squaresState&lt;/code&gt; via the &lt;code&gt;bishop&lt;/code&gt; library.&lt;/p&gt;

&lt;p&gt;To synchronize the remote user's experience, we transmit the most recent FEN (Forsyth-Edwards Notation) obtained from the bishop library through the Dyte plugin's chat functionality. This data is seamlessly sent to the remote peer's device.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;onUserMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Move&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;isDrop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;isPremove&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeSquaresMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;squaresState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerColor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;localUserTurn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;snackbar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid move"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;snackPosition:&lt;/span&gt; &lt;span class="n"&gt;SnackPosition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BOTTOM&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;checkmate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;barrierDismissible:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;"You won the game"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;textConfirm:&lt;/span&gt; &lt;span class="s"&gt;"Leave"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;middleText:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;confirmTextColor:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;onConfirm:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;leaveRoom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Using Dyte’s chat component&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;To ensure real-time updates of the game whenever a user makes their move, we are harnessing the chat feature provided by the Dyte plugin. Within this strategy, we employ the &lt;code&gt;makeSquareMove(move)&lt;/code&gt; function from the bishop library, a built-in tool. This function possesses a boolean return type; if the move is invalid, it yields false, otherwise, it is true. Upon confirming a valid move, we update the ChessBoard's state by fetching the latest &lt;code&gt;squaresState&lt;/code&gt; via the &lt;code&gt;bishop&lt;/code&gt; library.  &lt;/p&gt;

&lt;p&gt;To synchronize the remote user's experience, we transmit the most recent FEN obtained from the bishop library through the Dyte plugin's chat functionality. This data is seamlessly sent to the remote peer's device.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;onUserMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Move&lt;/span&gt; &lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;isDrop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;isPremove&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;makeSquaresMove&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;move&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;squaresState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerColor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;fen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
   &lt;span class="n"&gt;localUserTurn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;snackbar&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invalid move"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="nl"&gt;snackPosition:&lt;/span&gt; &lt;span class="n"&gt;SnackPosition&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;BOTTOM&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;checkmate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;barrierDismissible:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;"You won the game"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;textConfirm:&lt;/span&gt; &lt;span class="s"&gt;"Leave"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;middleText:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;confirmTextColor:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;onConfirm:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;leaveRoom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="n"&gt;sendMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;String&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;chat&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;sendTextMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Lastly, we make use of the &lt;code&gt;onNewChatMessage&lt;/code&gt; override function. This function lets us receive the chess FEN in text format through the chat functionality. We will now load the &lt;code&gt;bishop&lt;/code&gt; variable (game) with a new FEN and update the &lt;code&gt;chessBoard&lt;/code&gt; state using the &lt;code&gt;squareState&lt;/code&gt; function, which enables us to update the UI accordingly.&lt;/p&gt;

&lt;p&gt;By implementing this functionality, we ensure that any updates made by the remote peer are received and reflected in real-time on the local user's UI.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="nd"&gt;@override&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;onNewChatMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DyteChatMessage&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;message&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;DyteTextMessage&lt;/span&gt; &lt;span class="n"&gt;textMessage&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;message&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;DyteTextMessage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="kd"&gt;final&lt;/span&gt; &lt;span class="n"&gt;fen&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;textMessage&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;message&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
 &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;loadFen&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;fen&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="n"&gt;state&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;squaresState&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;playerColor&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
 &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;game&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;checkmate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;defaultDialog&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;barrierDismissible:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;title:&lt;/span&gt; &lt;span class="s"&gt;"You lose the game"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;textConfirm:&lt;/span&gt; &lt;span class="s"&gt;"Leave"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;middleText:&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;confirmTextColor:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;white&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;onConfirm:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;leaveRoom&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;Get&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;back&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
   &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
 &lt;span class="n"&gt;localUserTurn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Managing audio/video of participants&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We will utilize two additional functions — &lt;code&gt;toggleVideo()&lt;/code&gt; and &lt;code&gt;toggleAudio()&lt;/code&gt; — to manage the local peer's video and audio within the room. These functions allow us to dynamically control the starting and stopping of the local peer's video and audio streams during the video call session.&lt;/p&gt;

&lt;p&gt;By invoking &lt;code&gt;toggleVideo()&lt;/code&gt;, we can initiate or pause the local peer's video transmission, while &lt;code&gt;toggleAudio()&lt;/code&gt; enables us to start or mute the local peer's audio feed. These functionalities provide flexibility and control to the user, allowing them to manage their video and audio presence according to their preferences and requirements within the room.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;toogleVideo&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isVideoOn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
 &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disableVideo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enableVideo&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
       &lt;span class="n"&gt;isVideoOn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="n"&gt;toogleAudio&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;isAudioOn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;disableAudio&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;dyteClient&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUser&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;enableAudio&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
     &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="n"&gt;isAudioOn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toggle&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  &lt;strong&gt;Setting up the chess game&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Now, let's navigate to the &lt;code&gt;gameScreen.dart&lt;/code&gt; file. This file contains the UI code for our game and the video call controls UI. However, we must add some code to display the video tiles correctly. This code will handle the rendering and layout of the video tiles, ensuring they are displayed correctly on the game screen. By incorporating this code, we can seamlessly integrate the game UI and the video call interface, providing users with a comprehensive and immersive experience.&lt;/p&gt;

&lt;p&gt;Search for the comment "// Dyte Meeting Video View" in the &lt;code&gt;gameScreen.dart&lt;/code&gt; file. Within the corresponding section, we will proceed to check whether the user has joined the meeting or not by using the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;roomJoin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By implementing this code snippet, we can differentiate between the scenarios where the user has successfully joined the meeting and where they have not. This conditional logic allows us to handle each situation appropriately, ensuring a smooth and coherent user experience throughout the game.&lt;/p&gt;

&lt;p&gt;If the &lt;code&gt;roomJoin&lt;/code&gt; variable is true, it indicates that the user has successfully joined the meeting. We can use the &lt;code&gt;VideoView&lt;/code&gt; widget the Dyte video calling SDK provides to render the user's video tile.&lt;/p&gt;

&lt;p&gt;This widget lets us display the video feed for local and remote peers within the game interface. By incorporating the &lt;code&gt;VideoView&lt;/code&gt; widget, we can coherently integrate the video streams from the local and remote participants, enriching the interactive experience and fostering real-time communication between the players.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Local user video tile and name&lt;/span&gt;
&lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Spacer&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="n"&gt;Obx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;roomJoin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
  &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;
  &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;username&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;black&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;fontWeight:&lt;/span&gt; &lt;span class="n"&gt;FontWeight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SizedBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="n"&gt;Obx&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;decoration:&lt;/span&gt; &lt;span class="n"&gt;BoxDecoration&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;borderRadius:&lt;/span&gt; &lt;span class="n"&gt;BorderRadius&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;circular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="nl"&gt;boxShadow:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;localUserTurn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;...[&lt;/span&gt;
   &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;BoxShadow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;red&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;spreadRadius:&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nl"&gt;blurRadius:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;BoxShadow&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;red&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;spreadRadius:&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;blurRadius:&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;)]&lt;/span&gt;
  &lt;span class="p"&gt;],&lt;/span&gt;
 &lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="nl"&gt;margin:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;right:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;ClipRRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nl"&gt;borderRadius:&lt;/span&gt; &lt;span class="n"&gt;BorderRadius&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;circular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="c1"&gt;// Dyte Meeting Video View&lt;/span&gt;
 &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;roomJoin&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
 &lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SizedBox&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;VideoView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;isSelfParticipant:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To render the local peer's video feed, we must pass the &lt;code&gt;isSelfParticipant&lt;/code&gt; parameter as true, as shown in the code snippet above. This informs the &lt;code&gt;VideoView&lt;/code&gt; widget that the video is rendered from the local participant.&lt;/p&gt;

&lt;p&gt;On the other hand, for rendering the remote peer's video feed, we can utilize the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight dart"&gt;&lt;code&gt;&lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;
&lt;span class="c1"&gt;// Room Id&lt;/span&gt;
&lt;span class="o"&gt;?&lt;/span&gt; &lt;span class="n"&gt;SizedBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="nl"&gt;mainAxisSize:&lt;/span&gt; &lt;span class="n"&gt;MainAxisSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
   &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Room Id: &lt;/span&gt;&lt;span class="si"&gt;${roomStateNotifier.roomId.value.substring(0,10)}&lt;/span&gt;&lt;span class="s"&gt;..."&lt;/span&gt;&lt;span class="p"&gt;,),&lt;/span&gt;
   &lt;span class="n"&gt;IconButton&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;onPressed:&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kd"&gt;async&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;//`Clipboard.setData` copy string to clipboard&lt;/span&gt;
   &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Clipboard&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;setData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ClipboardData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;text:&lt;/span&gt; &lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;roomId&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
   &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="nl"&gt;icon:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Icon&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Icons&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;copy&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt;
  &lt;span class="p"&gt;]),&lt;/span&gt;
 &lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="c1"&gt;// Remote user video tile and name&lt;/span&gt;
&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Row&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;mainAxisSize:&lt;/span&gt; &lt;span class="n"&gt;MainAxisSize&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;min&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
   &lt;span class="nl"&gt;children:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="n"&gt;Container&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
     &lt;span class="nl"&gt;height:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;100&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
     &lt;span class="nl"&gt;padding:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;EdgeInsets&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nl"&gt;left:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
     &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;ClipRRect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
      &lt;span class="nl"&gt;borderRadius:&lt;/span&gt; &lt;span class="n"&gt;BorderRadius&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;circular&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
      &lt;span class="nl"&gt;child:&lt;/span&gt; &lt;span class="n"&gt;VideoView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
       &lt;span class="nl"&gt;meetingParticipant:&lt;/span&gt;
       &lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
      &lt;span class="p"&gt;),&lt;/span&gt;
     &lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;SizedBox&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
 &lt;span class="nl"&gt;width:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
 &lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="n"&gt;roomStateNotifier&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;remotePeer&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="o"&gt;!.&lt;/span&gt;&lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nl"&gt;style:&lt;/span&gt; &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TextStyle&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
   &lt;span class="nl"&gt;color:&lt;/span&gt; &lt;span class="n"&gt;Colors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;black&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nl"&gt;fontWeight:&lt;/span&gt; &lt;span class="n"&gt;FontWeight&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;),&lt;/span&gt;
 &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="n"&gt;Spacer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
 &lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To meet the specific requirement, it's essential to include a &lt;code&gt;meetingParticipant&lt;/code&gt; parameter, assigning it the value of &lt;code&gt;remotePeer&lt;/code&gt;. This value is stored within the &lt;code&gt;onParticipantJoin&lt;/code&gt; override function.&lt;/p&gt;

&lt;p&gt;By incorporating the &lt;code&gt;meetingParticipant&lt;/code&gt; parameter and accessing the stored &lt;code&gt;remotePeer&lt;/code&gt; value, we guarantee the accurate rendering of the video stream for the respective participant. This synchronization ensures that the appropriate participant's video feed is correctly displayed within the &lt;code&gt;VideoView&lt;/code&gt; widget.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Conclusion&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Congratulations! If you've reached here, it's checkmate for this blog. You've successfully added live video calling to chess and made it multiplayer using Flutter, Dyte video calling SDK, and GetX for expert state management. By integrating these tools, you're empowered to construct a gaming encounter that's not only immersive but also teeming with interactivity.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dyte-io/collaborative-chess"&gt;Here's&lt;/a&gt; the source code for the full project.&lt;/p&gt;

&lt;p&gt;By harnessing the versatile capabilities of Flutter, you've fashioned a visually captivating and responsive UI across different platforms. The Dyte video calling plugin has bridged geographical gaps, enabling players to engage in real-time bouts of strategic prowess, regardless of location. Lastly, the seamless integration of GetX ensures the game's state remains effortlessly manageable, culminating in an immersive gaming escapade for your users.&lt;/p&gt;

&lt;p&gt;Yet, this journey into game development is but the opening chapter. The canvas for expanding and enriching your chess prowess is boundless. Think about infusing features like game statistics to track progress, player rankings to heighten competition, or even exploring novel game modes to keep users enthralled and amused. You're bound to gain tempo.&lt;/p&gt;

&lt;p&gt;It's time we stop the clock and offer you a handshake. Until next time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Get better insights on leveraging Dyte’s technology and discover how it can revolutionize your app’s communication capabilities with its &lt;a href="https://dyte.io/video-sdk"&gt;SDKs&lt;/a&gt;.&lt;/strong&gt;&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
