Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion lib/src/chatbox.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:async';

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

typedef SendMessageHandler = void Function(SendMessageEvent event);
typedef TranslationToggledHandler = void Function(TranslationToggledEvent event);
typedef LoadingStateHandler = void Function(LoadingState state);

class SendMessageEvent {
final ConversationData conversation;
Expand All @@ -36,6 +38,8 @@ class TranslationToggledEvent {
isEnabled = json['isEnabled'];
}

enum LoadingState { loading, loaded }

/// A messaging UI for just a single conversation.
///
/// Create a Chatbox through [Session.createChatbox] and then call [mount] to show it.
Expand All @@ -57,6 +61,7 @@ class ChatBox extends StatefulWidget {

final SendMessageHandler? onSendMessage;
final TranslationToggledHandler? onTranslationToggled;
final LoadingStateHandler? onLoadingStateChanged;

const ChatBox({
Key? key,
Expand All @@ -73,6 +78,7 @@ class ChatBox extends StatefulWidget {
this.asGuest,
this.onSendMessage,
this.onTranslationToggled,
this.onLoadingStateChanged,
}) : super(key: key);

@override
Expand Down Expand Up @@ -121,14 +127,18 @@ class ChatBoxState extends State<ChatBox> {
// If it's the first time that the widget is built, then build everything
_webViewCreated = true;

// Here a Timer is needed, as we can't change the widget's state while the widget
// is being constructed, and the callback may very possibly change the state
Timer.run(() => widget.onLoadingStateChanged?.call(LoadingState.loading));

execute('let chatBox;');

_createSession();
_createChatBox();
// messageFilter and highlightedWords are set as options for the chatbox
_createConversation();

execute('chatBox.mount(document.getElementById("talkjs-container"));');
execute('chatBox.mount(document.getElementById("talkjs-container")).then(() => JSCLoadingState.postMessage("loaded"));');
} else {
// If it's not the first time that the widget is built,
// then check what needs to be rebuilt
Expand Down Expand Up @@ -161,6 +171,7 @@ class ChatBoxState extends State<ChatBox> {
javascriptChannels: <JavascriptChannel>{
JavascriptChannel(name: 'JSCSendMessage', onMessageReceived: _jscSendMessage),
JavascriptChannel(name: 'JSCTranslationToggled', onMessageReceived: _jscTranslationToggled),
JavascriptChannel(name: 'JSCLoadingState', onMessageReceived: _jscLoadingState),
});
}

Expand Down Expand Up @@ -339,6 +350,14 @@ class ChatBoxState extends State<ChatBox> {
widget.onTranslationToggled?.call(TranslationToggledEvent.fromJson(json.decode(message.message)));
}

void _jscLoadingState(JavascriptMessage message) {
if (kDebugMode) {
print('📗 chatbox._jscLoadingState: ${message.message}');
}

widget.onLoadingStateChanged?.call(LoadingState.loaded);
}

/// For internal use only. Implementation detail that may change anytime.
///
/// Return a string with a unique ID
Expand Down
19 changes: 18 additions & 1 deletion lib/src/conversationlist.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:convert';
import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
Expand All @@ -10,6 +11,7 @@ import './session.dart';
import './conversation.dart';
import './user.dart';
import './predicate.dart';
import './chatbox.dart';

typedef SelectConversationHandler = void Function(SelectConversationEvent event);

Expand Down Expand Up @@ -80,6 +82,7 @@ class ConversationList extends StatefulWidget {
final ConversationPredicate feedFilter;

final SelectConversationHandler? onSelectConversation;
final LoadingStateHandler? onLoadingStateChanged;

const ConversationList({
Key? key,
Expand All @@ -88,6 +91,7 @@ class ConversationList extends StatefulWidget {
this.theme,
this.feedFilter = const ConversationPredicate(),
this.onSelectConversation,
this.onLoadingStateChanged,
}) : super(key: key);

@override
Expand Down Expand Up @@ -121,11 +125,15 @@ class ConversationListState extends State<ConversationList> {
if (!_webViewCreated) {
_webViewCreated = true;

// Here a Timer is needed, as we can't change the widget's state while the widget
// is being constructed, and the callback may very possibly change the state
Timer.run(() => widget.onLoadingStateChanged?.call(LoadingState.loading));

_createSession();
_createConversationList();
// feedFilter is set as an option for the inbox

execute('conversationList.mount(document.getElementById("talkjs-container"));');
execute('conversationList.mount(document.getElementById("talkjs-container")).then(() => JSCLoadingState.postMessage("loaded"));');
} else {
// If it's not the first time that the widget is built,
// then check what needs to be rebuilt
Expand All @@ -142,6 +150,7 @@ class ConversationListState extends State<ConversationList> {
onPageFinished: _onPageFinished,
javascriptChannels: <JavascriptChannel>{
JavascriptChannel(name: 'JSCSelectConversation', onMessageReceived: _jscSelectConversation),
JavascriptChannel(name: 'JSCLoadingState', onMessageReceived: _jscLoadingState),
});
}

Expand Down Expand Up @@ -243,6 +252,14 @@ class ConversationListState extends State<ConversationList> {
widget.onSelectConversation?.call(SelectConversationEvent.fromJson(json.decode(message.message)));
}

void _jscLoadingState(JavascriptMessage message) {
if (kDebugMode) {
print('📗 conversationlist._jscLoadingState: ${message.message}');
}

widget.onLoadingStateChanged?.call(LoadingState.loaded);
}

/// For internal use only. Implementation detail that may change anytime.
///
/// Return a string with a unique ID
Expand Down