Skip to content

Commit b60e6d6

Browse files
committed
Refactor flutter_html_audio and flutter_html_video
1 parent d1a6b49 commit b60e6d6

File tree

8 files changed

+131
-85
lines changed

8 files changed

+131
-85
lines changed

example/lib/main.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import 'package:flutter/material.dart';
22
import 'package:flutter_html/flutter_html.dart';
3-
import 'package:flutter_html_math/flutter_html_math.dart';
3+
import 'package:flutter_html_all/flutter_html_all.dart';
44

55
void main() => runApp(const MyApp());
66

lib/src/extension/extension.dart

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import 'package:flutter/painting.dart';
22
import 'package:flutter_html/src/extension/extension_context.dart';
3+
import 'package:flutter_html/src/style.dart';
34
import 'package:flutter_html/src/tree/styled_element.dart';
45

56
export 'package:flutter_html/src/extension/extension_context.dart';
@@ -29,25 +30,36 @@ abstract class Extension {
2930
return supportedTags.contains(context.elementName);
3031
}
3132

32-
// Converts parsed HTML to a StyledElement.
33+
/// Converts parsed HTML to a StyledElement.
3334
StyledElement lex(ExtensionContext context, List<StyledElement> children) {
34-
throw UnimplementedError("Extension `$runtimeType` matched `${context.elementName}` but didn't implement `lex`");
35+
return StyledElement(
36+
node: context.node,
37+
style: Style(),
38+
elementClasses: context.classes.toList(),
39+
elementId: context.id,
40+
children: children,
41+
name: context.elementName,
42+
);
3543
}
3644

37-
// Called before styles are applied to the tree. Default behavior: do nothing;
45+
/// Called before styles are applied to the tree. Default behavior: do nothing;
3846
void beforeStyle(ExtensionContext context) {}
3947

40-
// Called after styling, but before extra elements/whitespace has been
41-
// removed, margins collapsed, list characters processed, or relative
42-
// values calculated. Default behavior: do nothing;
48+
/// Called after styling, but before extra elements/whitespace has been
49+
/// removed, margins collapsed, list characters processed, or relative
50+
/// values calculated. Default behavior: do nothing;
4351
void beforeProcessing(ExtensionContext context) {}
4452

45-
//The final step in the chain. Converts the StyledElement tree, with its attached `Style` elements, into an `InlineSpan` tree that includes Widget/TextSpans that can be rendered in a RichText widget.
53+
/// The final step in the chain. Converts the StyledElement tree, with its
54+
/// attached `Style` elements, into an `InlineSpan` tree that includes
55+
/// Widget/TextSpans that can be rendered in a RichText widget.
4656
InlineSpan parse(ExtensionContext context, Map<StyledElement, InlineSpan> Function() parseChildren) {
4757
throw UnimplementedError("Extension `$runtimeType` matched `${context.styledElement!.name}` but didn't implement `parse`");
4858
}
4959

50-
//Called when the Html widget is being destroyed. This would be a very good place to dispose() any controllers or free any resources that the extension uses. Default behavior: do nothing.
60+
/// Called when the Html widget is being destroyed. This would be a very
61+
/// good place to dispose() any controllers or free any resources that
62+
/// the extension uses. Default behavior: do nothing.
5163
void onDispose() {
5264
// Subclasses may override this to clean up when the extension is being disposed.
5365
}

