|
| 1 | +import 'package:flutter/material.dart'; |
| 2 | +import 'package:flutter_inappwebview/flutter_inappwebview.dart'; |
| 3 | + |
| 4 | +/// {@template in_app_browser} |
| 5 | +/// A modal widget that displays a web page within the app using a custom |
| 6 | +/// InAppWebView implementation. |
| 7 | +/// |
| 8 | +/// This browser is presented modally and includes a custom app bar with a |
| 9 | +/// close button, providing a consistent and controlled browsing experience. |
| 10 | +/// {@endtemplate} |
| 11 | +class InAppBrowser extends StatefulWidget { |
| 12 | + /// {@macro in_app_browser} |
| 13 | + const InAppBrowser({required this.url, super.key}); |
| 14 | + |
| 15 | + /// The initial URL to load in the web view. |
| 16 | + final String url; |
| 17 | + |
| 18 | + /// A static method to show the browser as a modal dialog. |
| 19 | + static Future<void> show(BuildContext context, {required String url}) { |
| 20 | + return showGeneralDialog( |
| 21 | + context: context, |
| 22 | + barrierDismissible: false, |
| 23 | + pageBuilder: (context, animation, secondaryAnimation) => |
| 24 | + InAppBrowser(url: url), |
| 25 | + ); |
| 26 | + } |
| 27 | + |
| 28 | + @override |
| 29 | + State<InAppBrowser> createState() => _InAppBrowserState(); |
| 30 | +} |
| 31 | + |
| 32 | +class _InAppBrowserState extends State<InAppBrowser> { |
| 33 | + double _progress = 0; |
| 34 | + |
| 35 | + @override |
| 36 | + Widget build(BuildContext context) { |
| 37 | + final theme = Theme.of(context); |
| 38 | + |
| 39 | + return Scaffold( |
| 40 | + appBar: AppBar( |
| 41 | + leading: IconButton( |
| 42 | + icon: const Icon(Icons.close), |
| 43 | + onPressed: () => Navigator.of(context).pop(), |
| 44 | + ), |
| 45 | + backgroundColor: theme.colorScheme.surface, |
| 46 | + elevation: 0, |
| 47 | + bottom: _progress < 1.0 |
| 48 | + ? PreferredSize( |
| 49 | + preferredSize: const Size.fromHeight(2), |
| 50 | + child: LinearProgressIndicator( |
| 51 | + value: _progress, |
| 52 | + backgroundColor: Colors.transparent, |
| 53 | + ), |
| 54 | + ) |
| 55 | + : null, |
| 56 | + ), |
| 57 | + body: InAppWebView( |
| 58 | + initialUrlRequest: URLRequest(url: WebUri(widget.url)), |
| 59 | + initialSettings: InAppWebViewSettings( |
| 60 | + // Restrict navigation to the initial domain to keep the user focused. |
| 61 | + useShouldOverrideUrlLoading: true, |
| 62 | + ), |
| 63 | + onProgressChanged: (controller, progress) { |
| 64 | + setState(() { |
| 65 | + _progress = progress / 100; |
| 66 | + }); |
| 67 | + }, |
| 68 | + shouldOverrideUrlLoading: (controller, navigationAction) async { |
| 69 | + // Allow the initial URL to load, but cancel any subsequent navigations. |
| 70 | + return navigationAction.isForMainFrame |
| 71 | + ? NavigationActionPolicy.CANCEL |
| 72 | + : NavigationActionPolicy.ALLOW; |
| 73 | + }, |
| 74 | + ), |
| 75 | + ); |
| 76 | + } |
| 77 | +} |
0 commit comments