Skip to content

Commit 1ae6972

Browse files
author
Franco Bugnano
committed
Implemented the onLoadingStateChanged callback
1 parent af5fbf7 commit 1ae6972

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

lib/src/chatbox.dart

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'dart:convert';
2+
import 'dart:async';
23

34
import 'package:flutter/material.dart';
45
import 'package:flutter/services.dart';
@@ -15,6 +16,7 @@ import './predicate.dart';
1516

1617
typedef SendMessageHandler = void Function(SendMessageEvent event);
1718
typedef TranslationToggledHandler = void Function(TranslationToggledEvent event);
19+
typedef LoadingStateHandler = void Function(LoadingState state);
1820

1921
class 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,6 +127,10 @@ 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();
@@ -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

@@ -180,6 +191,23 @@ class ChatBoxState extends State<ChatBox> {
180191
execute('options["me"] = $variableName;');
181192

182193
execute('const session = new Talk.Session(options);');
194+
195+
execute('''
196+
const observer = new MutationObserver((mutations) => {
197+
for (let mutation of mutations) {
198+
for (let node of mutation.addedNodes) {
199+
if (node.nodeName.toLowerCase().indexOf('iframe') >= 0) {
200+
observer.disconnect();
201+
node.addEventListener('load', () => {
202+
JSCLoadingState.postMessage('loaded');
203+
});
204+
}
205+
}
206+
}
207+
});
208+
209+
observer.observe(document.getElementById('talkjs-container'), {childList: true});
210+
''');
183211
}
184212

185213
void _createChatBox() {
@@ -339,6 +367,14 @@ class ChatBoxState extends State<ChatBox> {
339367
widget.onTranslationToggled?.call(TranslationToggledEvent.fromJson(json.decode(message.message)));
340368
}
341369

370+
void _jscLoadingState(JavascriptMessage message) {
371+
if (kDebugMode) {
372+
print('📗 chatbox._jscLoadingState: ${message.message}');
373+
}
374+
375+
widget.onLoadingStateChanged?.call(LoadingState.loaded);
376+
}
377+
342378
/// For internal use only. Implementation detail that may change anytime.
343379
///
344380
/// Return a string with a unique ID

lib/src/conversationlist.dart

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'dart:convert';
2+
import 'dart:async';
23

34
import 'package:flutter/material.dart';
45
import 'package:flutter/services.dart';
@@ -10,6 +11,7 @@ import './session.dart';
1011
import './conversation.dart';
1112
import './user.dart';
1213
import './predicate.dart';
14+
import './chatbox.dart';
1315

1416
typedef SelectConversationHandler = void Function(SelectConversationEvent event);
1517

@@ -80,6 +82,7 @@ class ConversationList extends StatefulWidget {
8082
final ConversationPredicate feedFilter;
8183

8284
final SelectConversationHandler? onSelectConversation;
85+
final LoadingStateHandler? onLoadingStateChanged;
8386

8487
const ConversationList({
8588
Key? key,
@@ -88,6 +91,7 @@ class ConversationList extends StatefulWidget {
8891
this.theme,
8992
this.feedFilter = const ConversationPredicate(),
9093
this.onSelectConversation,
94+
this.onLoadingStateChanged,
9195
}) : super(key: key);
9296

9397
@override
@@ -121,6 +125,10 @@ class ConversationListState extends State<ConversationList> {
121125
if (!_webViewCreated) {
122126
_webViewCreated = true;
123127

128+
// Here a Timer is needed, as we can't change the widget's state while the widget
129+
// is being constructed, and the callback may very possibly change the state
130+
Timer.run(() => widget.onLoadingStateChanged?.call(LoadingState.loading));
131+
124132
_createSession();
125133
_createConversationList();
126134
// feedFilter is set as an option for the inbox
@@ -142,6 +150,7 @@ class ConversationListState extends State<ConversationList> {
142150
onPageFinished: _onPageFinished,
143151
javascriptChannels: <JavascriptChannel>{
144152
JavascriptChannel(name: 'JSCSelectConversation', onMessageReceived: _jscSelectConversation),
153+
JavascriptChannel(name: 'JSCLoadingState', onMessageReceived: _jscLoadingState),
145154
});
146155
}
147156

@@ -161,6 +170,23 @@ class ConversationListState extends State<ConversationList> {
161170
execute('options["me"] = $variableName;');
162171

163172
execute('const session = new Talk.Session(options);');
173+
174+
execute('''
175+
const observer = new MutationObserver((mutations) => {
176+
for (let mutation of mutations) {
177+
for (let node of mutation.addedNodes) {
178+
if (node.nodeName.toLowerCase().indexOf('iframe') >= 0) {
179+
observer.disconnect();
180+
node.addEventListener('load', () => {
181+
JSCLoadingState.postMessage('loaded');
182+
});
183+
}
184+
}
185+
}
186+
});
187+
188+
observer.observe(document.getElementById('talkjs-container'), {childList: true});
189+
''');
164190
}
165191

166192
void _createConversationList() {
@@ -243,6 +269,14 @@ class ConversationListState extends State<ConversationList> {
243269
widget.onSelectConversation?.call(SelectConversationEvent.fromJson(json.decode(message.message)));
244270
}
245271

272+
void _jscLoadingState(JavascriptMessage message) {
273+
if (kDebugMode) {
274+
print('📗 conversationlist._jscLoadingState: ${message.message}');
275+
}
276+
277+
widget.onLoadingStateChanged?.call(LoadingState.loaded);
278+
}
279+
246280
/// For internal use only. Implementation detail that may change anytime.
247281
///
248282
/// Return a string with a unique ID

0 commit comments

Comments
 (0)