11import 'dart:async' ;
2+ import 'dart:convert' ;
23import 'dart:io' ;
34import 'dart:typed_data' ;
45
@@ -8,10 +9,9 @@ import 'package:flutter/cupertino.dart';
89import 'package:flutter/foundation.dart' ;
910import 'package:flutter/gestures.dart' ;
1011import 'package:flutter/material.dart' ;
11- import 'package:flutter/widgets.dart' ;
12- import 'package:flutter_inappwebview/flutter_inappwebview.dart' ;
1312import 'package:enough_mail_html/enough_mail_html.dart' ;
1413import 'package:url_launcher/url_launcher.dart' as launcher;
14+ import 'package:webview_flutter/webview_flutter.dart' ;
1515
1616import 'mime_media_provider.dart' ;
1717
@@ -50,10 +50,10 @@ class MimeMessageViewer extends StatelessWidget {
5050 final Future <bool > Function (String url)? urlLauncherDelegate;
5151
5252 /// Register this callback if you want a reference to the [InAppWebViewController] .
53- final void Function (InAppWebViewController controller)? onWebViewCreated;
53+ final void Function (WebViewController controller)? onWebViewCreated;
5454
5555 /// This callback will be called when the webview zooms out after loading, usually this is a sign that the user might want to zoom in again.
56- final void Function (InAppWebViewController controller, double zoomFactor)?
56+ final void Function (WebViewController controller, double zoomFactor)?
5757 onZoomed;
5858
5959 /// Is notified about any errors that might occur
@@ -157,6 +157,8 @@ class _HtmlViewerState extends State<_HtmlMimeMessageViewer> {
157157 double ? _webViewHeight;
158158 bool _isHtmlMessage = true ;
159159
160+ late WebViewController _controller;
161+
160162 @override
161163 void initState () {
162164 _generateHtml (widget.config.blockExternalImages,
@@ -203,7 +205,14 @@ class _HtmlViewerState extends State<_HtmlMimeMessageViewer> {
203205 emptyMessageText: args.emptyMessageText,
204206 maxImageWidth: args.maxImageWidth,
205207 );
206- return _HtmlGenerationResult .success (html);
208+ final base64Html = Uri .dataFromString (
209+ html,
210+ mimeType: 'text/html' ,
211+ encoding: utf8,
212+ base64: true ,
213+ ).toString ();
214+
215+ return _HtmlGenerationResult .success (base64Html);
207216 } catch (e, s) {
208217 print ('ERROR: unable to transform mime message to HTML: $e $s ' );
209218 String errorDetails = e.toString () + '\n\n ' + s.toString ();
@@ -252,70 +261,79 @@ class _HtmlViewerState extends State<_HtmlMimeMessageViewer> {
252261 }
253262
254263 Widget _buildWebView () {
255- if (_htmlData == null ) {
264+ final htmlData = _htmlData;
265+ if (htmlData == null ) {
256266 return Container ();
257267 }
258268 final theme = Theme .of (context);
259269 final isDark =
260270 (theme.brightness == Brightness .dark) || widget.config.enableDarkMode;
261- return InAppWebView (
262- key: ValueKey (_htmlData),
263- initialData: InAppWebViewInitialData (data: _htmlData! ),
264- initialOptions: InAppWebViewGroupOptions (
265- crossPlatform: InAppWebViewOptions (
266- useShouldOverrideUrlLoading: true ,
267- verticalScrollBarEnabled: false ,
268- transparentBackground: isDark,
269- ),
270- android: AndroidInAppWebViewOptions (
271- useWideViewPort: false ,
272- loadWithOverviewMode: true ,
273- useHybridComposition: true ,
274- forceDark: isDark
275- ? AndroidForceDark .FORCE_DARK_ON
276- : AndroidForceDark .FORCE_DARK_OFF ,
277- ),
278- ),
279- onWebViewCreated: widget.config.onWebViewCreated,
280- onLoadStop: (controller, url) async {
271+ return WebView (
272+ key: ValueKey (htmlData),
273+ initialUrl: htmlData,
274+ javascriptMode: JavascriptMode .unrestricted,
275+ // initialData: InAppWebViewInitialData(data: _htmlData!),
276+ // initialOptions: InAppWebViewGroupOptions(
277+ // crossPlatform: InAppWebViewOptions(
278+ // useShouldOverrideUrlLoading: true,
279+ // verticalScrollBarEnabled: false,
280+ // transparentBackground: isDark,
281+ // ),
282+ // android: AndroidInAppWebViewOptions(
283+ // useWideViewPort: false,
284+ // loadWithOverviewMode: true,
285+ // useHybridComposition: true,
286+ // forceDark: isDark
287+ // ? AndroidForceDark.FORCE_DARK_ON
288+ // : AndroidForceDark.FORCE_DARK_OFF,
289+ // ),
290+ // ),
291+ onWebViewCreated: (controller) {
292+ _controller = controller;
293+ widget.config.onWebViewCreated? .call (controller);
294+ },
295+ onPageFinished: (url) async {
281296 if (widget.config.adjustHeight) {
282- var scrollHeight = (await controller.evaluateJavascript (
283- source: 'document.body.scrollHeight' ));
284- // print('scrollHeight: $scrollHeight');
285- if (scrollHeight != null ) {
286- final scrollWidth = (await controller.evaluateJavascript (
287- source: 'document.body.scrollWidth' ));
288- // print('scrollWidth: $scrollWidth');
289- final size = MediaQuery .of (context).size;
290- // print('size: ${size.height}x${size.width}');
291- if (_isHtmlMessage && scrollWidth > size.width) {
292- var scale = (size.width / scrollWidth);
293- if (scale < 0.2 ) {
294- scale = 0.2 ;
295- }
296- await controller.zoomBy (zoomFactor: scale, iosAnimated: true );
297- scrollHeight = (scrollHeight * scale).ceil ();
298- final callback = widget.config.onZoomed;
299- if (callback != null ) {
300- callback (controller, scale);
301- }
302- }
297+ final scrollHeightText = await _controller
298+ .runJavascriptReturningResult ('document.body.scrollHeight' );
299+ final scrollHeight = double .tryParse (scrollHeightText);
300+ // print('scrollHeight: $scrollHeightText');
301+ // final scrollWidthText = await _controller
302+ // .runJavascriptReturningResult('document.body.scrollWidth');
303+ // print('scrollWidth: $scrollWidthText');
304+ // final scrollWidth = double.tryParse(scrollWidthText);
305+ if (scrollHeight != null && mounted) {
306+ // final size = MediaQuery.of(context).size;
307+ // // print('size: ${size.height}x${size.width}');
308+ // if (_isHtmlMessage && scrollWidth > size.width) {
309+ // var scale = (size.width / scrollWidth);
310+ // if (scale < 0.2) {
311+ // scale = 0.2;
312+ // }
313+ // await controller.zoomBy(zoomFactor: scale, iosAnimated: true);
314+ // scrollHeight = (scrollHeight * scale).ceil();
315+ // final callback = widget.config.onZoomed;
316+ // if (callback != null) {
317+ // callback(controller, scale);
318+ // }
319+ // }
303320 setState (() {
304321 _webViewHeight = (scrollHeight + 10.0 );
305322 // print('webViewHeight set to $_webViewHeight');
306323 });
307324 }
308325 }
309326 },
310- shouldOverrideUrlLoading: _shouldOverrideUrlLoading,
311- androidOnPermissionRequest: (controller, origin, resources) {
312- // print('androidOnPermissionRequest for $resources');
313- return Future .value (
314- PermissionRequestResponse (
315- resources: resources,
316- action: PermissionRequestResponseAction .GRANT ),
317- );
318- },
327+ navigationDelegate: _onNavigation,
328+ // shouldOverrideUrlLoading: _shouldOverrideUrlLoading,
329+ // androidOnPermissionRequest: (controller, origin, resources) {
330+ // // print('androidOnPermissionRequest for $resources');
331+ // return Future.value(
332+ // PermissionRequestResponse(
333+ // resources: resources,
334+ // action: PermissionRequestResponseAction.GRANT),
335+ // );
336+ // },
319337 gestureRecognizers: widget.config.adjustHeight
320338 ? {
321339 Factory <LongPressGestureRecognizer >(
@@ -327,14 +345,62 @@ class _HtmlViewerState extends State<_HtmlMimeMessageViewer> {
327345 );
328346 }
329347
330- Future <NavigationActionPolicy > _shouldOverrideUrlLoading (
331- InAppWebViewController controller, NavigationAction request) async {
332- final requestUri = request.request.url! ;
348+ // Future<NavigationActionPolicy> _shouldOverrideUrlLoading(
349+ // InAppWebViewController controller, NavigationAction request) async {
350+ // final requestUri = request.request.url!;
351+ // final mimeMessage = widget.config.mimeMessage;
352+ // final mailtoHandler = widget.config.mailtoDelegate;
353+ // if (mailtoHandler != null && requestUri.isScheme('mailto')) {
354+ // await mailtoHandler(requestUri, mimeMessage);
355+ // return NavigationActionPolicy.CANCEL;
356+ // }
357+ // if (requestUri.isScheme('cid') || requestUri.isScheme('fetch')) {
358+ // // show inline part:
359+ // var cid = Uri.decodeComponent(requestUri.host);
360+ // final part = requestUri.isScheme('cid')
361+ // ? mimeMessage.getPartWithContentId(cid)
362+ // : mimeMessage.getPart(cid);
363+ // if (part != null) {
364+ // final mediaProvider =
365+ // MimeMediaProviderFactory.fromMime(mimeMessage, part);
366+ // final mediaWidget = InteractiveMediaWidget(
367+ // mediaProvider: mediaProvider,
368+ // );
369+ // final showMediaCallback = widget.config.showMediaDelegate;
370+ // if (showMediaCallback != null) {
371+ // showMediaCallback(mediaWidget);
372+ // } else {
373+ // setState(() {
374+ // _mediaView = mediaWidget;
375+ // });
376+ // }
377+ // }
378+ // return NavigationActionPolicy.CANCEL;
379+ // }
380+ // final url = requestUri.toString();
381+ // final urlDelegate = widget.config.urlLauncherDelegate;
382+ // if (urlDelegate != null) {
383+ // final handled = await urlDelegate(url);
384+ // if (handled) {
385+ // return NavigationActionPolicy.CANCEL;
386+ // }
387+ // }
388+ // if (await launcher.canLaunch(url)) {
389+ // await launcher.launch(url);
390+ // return NavigationActionPolicy.CANCEL;
391+ // } else {
392+ // return NavigationActionPolicy.ALLOW;
393+ // }
394+ // }
395+
396+ FutureOr <NavigationDecision > _onNavigation (
397+ NavigationRequest navigation) async {
398+ final requestUri = Uri .parse (navigation.url);
333399 final mimeMessage = widget.config.mimeMessage;
334400 final mailtoHandler = widget.config.mailtoDelegate;
335401 if (mailtoHandler != null && requestUri.isScheme ('mailto' )) {
336402 await mailtoHandler (requestUri, mimeMessage);
337- return NavigationActionPolicy . CANCEL ;
403+ return NavigationDecision .prevent ;
338404 }
339405 if (requestUri.isScheme ('cid' ) || requestUri.isScheme ('fetch' )) {
340406 // show inline part:
@@ -357,22 +423,24 @@ class _HtmlViewerState extends State<_HtmlMimeMessageViewer> {
357423 });
358424 }
359425 }
360- return NavigationActionPolicy . CANCEL ;
426+ return NavigationDecision .prevent ;
361427 }
362- final url = requestUri. toString () ;
428+ final url = navigation.url ;
363429 final urlDelegate = widget.config.urlLauncherDelegate;
364430 if (urlDelegate != null ) {
365431 final handled = await urlDelegate (url);
366432 if (handled) {
367- return NavigationActionPolicy . CANCEL ;
433+ return NavigationDecision .prevent ;
368434 }
369435 }
370- if (await launcher.canLaunch (url)) {
371- await launcher.launch (url);
372- return NavigationActionPolicy .CANCEL ;
373- } else {
374- return NavigationActionPolicy .ALLOW ;
375- }
436+ //if (await launcher.canLaunch(url)) {
437+ // not checking due to
438+ // https://github.com/flutter/flutter/issues/93765#issuecomment-1018994962
439+ await launcher.launch (url);
440+ return NavigationDecision .prevent;
441+ // } else {
442+ // return NavigationDecision.navigate;
443+ // }
376444 }
377445}
378446
0 commit comments