11import 'dart:convert' ;
2+ import 'dart:async' ;
23
34import 'package:flutter/material.dart' ;
45import 'package:flutter/services.dart' ;
@@ -15,6 +16,7 @@ import './predicate.dart';
1516
1617typedef SendMessageHandler = void Function (SendMessageEvent event);
1718typedef TranslationToggledHandler = void Function (TranslationToggledEvent event);
19+ typedef LoadingStateHandler = void Function (LoadingState state);
1820
1921class SendMessageEvent {
2022 final ConversationData conversation;
@@ -36,6 +38,8 @@ class TranslationToggledEvent {
3638 isEnabled = json['isEnabled' ];
3739}
3840
41+ enum LoadingState { loading, loaded }
42+
3943/// A messaging UI for just a single conversation.
4044///
4145/// Create a Chatbox through [Session.createChatbox] and then call [mount] to show it.
@@ -57,6 +61,7 @@ class ChatBox extends StatefulWidget {
5761
5862 final SendMessageHandler ? onSendMessage;
5963 final TranslationToggledHandler ? onTranslationToggled;
64+ final LoadingStateHandler ? onLoadingStateChanged;
6065
6166 const ChatBox ({
6267 Key ? key,
@@ -73,6 +78,7 @@ class ChatBox extends StatefulWidget {
7378 this .asGuest,
7479 this .onSendMessage,
7580 this .onTranslationToggled,
81+ this .onLoadingStateChanged,
7682 }) : super (key: key);
7783
7884 @override
@@ -121,14 +127,18 @@ class ChatBoxState extends State<ChatBox> {
121127 // If it's the first time that the widget is built, then build everything
122128 _webViewCreated = true ;
123129
130+ // Here a Timer is needed, as we can't change the widget's state while the widget
131+ // is being constructed, and the callback may very possibly change the state
132+ Timer .run (() => widget.onLoadingStateChanged? .call (LoadingState .loading));
133+
124134 execute ('let chatBox;' );
125135
126136 _createSession ();
127137 _createChatBox ();
128138 // messageFilter and highlightedWords are set as options for the chatbox
129139 _createConversation ();
130140
131- execute ('chatBox.mount(document.getElementById("talkjs-container"));' );
141+ execute ('chatBox.mount(document.getElementById("talkjs-container")).then(() => JSCLoadingState.postMessage("loaded")) ;' );
132142 } else {
133143 // If it's not the first time that the widget is built,
134144 // then check what needs to be rebuilt
@@ -161,6 +171,7 @@ class ChatBoxState extends State<ChatBox> {
161171 javascriptChannels: < JavascriptChannel > {
162172 JavascriptChannel (name: 'JSCSendMessage' , onMessageReceived: _jscSendMessage),
163173 JavascriptChannel (name: 'JSCTranslationToggled' , onMessageReceived: _jscTranslationToggled),
174+ JavascriptChannel (name: 'JSCLoadingState' , onMessageReceived: _jscLoadingState),
164175 });
165176 }
166177
@@ -339,6 +350,14 @@ class ChatBoxState extends State<ChatBox> {
339350 widget.onTranslationToggled? .call (TranslationToggledEvent .fromJson (json.decode (message.message)));
340351 }
341352
353+ void _jscLoadingState (JavascriptMessage message) {
354+ if (kDebugMode) {
355+ print ('📗 chatbox._jscLoadingState: ${message .message }' );
356+ }
357+
358+ widget.onLoadingStateChanged? .call (LoadingState .loaded);
359+ }
360+
342361 /// For internal use only. Implementation detail that may change anytime.
343362 ///
344363 /// Return a string with a unique ID
0 commit comments