Skip to content

Commit 1a99265

Browse files
committed
transition to webview_flutter
1 parent 097f8cd commit 1a99265

4 files changed

Lines changed: 154 additions & 81 deletions

File tree

lib/enough_mail_flutter.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ export 'src/mime_message_viewer.dart';
55
export 'src/mime_message_downloader.dart';
66
export 'src/mime_media_provider.dart';
77

8-
export 'package:flutter_inappwebview/flutter_inappwebview.dart';
8+
export 'package:webview_flutter/webview_flutter.dart';
99
export 'package:url_launcher/url_launcher.dart';
1010
export 'package:enough_mail_html/enough_mail_html.dart';
1111
export 'package:enough_media/enough_media.dart';

lib/src/mime_message_downloader.dart

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
import 'dart:io';
22

33
import 'package:enough_mail/enough_mail.dart';
4-
import 'package:enough_mail_flutter/enough_mail_flutter.dart';
54
import 'package:enough_media/enough_media.dart';
65
import 'package:flutter/cupertino.dart';
76
import 'package:flutter/material.dart';
8-
import 'package:flutter/widgets.dart';
7+
import 'package:webview_flutter/webview_flutter.dart';
98

109
import 'mime_message_viewer.dart';
1110

@@ -34,8 +33,8 @@ class MimeMessageDownloader extends StatefulWidget {
3433

3534
/// Handler for any non-media URLs that the user taps on the website, return `true` when the given `url` was handled.
3635
final Future<bool> Function(String url)? urlLauncherDelegate;
37-
final void Function(InAppWebViewController controller)? onWebViewCreated;
38-
final void Function(InAppWebViewController controller, double zoomFactor)?
36+
final void Function(WebViewController controller)? onWebViewCreated;
37+
final void Function(WebViewController controller, double zoomFactor)?
3938
onZoomed;
4039
final void Function(Object? exception, StackTrace? stackTrace)? onError;
4140

lib/src/mime_message_viewer.dart

Lines changed: 137 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'dart:async';
2+
import 'dart:convert';
23
import 'dart:io';
34
import 'dart:typed_data';
45

@@ -8,10 +9,9 @@ import 'package:flutter/cupertino.dart';
89
import 'package:flutter/foundation.dart';
910
import 'package:flutter/gestures.dart';
1011
import 'package:flutter/material.dart';
11-
import 'package:flutter/widgets.dart';
12-
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
1312
import 'package:enough_mail_html/enough_mail_html.dart';
1413
import 'package:url_launcher/url_launcher.dart' as launcher;
14+
import 'package:webview_flutter/webview_flutter.dart';
1515

1616
import '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

pubspec.yaml

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,20 +13,26 @@ dependencies:
1313
enough_mail: #'>=1.3.6 <3.0.0'
1414
git:
1515
url: https://github.com/Enough-Software/enough_mail.git
16-
# path: ../enough_mail
1716
enough_mail_html: #^1.3.0
1817
git:
1918
url: https://github.com/Enough-Software/enough_mail_html.git
20-
# path: ../enough_mail_html
2119
enough_media: #^2.1.0
2220
git:
2321
url: https://github.com/Enough-Software/enough_media.git
2422
# path: ../enough_media
25-
flutter_inappwebview: #^5.3.2
26-
#path: ../flutter_inappwebview
27-
git:
28-
url: https://github.com/robert-virkus/flutter_inappwebview.git
29-
url_launcher: ^6.0.6
23+
url_launcher: ^6.0.18
24+
webview_flutter: ^3.0.0
25+
26+
dependency_overrides:
27+
# out-comment the following to enable local development:
28+
# enough_mail:
29+
# path: ../enough_mail
30+
# enough_mail_html:
31+
# path: ../enough_mail_html
32+
# enough_media:
33+
# path: ../enough_media
34+
35+
3036

3137
dev_dependencies:
3238
flutter_test:

0 commit comments

Comments
 (0)