lib/src/extension/extension_context.dart

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,16 @@ class ExtensionContext {
1111
/// The HTML node being represented as a Flutter widget.
1212
final html.Node node;
1313

14+
/// Returns the reference to the Html element if this Html node represents
15+
/// and element. Otherwise returns null.
16+
html.Element? get element {
17+
if(node is html.Element) {
18+
return (node as html.Element);
19+
}
20+
21+
return null;
22+
}
23+
1424
/// Returns the name of the Html element, or an empty string if the node is
1525
/// a text content node, comment node, or any other node without a name.
1626
String get elementName {

packages/flutter_html_audio/lib/flutter_html_audio.dart

Lines changed: 37 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,37 @@ import 'package:flutter_html/flutter_html.dart';
66
import 'package:video_player/video_player.dart';
77
import 'package:html/dom.dart' as dom;
88

9-
typedef AudioControllerCallback = void Function(
10-
dom.Element?, ChewieAudioController, VideoPlayerController);
9+
/// [AudioHtmlExtension] adds support for the <audio> tag to the flutter_html
10+
/// library.
11+
class AudioHtmlExtension extends Extension {
12+
13+
final AudioControllerCallback? audioControllerCallback;
14+
15+
const AudioHtmlExtension({
16+
this.audioControllerCallback,
17+
});
1118

12-
/// The CustomRender function for the `<audio>` tag
13-
CustomRender audioRender({AudioControllerCallback? onControllerCreated}) =>
14-
CustomRender.widget(
15-
widget: (context, buildChildren) => AudioWidget(
19+
@override
20+
Set<String> get supportedTags => {"audio"};
21+
22+
@override
23+
InlineSpan parse(ExtensionContext context, parseChildren) {
24+
return WidgetSpan(
25+
child: AudioWidget(
1626
context: context,
17-
callback: onControllerCreated,
18-
),
27+
callback: audioControllerCallback,
28+
)
1929
);
30+
}
2031

21-
/// The CustomRenderMatcher that will match the `<audio>` tag
22-
CustomRenderMatcher audioMatcher() => (context) {
23-
return context.tree.element?.localName == "audio";
24-
};
32+
}
33+
34+
typedef AudioControllerCallback = void Function(
35+
dom.Element?, ChewieAudioController, VideoPlayerController);
2536

2637
/// A widget used for rendering an audio player in the HTML tree
2738
class AudioWidget extends StatefulWidget {
28-
final RenderContext context;
39+
final ExtensionContext context;
2940
final AudioControllerCallback? callback;
3041

3142
const AudioWidget({
@@ -46,25 +57,27 @@ class _AudioWidgetState extends State<AudioWidget> {
4657
@override
4758
void initState() {
4859
sources = <String?>[
49-
if (widget.context.tree.element?.attributes['src'] != null)
50-
widget.context.tree.element!.attributes['src'],
51-
...ReplacedElement.parseMediaSources(
52-
widget.context.tree.element!.children),
60+
if (widget.context.attributes['src'] != null)
61+
widget.context.attributes['src'],
62+
...ReplacedElement.parseMediaSources(widget.context.node.children),
5363
];
64+
5465
if (sources.isNotEmpty && sources.first != null) {
5566
audioController = VideoPlayerController.network(
5667
sources.first ?? "",
5768
);
5869
chewieAudioController = ChewieAudioController(
5970
videoPlayerController: audioController!,
60-
autoPlay: widget.context.tree.element?.attributes['autoplay'] != null,
61-
looping: widget.context.tree.element?.attributes['loop'] != null,
62-
showControls:
63-
widget.context.tree.element?.attributes['controls'] != null,
71+
autoPlay: widget.context.attributes['autoplay'] != null,
72+
looping: widget.context.attributes['loop'] != null,
73+
showControls: widget.context.attributes['controls'] != null,
6474
autoInitialize: true,
6575
);
66-
widget.callback?.call(widget.context.tree.element, chewieAudioController!,
67-
audioController!);
76+
widget.callback?.call(
77+
widget.context.element,
78+
chewieAudioController!,
79+
audioController!,
80+
);
6881
}
6982
super.initState();
7083
}
@@ -83,8 +96,7 @@ class _AudioWidgetState extends State<AudioWidget> {
8396
}
8497

8598
return CssBoxWidget(
86-
key: widget.context.key,
87-
style: widget.context.style,
99+
style: widget.context.styledElement!.style,
88100
childIsReplaced: true,
89101
child: ChewieAudio(
90102
controller: chewieAudioController!,

packages/flutter_html_audio/pubspec.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ dependencies:
1212
sdk: flutter
1313
html: '>=0.15.0 <1.0.0'
1414
flutter_html: ^3.0.0-alpha.6
15-
# flutter_html:
16-
# path: ../..
17-
1815
video_player: '>=2.2.8 <3.0.0'
1916
chewie_audio: '>=1.3.0 <2.0.0'
2017

packages/flutter_html_math/lib/flutter_html_math.dart

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,36 @@ import 'package:flutter_math_fork/flutter_math.dart';
77

88
export 'package:flutter_math_fork/flutter_math.dart';
99

10-
class MathHtmlExtension extends TagExtension {
10+
/// [MathHtmlExtension] adds support for the <math> tag to the flutter_html
11+
/// library.
12+
class MathHtmlExtension extends Extension {
1113

12-
MathHtmlExtension({OnMathErrorBuilder? onMathErrorBuilder}): super(
13-
tagsToExtend: {"math"},
14-
builder: (context) => _renderMath(context, onMathErrorBuilder),
15-
);
14+
final OnMathErrorBuilder? onMathErrorBuilder;
1615

17-
static Widget _renderMath(ExtensionContext context, OnMathErrorBuilder? onMathError) {
16+
const MathHtmlExtension({this.onMathErrorBuilder});
17+
18+
@override
19+
Set<String> get supportedTags => {"math"};
20+
21+
@override
22+
InlineSpan parse(ExtensionContext context, parseChildren) {
1823
String texStr = _parseMathRecursive(context.styledElement!.element!, '');
19-
return CssBoxWidget(
20-
style: context.styledElement!.style,
21-
childIsReplaced: true,
22-
child: Math.tex(
23-
texStr,
24-
mathStyle: MathStyle.display,
25-
textStyle: context.styledElement!.style.generateTextStyle(),
26-
onErrorFallback: (FlutterMathException e) {
27-
if (onMathError != null) {
28-
return onMathError.call(texStr, e.message, e.messageWithType);
29-
} else {
30-
return Text(e.message);
31-
}
32-
},
24+
return WidgetSpan(
25+
child: CssBoxWidget(
26+
style: context.styledElement!.style,
27+
childIsReplaced: true,
28+
child: Math.tex(
29+
texStr,
30+
mathStyle: MathStyle.display,
31+
textStyle: context.styledElement!.style.generateTextStyle(),
32+
onErrorFallback: (FlutterMathException e) {
33+
if (onMathErrorBuilder != null) {
34+
return onMathErrorBuilder!.call(texStr, e.message, e.messageWithType);
35+
} else {
36+
return Text(e.message);
37+
}
38+
},
39+
),
3340
),
3441
);
3542
}
@@ -90,9 +97,7 @@ String _parseMathRecursive(dom.Node node, String parsed) {
9097
node.localName == "mn" ||
9198
node.localName == "mo") {
9299
if (_mathML2Tex.keys.contains(node.text.trim())) {
93-
parsed = parsed +
94-
_mathML2Tex[
95-
_mathML2Tex.keys.firstWhere((e) => e == node.text.trim())]!;
100+
parsed = parsed + _mathML2Tex[node.text.trim()]!;
96101
} else if (node.text.startsWith("&") && node.text.endsWith(";")) {
97102
parsed = parsed +
98103
node.text

packages/flutter_html_video/lib/flutter_html_video.dart

Lines changed: 35 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,34 @@ import 'package:video_player/video_player.dart';
88
import 'package:html/dom.dart' as dom;
99
import 'dart:io';
1010

11-
typedef VideoControllerCallback = void Function(
12-
dom.Element?, ChewieController, VideoPlayerController);
11+
/// [VideoHtmlExtension] adds support for the <video> tag to the flutter_html
12+
/// library.
13+
class VideoHtmlExtension extends Extension {
14+
final VideoControllerCallback? videoControllerCallback;
15+
16+
const VideoHtmlExtension({
17+
this.videoControllerCallback,
18+
});
19+
20+
@override
21+
Set<String> get supportedTags => {"video"};
1322

14-
/// A CustomRender function for rendering the <video> HTML tag.
15-
CustomRender videoRender({VideoControllerCallback? onControllerCreated}) =>
16-
CustomRender.widget(
17-
widget: (context, buildChildren) =>
18-
VideoWidget(context: context, callback: onControllerCreated));
23+
@override
24+
InlineSpan parse(ExtensionContext context, parseChildren) {
25+
return WidgetSpan(
26+
child: VideoWidget(
27+
context: context,
28+
callback: videoControllerCallback,
29+
));
30+
}
31+
}
1932

20-
/// A CustomRenderMatcher for the <video> HTML tag
21-
CustomRenderMatcher videoMatcher() => (context) {
22-
return context.tree.element?.localName == "video";
23-
};
33+
typedef VideoControllerCallback = void Function(
34+
dom.Element?, ChewieController, VideoPlayerController);
2435

2536
/// A VideoWidget for displaying within the HTML tree.
2637
class VideoWidget extends StatefulWidget {
27-
final RenderContext context;
38+
final ExtensionContext context;
2839
final VideoControllerCallback? callback;
2940
final List<DeviceOrientation>? deviceOrientationsOnEnterFullScreen;
3041
final List<DeviceOrientation> deviceOrientationsAfterFullScreen;
@@ -49,14 +60,16 @@ class _VideoWidgetState extends State<VideoWidget> {
4960

5061
@override
5162
void initState() {
52-
final attributes = widget.context.tree.element?.attributes ?? {};
63+
final attributes = widget.context.attributes;
64+
5365
final sources = <String?>[
5466
if (attributes['src'] != null) attributes['src'],
55-
...ReplacedElement.parseMediaSources(
56-
widget.context.tree.element!.children),
67+
...ReplacedElement.parseMediaSources(widget.context.node.children),
5768
];
69+
5870
final givenWidth = double.tryParse(attributes['width'] ?? "");
5971
final givenHeight = double.tryParse(attributes['height'] ?? "");
72+
6073
if (sources.isNotEmpty && sources.first != null) {
6174
_width = givenWidth ?? (givenHeight ?? 150) * 2;
6275
_height = givenHeight ?? (givenWidth ?? 300) / 2;
@@ -92,7 +105,10 @@ class _VideoWidgetState extends State<VideoWidget> {
92105
widget.deviceOrientationsAfterFullScreen,
93106
);
94107
widget.callback?.call(
95-
widget.context.tree.element, _chewieController!, _videoController!);
108+
widget.context.element,
109+
_chewieController!,
110+
_videoController!,
111+
);
96112
}
97113
super.initState();
98114
}
@@ -109,15 +125,12 @@ class _VideoWidgetState extends State<VideoWidget> {
109125
if (_chewieController == null) {
110126
return const SizedBox(height: 0, width: 0);
111127
}
112-
final child = Container(
113-
key: widget.context.key,
128+
129+
return AspectRatio(
130+
aspectRatio: _width! / _height!,
114131
child: Chewie(
115132
controller: _chewieController!,
116133
),
117134
);
118-
return AspectRatio(
119-
aspectRatio: _width! / _height!,
120-
child: child,
121-
);
122135
}
123136
}

packages/flutter_html_video/pubspec.yaml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ dependencies:
1212
sdk: flutter
1313
html: '>=0.15.0 <1.0.0'
1414
flutter_html: ^3.0.0-alpha.6
15-
# flutter_html:
16-
# path: ../..
17-
1815
video_player: '>=2.2.8 <3.0.0'
1916
chewie: '>=1.1.0 <2.0.0'
2017

0 commit comments

Comments
 (0)