TF-105 Create HtmlContentViewer widget

This commit is contained in:
dab246
2021-10-06 09:56:54 +07:00
committed by Dat H. Pham
parent 86cdbda60b
commit a9d83852d0
3 changed files with 179 additions and 0 deletions
+1
View File
@@ -38,6 +38,7 @@ export 'presentation/views/context_menu/simple_context_menu_action_builder.dart'
export 'presentation/views/dialog/loading_dialog_builder.dart';
export 'presentation/views/dialog/downloading_file_dialog_builder.dart';
export 'presentation/views/background/background_widget_builder.dart';
export 'presentation/views/html_viewer/html_content_viewer_widget.dart';
// Resources
export 'presentation/resources/assets_paths.dart';
@@ -0,0 +1,171 @@
import 'package:core/core.dart';
import 'package:core/presentation/utils/html_transformer/html_transform.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
class _HtmlGenerationArguments {
final String message;
final bool blockExternalImages;
const _HtmlGenerationArguments(
this.message,
this.blockExternalImages,
);
}
class _HtmlGenerationResult {
final String? html;
final String? errorDetails;
const _HtmlGenerationResult.success(this.html) : errorDetails = null;
const _HtmlGenerationResult.error(this.errorDetails) : this.html = null;
}
class HtmlContentViewer extends StatefulWidget {
final String message;
final bool blockExternalImages;
/// Is notified about any errors that might occur
final void Function(Object? exception, StackTrace? stackTrace)? onError;
/// Register this callback if you want a reference to the [InAppWebViewController].
final void Function(InAppWebViewController controller)? onWebViewCreated;
const HtmlContentViewer({
Key? key,
required this.message,
this.blockExternalImages = false,
this.onError,
this.onWebViewCreated,
}) : super(key: key);
@override
State<StatefulWidget> createState() => _HtmlContentViewState();
}
class _HtmlContentViewState extends State<HtmlContentViewer> {
String? _htmlData;
bool? _wereExternalImagesBlocked;
bool _isGenerating = false;
double? _webViewContentHeight;
@override
void initState() {
_generateHtml(widget.blockExternalImages);
super.initState();
}
void _generateHtml(bool blockExternalImages) async {
_wereExternalImagesBlocked = blockExternalImages;
_isGenerating = true;
final args = _HtmlGenerationArguments(
widget.message,
blockExternalImages,
);
final result = await compute(_generateHtmlImpl, args);
_htmlData = result.html;
if (_htmlData == null) {
final onError = widget.onError;
if (onError != null) {
onError(result.errorDetails, null);
}
}
if (mounted) {
setState(() {
_isGenerating = false;
});
}
}
static _HtmlGenerationResult _generateHtmlImpl(_HtmlGenerationArguments args) {
try {
final htmlTransform = HtmlTransform(args.message);
final html = htmlTransform.transformToHtml(
blockExternalImages: args.blockExternalImages,
);
return _HtmlGenerationResult.success(html);
} catch (e, s) {
String errorDetails = e.toString() + '\n\n' + s.toString();
return _HtmlGenerationResult.error(errorDetails);
}
}
@override
Widget build(BuildContext context) {
if (_isGenerating) {
return Padding(
padding: const EdgeInsets.all(16.0),
child: Center(
child: SizedBox(
width: 30,
height: 30,
child: CircularProgressIndicator(color: AppColor.primaryColor)),
),
);
}
if (widget.blockExternalImages != _wereExternalImagesBlocked) {
_generateHtml(widget.blockExternalImages);
}
final size = MediaQuery.of(context).size;
return SizedBox(
height: _webViewContentHeight ?? size.height,
width: size.width,
child: Padding(
padding: EdgeInsets.only(top: 16),
child: _buildWebView(),
),
);
}
Widget _buildWebView() {
if (_htmlData == null) {
return Container();
}
return InAppWebView(
key: ValueKey(_htmlData),
initialData: InAppWebViewInitialData(data: _htmlData!),
initialOptions: InAppWebViewGroupOptions(
crossPlatform: InAppWebViewOptions(
useShouldOverrideUrlLoading: true,
verticalScrollBarEnabled: false,
),
android: AndroidInAppWebViewOptions(
useHybridComposition: true,
),
ios: IOSInAppWebViewOptions(
allowsInlineMediaPlayback: true,
enableViewportScale: true,
)
),
onWebViewCreated: widget.onWebViewCreated,
onLoadStop: (controller, uri) async {
var scrollHeight = (await controller.evaluateJavascript(source: 'document.body.scrollHeight'));
if (scrollHeight != null) {
final scrollWidth = (await controller.evaluateJavascript(source: 'document.body.scrollWidth'));
final size = MediaQuery.of(context).size;
if (scrollWidth > size.width) {
var scale = (size.width / scrollWidth);
if (scale < 0.2) {
scale = 0.2;
}
await controller.zoomBy(zoomFactor: scale, iosAnimated: true);
scrollHeight = (scrollHeight * scale).ceil();
}
setState(() {
_webViewContentHeight = double.tryParse('${scrollHeight + 10.0}');
});
}
},
gestureRecognizers: {
Factory<LongPressGestureRecognizer>(() => LongPressGestureRecognizer()),
},
);
}
}
+7
View File
@@ -59,6 +59,13 @@ dependencies:
# getwidget
getwidget: 2.0.4
# Used to fix bugs in the official version of flutter_inappwebview: https://githubmemory.com/repo/pichillilorenzo/flutter_inappwebview/issues/873
# flutter_inappwebview
flutter_inappwebview:
git:
url: git://github.com/robert-virkus/flutter_inappwebview.git
ref: master
dev_dependencies:
flutter_test:
sdk: flutter