1
+ import 'dart:collection' ;
2
+
1
3
import 'package:flutter/material.dart' ;
2
4
import 'package:chative_sdk/src/webview.dart' ;
3
5
import 'package:chative_sdk/src/utils.dart' ;
@@ -7,41 +9,102 @@ typedef OnLoaded = void Function();
7
9
typedef OnNewMessage = void Function ();
8
10
typedef OnError = void Function (String message);
9
11
12
+ /// Controller for managing the ChativeWidget's state and interactions
10
13
class ChativeWidgetController {
11
- late _ChativeWidgetState _state;
14
+ _ChativeWidgetState ? _state;
15
+ final Queue <Function > _actionQueue = Queue <Function >();
16
+
17
+ /// Sets the state of the ChativeWidget
18
+ void _setState (_ChativeWidgetState state) {
19
+ _state = state;
20
+ _processQueue ();
21
+ }
22
+
23
+ /// Processes the action queue
24
+ void _processQueue () {
25
+ while (_actionQueue.isNotEmpty) {
26
+ final action = _actionQueue.removeFirst ();
27
+ action ();
28
+ }
29
+ }
12
30
31
+ /// Enqueues an action to be executed when the state is set
32
+ void _enqueueOrExecute (Function action) {
33
+ if (_state != null ) {
34
+ action ();
35
+ } else {
36
+ _actionQueue.add (action);
37
+ }
38
+ }
39
+
40
+ /// Function to show the ChativeWidget
13
41
void show () {
14
- _state.show ();
42
+ _enqueueOrExecute (() {
43
+ _state! .show ();
44
+ });
15
45
}
16
46
47
+ /// Function to hide the ChativeWidget
17
48
void hide () {
18
- _state.hide ();
49
+ _enqueueOrExecute (() {
50
+ _state! .hide ();
51
+ });
19
52
}
20
53
54
+ /// Inject JavaScript code into the WebView
21
55
Future <void > injectJavascript (String script) async {
22
- await _state.injectJavaScript (script);
56
+ _enqueueOrExecute (() async {
57
+ await _state! .injectJavaScript (script);
58
+ });
23
59
}
24
60
61
+ /// Reloads the WebView content
25
62
Future <void > reload () async {
26
- await _state.reload ();
63
+ _enqueueOrExecute (() async {
64
+ await _state! .reload ();
65
+ });
27
66
}
28
67
68
+ /// Clears the WebView's local storage
29
69
Future <void > clearData () async {
30
- await _state.clearLocalStorage ();
70
+ _enqueueOrExecute (() async {
71
+ await _state! .clearLocalStorage ();
72
+ });
31
73
}
32
74
}
33
75
76
+ /// A StatefulWidget that displays a chat interface using WebView
34
77
class ChativeWidget extends StatefulWidget {
35
78
final ChativeWidgetController ? controller;
79
+
80
+ /// The channel ID to be used for the chat widget
36
81
final String channelId;
82
+
83
+ /// The user data to be passed to the chat widget
37
84
final Map <String , dynamic >? user;
85
+
86
+ /// The widget to be displayed as the header of the chat widget
38
87
final Widget ? headerWidget;
88
+
89
+ /// The decoration to be applied to the chat widget container
39
90
final BoxDecoration ? containerDecoration;
91
+
92
+ /// The top inset of the chat widget
40
93
final double insetTop;
94
+
95
+ /// The bottom inset of the chat widget
41
96
final double insetBottom;
97
+
98
+ /// Callback function to be called when the chat widget is closed
42
99
final OnClosed ? onClosed;
100
+
101
+ /// Callback function to be called when the chat widget is loaded
43
102
final OnLoaded ? onLoaded;
103
+
104
+ /// Callback function to be called when a new message is received
44
105
final OnNewMessage ? onNewMessage;
106
+
107
+ /// Callback function to be called when an error occurs
45
108
final OnError ? onError;
46
109
47
110
const ChativeWidget ({
@@ -65,50 +128,66 @@ class ChativeWidget extends StatefulWidget {
65
128
66
129
class _ChativeWidgetState extends State <ChativeWidget > {
67
130
bool isVisible = false ;
68
- late ChativeWidgetController controller;
131
+ late ChativeWidgetController _controller;
132
+
133
+ /// Key to access the WebViewState
134
+ final GlobalKey <WebviewState > _webViewKey = GlobalKey <WebviewState >();
69
135
70
136
@override
71
137
void initState () {
72
138
super .initState ();
73
- controller = widget.controller ?? ChativeWidgetController ();
74
- controller._state = this ;
139
+ _initializeController ();
140
+ }
141
+
142
+ /// Initializes the controller, either using the provided one or creating a new instance
143
+ void _initializeController () {
144
+ _controller = widget.controller ?? ChativeWidgetController ();
145
+ _controller._setState (this );
75
146
}
76
147
148
+ /// Shows the chat widget and sends a command to open the chat window
77
149
void show () {
78
150
setState (() {
79
151
isVisible = true ;
80
152
});
81
153
injectJavaScript (widgetApi ('openChatWindow' , {}));
82
154
}
83
155
84
- void handleClosed () {
156
+ /// Hides the chat widget and sends a command to close the chat window
157
+ void hide () {
85
158
setState (() {
86
159
isVisible = false ;
87
160
});
88
- injectJavaScript (widgetApi ('openChatWindow' , {}));
89
- if (widget.onClosed != null ) widget.onClosed !();
90
161
}
91
162
92
- void hide () {
163
+ /// Handles the closure of the chat widget
164
+ void handleClosed () {
93
165
setState (() {
94
166
isVisible = false ;
95
167
});
168
+ injectJavaScript (widgetApi ('openChatWindow' , {}));
169
+ if (widget.onClosed != null ) widget.onClosed !();
96
170
}
97
171
172
+ /// Reloads the WebView content
98
173
Future <void > reload () async {
99
174
await _webViewKey.currentState? .reload ();
100
175
}
101
176
177
+ /// Injects JavaScript code into the WebView
102
178
Future <void > injectJavaScript (dynamic script) async {
103
- await _webViewKey.currentState? .injectJavaScript (script);
179
+ if (isScriptSafe (script)) {
180
+ await _webViewKey.currentState? .injectJavaScript (script);
181
+ } else {
182
+ widget.onError? .call ('unsafe_script' );
183
+ }
104
184
}
105
185
186
+ /// Clears the WebView's local storage and reloads the content
106
187
Future <void > clearLocalStorage () async {
107
188
await _webViewKey.currentState? .clearLocalStorage ();
108
189
}
109
190
110
- final GlobalKey <WebviewState > _webViewKey = GlobalKey <WebviewState >();
111
-
112
191
@override
113
192
Widget build (BuildContext context) {
114
193
return Positioned (
0 commit comments