1
1
library flutter_html;
2
2
3
+ import 'package:chewie/chewie.dart' ;
4
+ import 'package:chewie_audio/chewie_audio.dart' ;
3
5
import 'package:flutter/material.dart' ;
4
6
import 'package:flutter/rendering.dart' ;
5
7
import 'package:flutter_html/html_parser.dart' ;
@@ -8,6 +10,7 @@ import 'package:flutter_html/src/html_elements.dart';
8
10
import 'package:flutter_html/src/utils.dart' ;
9
11
import 'package:flutter_html/style.dart' ;
10
12
import 'package:html/dom.dart' as dom;
13
+ import 'package:video_player/video_player.dart' ;
11
14
import 'package:webview_flutter/webview_flutter.dart' ;
12
15
13
16
//export render context api
@@ -22,7 +25,7 @@ export 'package:flutter_html/src/styled_element.dart';
22
25
//export style api
23
26
export 'package:flutter_html/style.dart' ;
24
27
25
- class Html extends StatelessWidget {
28
+ class Html extends StatefulWidget {
26
29
/// The `Html` widget takes HTML as input and displays a RichText
27
30
/// tree of the parsed HTML content.
28
31
///
@@ -64,7 +67,8 @@ class Html extends StatelessWidget {
64
67
this .tagsList = const [],
65
68
this .style = const {},
66
69
this .navigationDelegateForIframe,
67
- }) : document = null ,
70
+ })
71
+ : document = null ,
68
72
assert (data != null ),
69
73
_anchorKey = anchorKey ?? GlobalKey (),
70
74
super (key: key);
@@ -85,7 +89,8 @@ class Html extends StatelessWidget {
85
89
this .tagsList = const [],
86
90
this .style = const {},
87
91
this .navigationDelegateForIframe,
88
- }) : data = null ,
92
+ })
93
+ : data = null ,
89
94
assert (document != null ),
90
95
_anchorKey = anchorKey ?? GlobalKey (),
91
96
super (key: key);
@@ -142,54 +147,124 @@ class Html extends StatelessWidget {
142
147
/// to use NavigationDelegate.
143
148
final NavigationDelegate ? navigationDelegateForIframe;
144
149
145
- static List <String > get tags => new List <String >.from (STYLED_ELEMENTS )
146
- ..addAll (INTERACTABLE_ELEMENTS )
147
- ..addAll (REPLACED_ELEMENTS )
148
- ..addAll (LAYOUT_ELEMENTS )
149
- ..addAll (TABLE_CELL_ELEMENTS )
150
- ..addAll (TABLE_DEFINITION_ELEMENTS );
150
+ /// Get the list of supported tags for the [Html] widget
151
+ static List <String > get tags =>
152
+ new List <String >.from (STYLED_ELEMENTS )
153
+ ..addAll (INTERACTABLE_ELEMENTS )..addAll (REPLACED_ELEMENTS )..addAll (
154
+ LAYOUT_ELEMENTS )..addAll (TABLE_CELL_ELEMENTS )..addAll (
155
+ TABLE_DEFINITION_ELEMENTS );
156
+
157
+ /// Protected member to track controllers used in all [Html] widgets. Please
158
+ /// refrain from using this member, and rather use the [chewieAudioControllers] ,
159
+ /// [chewieControllers] , [videoPlayerControllers] , and [audioPlayerControllers]
160
+ /// getters to access the controllers in your own code.
161
+ @protected
162
+ static final InternalControllers controllers = InternalControllers ();
163
+
164
+ /// Internal member to track controllers used in the specific [Html] widget.
165
+ /// This is only used so controllers can be automatically disposed when the
166
+ /// widget disposes.
167
+ final InternalControllers _controllers = InternalControllers ();
168
+
169
+ /// Getter for all [ChewieAudioController] s initialized by [Html] widgets.
170
+ static List <ChewieAudioController > get chewieAudioControllers => controllers.chewieAudioControllers.values.toList ();
171
+ /// Getter for all [ChewieController] s initialized by [Html] widgets.
172
+ static List <ChewieController > get chewieControllers => controllers.chewieControllers.values.toList ();
173
+ /// Getter for all [VideoPlayerController] s for video widgets initialized by [Html] widgets.
174
+ static List <VideoPlayerController > get videoPlayerControllers => controllers.videoPlayerControllers.values.toList ();
175
+ /// Getter for all [VideoPlayerController] s for audio widgets initialized by [Html] widgets.
176
+ static List <VideoPlayerController > get audioPlayerControllers => controllers.audioPlayerControllers.values.toList ();
177
+
178
+ /// Convenience method to dispose all controllers used by all [Html] widgets
179
+ /// at this time. This is not necessary to be called, as each [Html] widget
180
+ /// will automatically handle disposing.
181
+ static void disposeAll () {
182
+ controllers.chewieAudioControllers.values.forEach ((element) {
183
+ element.dispose ();
184
+ });
185
+ controllers.chewieControllers.values.forEach ((ChewieController element) {
186
+ element.dispose ();
187
+ });
188
+ controllers.videoPlayerControllers.values.forEach ((element) {
189
+ element.dispose ();
190
+ });
191
+ controllers.audioPlayerControllers.values.forEach ((element) {
192
+ element.dispose ();
193
+ });
194
+ }
151
195
152
- final InternalControllers controllers = InternalControllers ();
196
+ /// Internal method to add controllers to the global list and widget-specific
197
+ /// list. This should not be used in your app code.
198
+ void addController (int hashCode, dynamic controller, {bool isAudioController = false }) {
199
+ if (controller is ChewieAudioController ) {
200
+ controllers.chewieAudioControllers[hashCode] = controller;
201
+ _controllers.chewieAudioControllers[hashCode] = controller;
202
+ } else if (controller is ChewieController ) {
203
+ controllers.chewieControllers[hashCode] = controller;
204
+ _controllers.chewieControllers[hashCode] = controller;
205
+ } else if (controller is VideoPlayerController && ! isAudioController) {
206
+ controllers.videoPlayerControllers[hashCode] = controller;
207
+ _controllers.videoPlayerControllers[hashCode] = controller;
208
+ } else if (controller is VideoPlayerController ) {
209
+ controllers.audioPlayerControllers[hashCode] = controller;
210
+ _controllers.audioPlayerControllers[hashCode] = controller;
211
+ }
212
+ }
153
213
214
+ @override
215
+ State <StatefulWidget > createState () => _HtmlState ();
216
+ }
217
+
218
+ class _HtmlState extends State <Html > {
219
+ late final dom.Document doc;
220
+
221
+ @override
222
+ void initState () {
223
+ super .initState ();
224
+ doc =
225
+ widget.data != null ? HtmlParser .parseHTML (widget.data! ) : widget.document! ;
226
+ }
227
+
228
+ @override
154
229
void dispose () {
155
- controllers. chewieAudioControllers.forEach ((element) {
230
+ widget._controllers. chewieAudioControllers.values .forEach ((element) {
156
231
element.dispose ();
157
232
});
158
- controllers. chewieControllers.forEach ((element) {
233
+ widget._controllers. chewieControllers.values. forEach ((ChewieController element) {
159
234
element.dispose ();
160
235
});
161
- controllers. videoPlayerControllers.forEach ((element) {
236
+ widget._controllers. videoPlayerControllers.values .forEach ((element) {
162
237
element.dispose ();
163
238
});
239
+ widget._controllers.audioPlayerControllers.values.forEach ((element) {
240
+ element.dispose ();
241
+ });
242
+ super .dispose ();
164
243
}
165
244
166
245
@override
167
246
Widget build (BuildContext context) {
168
- final dom.Document doc =
169
- data != null ? HtmlParser .parseHTML (data! ) : document! ;
170
- final double ? width = shrinkWrap ? null : MediaQuery .of (context).size.width;
171
-
172
247
return Container (
173
- width: width,
248
+ width: widget.shrinkWrap ? null : MediaQuery . of (context).size. width,
174
249
child: HtmlParser (
175
- key: _anchorKey,
250
+ key: widget. _anchorKey,
176
251
htmlData: doc,
177
- onLinkTap: onLinkTap,
178
- onAnchorTap: onAnchorTap,
179
- onImageTap: onImageTap,
180
- onCssParseError: onCssParseError,
181
- onImageError: onImageError,
182
- onMathError: onMathError,
183
- shrinkWrap: shrinkWrap,
252
+ onLinkTap: widget. onLinkTap,
253
+ onAnchorTap: widget. onAnchorTap,
254
+ onImageTap: widget. onImageTap,
255
+ onCssParseError: widget. onCssParseError,
256
+ onImageError: widget. onImageError,
257
+ onMathError: widget. onMathError,
258
+ shrinkWrap: widget. shrinkWrap,
184
259
selectable: false ,
185
- style: style,
186
- customRender: customRender,
260
+ style: widget. style,
261
+ customRender: widget. customRender,
187
262
imageRenders: {}
188
- ..addAll (customImageRenders)
263
+ ..addAll (widget. customImageRenders)
189
264
..addAll (defaultImageRenders),
190
- tagsList: tagsList.isEmpty ? Html .tags : tagsList,
191
- navigationDelegateForIframe: navigationDelegateForIframe,
192
- root: this ,
265
+ tagsList: widget. tagsList.isEmpty ? Html .tags : widget. tagsList,
266
+ navigationDelegateForIframe: widget. navigationDelegateForIframe,
267
+ root: widget ,
193
268
),
194
269
);
195
270
}
@@ -297,6 +372,7 @@ class SelectableHtml extends StatelessWidget {
297
372
/// Allows you to override the default scrollPhysics for [SelectableText.rich]
298
373
final ScrollPhysics ? scrollPhysics;
299
374
375
+ /// Get the list of supported tags for the [SelectableHtml] widget
300
376
static List <String > get tags => new List <String >.from (SELECTABLE_ELEMENTS );
301
377
302
378
@override
0 commit comments