1+ import 'dart:collection' ;
2+
13import 'package:flutter/material.dart' ;
24import 'package:chative_sdk/src/webview.dart' ;
35import 'package:chative_sdk/src/utils.dart' ;
@@ -7,41 +9,102 @@ typedef OnLoaded = void Function();
79typedef OnNewMessage = void Function ();
810typedef OnError = void Function (String message);
911
12+ /// Controller for managing the ChativeWidget's state and interactions
1013class 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+ }
1230
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
1341 void show () {
14- _state.show ();
42+ _enqueueOrExecute (() {
43+ _state! .show ();
44+ });
1545 }
1646
47+ /// Function to hide the ChativeWidget
1748 void hide () {
18- _state.hide ();
49+ _enqueueOrExecute (() {
50+ _state! .hide ();
51+ });
1952 }
2053
54+ /// Inject JavaScript code into the WebView
2155 Future <void > injectJavascript (String script) async {
22- await _state.injectJavaScript (script);
56+ _enqueueOrExecute (() async {
57+ await _state! .injectJavaScript (script);
58+ });
2359 }
2460
61+ /// Reloads the WebView content
2562 Future <void > reload () async {
26- await _state.reload ();
63+ _enqueueOrExecute (() async {
64+ await _state! .reload ();
65+ });
2766 }
2867
68+ /// Clears the WebView's local storage
2969 Future <void > clearData () async {
30- await _state.clearLocalStorage ();
70+ _enqueueOrExecute (() async {
71+ await _state! .clearLocalStorage ();
72+ });
3173 }
3274}
3375
76+ /// A StatefulWidget that displays a chat interface using WebView
3477class ChativeWidget extends StatefulWidget {
3578 final ChativeWidgetController ? controller;
79+
80+ /// The channel ID to be used for the chat widget
3681 final String channelId;
82+
83+ /// The user data to be passed to the chat widget
3784 final Map <String , dynamic >? user;
85+
86+ /// The widget to be displayed as the header of the chat widget
3887 final Widget ? headerWidget;
88+
89+ /// The decoration to be applied to the chat widget container
3990 final BoxDecoration ? containerDecoration;
91+
92+ /// The top inset of the chat widget
4093 final double insetTop;
94+
95+ /// The bottom inset of the chat widget
4196 final double insetBottom;
97+
98+ /// Callback function to be called when the chat widget is closed
4299 final OnClosed ? onClosed;
100+
101+ /// Callback function to be called when the chat widget is loaded
43102 final OnLoaded ? onLoaded;
103+
104+ /// Callback function to be called when a new message is received
44105 final OnNewMessage ? onNewMessage;
106+
107+ /// Callback function to be called when an error occurs
45108 final OnError ? onError;
46109
47110 const ChativeWidget ({
@@ -65,50 +128,66 @@ class ChativeWidget extends StatefulWidget {
65128
66129class _ChativeWidgetState extends State <ChativeWidget > {
67130 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 >();
69135
70136 @override
71137 void initState () {
72138 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 );
75146 }
76147
148+ /// Shows the chat widget and sends a command to open the chat window
77149 void show () {
78150 setState (() {
79151 isVisible = true ;
80152 });
81153 injectJavaScript (widgetApi ('openChatWindow' , {}));
82154 }
83155
84- void handleClosed () {
156+ /// Hides the chat widget and sends a command to close the chat window
157+ void hide () {
85158 setState (() {
86159 isVisible = false ;
87160 });
88- injectJavaScript (widgetApi ('openChatWindow' , {}));
89- if (widget.onClosed != null ) widget.onClosed !();
90161 }
91162
92- void hide () {
163+ /// Handles the closure of the chat widget
164+ void handleClosed () {
93165 setState (() {
94166 isVisible = false ;
95167 });
168+ injectJavaScript (widgetApi ('openChatWindow' , {}));
169+ if (widget.onClosed != null ) widget.onClosed !();
96170 }
97171
172+ /// Reloads the WebView content
98173 Future <void > reload () async {
99174 await _webViewKey.currentState? .reload ();
100175 }
101176
177+ /// Injects JavaScript code into the WebView
102178 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+ }
104184 }
105185
186+ /// Clears the WebView's local storage and reloads the content
106187 Future <void > clearLocalStorage () async {
107188 await _webViewKey.currentState? .clearLocalStorage ();
108189 }
109190
110- final GlobalKey <WebviewState > _webViewKey = GlobalKey <WebviewState >();
111-
112191 @override
113192 Widget build (BuildContext context) {
114193 return Positioned (
0 commit comments