Skip to content

Commit 2975ffa

Browse files
committed
feat(shared): add InAppBrowser widget for modal web page display
- Implement InAppBrowser as a modal widget using InAppWebView - Include custom app bar with close button and progress indicator - Restrict navigation to initial domain to maintain focus - Add show method for easy presentation as a modal dialog
1 parent 60d662f commit 2975ffa

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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

Comments
 (0)