feat(client_app): open privacy policy in in-app webview

Add a reusable WebPageScreen (webview_flutter host with close button +
progress bar, no nav interception) and wire the profile 'kebijakan privasi'
menu item to open https://mybestieindonesia.com/privacy in it.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-05 15:10:47 +08:00
parent d04f6a8a69
commit be20eee16b
2 changed files with 105 additions and 1 deletions

View File

@@ -0,0 +1,96 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
import '../theme/halo_tokens.dart';
/// Generic in-app WebView host for static external pages (privacy policy,
/// terms & conditions, etc).
///
/// Unlike [XenditCheckoutScreen] this carries no navigation-interception logic
/// — it just loads [url] and lets the user read it, with a close button and a
/// progress bar. Push it with a plain `Navigator.push(MaterialPageRoute(...))`.
class WebPageScreen extends StatefulWidget {
final String url;
final String title;
const WebPageScreen({
super.key,
required this.url,
required this.title,
});
@override
State<WebPageScreen> createState() => _WebPageScreenState();
}
class _WebPageScreenState extends State<WebPageScreen> {
late final WebViewController _controller;
int _progress = 0;
@override
void initState() {
super.initState();
_controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setBackgroundColor(HaloTokens.surface)
..setNavigationDelegate(
NavigationDelegate(
onProgress: (p) {
if (!mounted) return;
setState(() => _progress = p);
},
onWebResourceError: (error) {
if (kDebugMode) {
debugPrint(
'[WebPageScreen] WebResourceError '
'code=${error.errorCode} type=${error.errorType} '
'desc=${error.description} url=${error.url}',
);
}
},
),
)
..loadRequest(Uri.parse(widget.url));
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: HaloTokens.surface,
appBar: AppBar(
backgroundColor: HaloTokens.surface,
elevation: 0,
leading: IconButton(
icon: const Icon(Icons.close, color: HaloTokens.brandDark),
tooltip: 'Tutup',
onPressed: () => Navigator.of(context).pop(),
),
title: Text(
widget.title,
style: const TextStyle(
fontFamily: HaloTokens.fontDisplay,
fontSize: 16,
fontWeight: FontWeight.w700,
color: HaloTokens.brandDark,
),
),
centerTitle: true,
bottom: _progress < 100
? PreferredSize(
preferredSize: const Size.fromHeight(2),
child: LinearProgressIndicator(
value: _progress / 100.0,
minHeight: 2,
backgroundColor: HaloTokens.brandSofter,
valueColor: const AlwaysStoppedAnimation<Color>(
HaloTokens.brand,
),
),
)
: null,
),
body: WebViewWidget(controller: _controller),
);
}
}

View File

@@ -3,6 +3,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import '../../core/auth/auth_notifier.dart'; import '../../core/auth/auth_notifier.dart';
import '../../core/theme/halo_tokens.dart'; import '../../core/theme/halo_tokens.dart';
import '../../core/widgets/web_page_screen.dart';
import '../home/widgets/halo_tab_bar.dart'; import '../home/widgets/halo_tab_bar.dart';
/// "Kamu" tab — profile screen. /// "Kamu" tab — profile screen.
@@ -78,7 +79,14 @@ class ProfileScreen extends ConsumerWidget {
_MenuItemData( _MenuItemData(
icon: Icons.lock_outline, icon: Icons.lock_outline,
label: 'kebijakan privasi', label: 'kebijakan privasi',
onTap: () {}, onTap: () => Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => const WebPageScreen(
url: 'https://mybestieindonesia.com/privacy',
title: 'kebijakan privasi',
),
),
),
), ),
]), ]),
const SizedBox(height: 16), const SizedBox(height: 16),