didvan-app/lib/views/webview/web_view.dart

152 lines
5.2 KiB
Dart

// ignore_for_file: library_private_types_in_public_api, deprecated_member_use, avoid_print
import 'package:didvan/constants/assets.dart';
import 'package:didvan/services/auth/token_storage.dart';
import 'package:didvan/views/widgets/didvan/text.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';
class WebView extends StatefulWidget {
final String src;
const WebView({Key? key, required this.src}) : super(key: key);
@override
_WebViewState createState() => _WebViewState();
}
class _WebViewState extends State<WebView> {
late WebViewController controller;
bool loading = true;
int progress = 0;
final Set<Factory<VerticalDragGestureRecognizer>> gestureRecognizers = {
Factory<VerticalDragGestureRecognizer>(
() => VerticalDragGestureRecognizer())
};
void _onProgress(int progress) {
print('🌐 WebView loading progress: $progress%'); // Add logging
setState(() {
this.progress = progress;
});
}
void _onPageFinished(String url) async {
print('✅ WebView finished loading: $url'); // Add logging
await Future.delayed(const Duration(seconds: 2));
setState(() {
if (progress == 100) loading = false;
});
}
/// قبل از باز کردنِ URL، توکنِ Keycloak را به‌صورتِ کوکی روی دامنه
/// `.didvan.com` ست می‌کنیم تا سایت‌های پنل (مثل `app.didvan.com`) کاربر
/// را همان لحظه لاگین‌شده ببینند و لاگین مجدد نخواهد.
Future<void> _injectAuthCookies() async {
final access = TokenStorage.accessToken;
final refresh = TokenStorage.refreshToken;
if (access == null || access.isEmpty) return;
final cookieManager = WebViewCookieManager();
Future<void> setCookie(String name, String value, String domain) async {
try {
await cookieManager.setCookie(WebViewCookie(
name: name,
value: value,
domain: domain,
path: '/',
));
} catch (e) {
print('⚠️ failed to set cookie $name on $domain: $e');
}
}
// برای پوششِ همه‌ی ساب‌دامین‌ها، روی هم `.didvan.com` و دامنه‌ی
// مقصد را ست می‌کنیم.
final host = Uri.tryParse(widget.src)?.host ?? '';
await setCookie('access_token', access, '.didvan.com');
if (host.isNotEmpty) {
await setCookie('access_token', access, host);
}
if (refresh != null && refresh.isNotEmpty) {
await setCookie('refresh_token', refresh, '.didvan.com');
if (host.isNotEmpty) {
await setCookie('refresh_token', refresh, host);
}
}
}
@override
void initState() {
print('🔄 Initializing WebView with URL: ${widget.src}'); // Add logging
controller = WebViewController()
..setJavaScriptMode(JavaScriptMode.unrestricted)
..setNavigationDelegate(
NavigationDelegate(
onProgress: _onProgress,
onPageStarted: (String url) {
print('▶️ WebView started loading: $url'); // Add logging
},
onPageFinished: _onPageFinished,
onHttpError: (HttpResponseError error) {
// print('❌ WebView HTTP error: ${error.statusCode} on ${error.url}'); // Add logging
},
onWebResourceError: (WebResourceError error) {
// print('❌ WebView resource error: ${error.description} on ${error.failingUrl}'); // Add logging
},
onNavigationRequest: (NavigationRequest request) {
print('🔀 WebView navigation request to: ${request.url}'); // Add logging
return NavigationDecision.navigate;
},
),
);
// ابتدا کوکی‌های احراز هویت را تزریق می‌کنیم، سپس URL را لود می‌کنیم.
_injectAuthCookies().whenComplete(() {
controller.loadRequest(Uri.parse(widget.src));
});
super.initState();
}
@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () async {
if (await controller.canGoBack()) {
await controller.goBack();
return false;
} else {
return true;
}
},
child: Scaffold(
resizeToAvoidBottomInset: true,
appBar: AppBar(
title: const DidvanText(
'بازگشت',
),
leading: const BackButton(),
),
body: loading
? Center(
child: Image.asset(
Assets.loadingAnimation,
width: 60,
height: 60,
),
)
: LayoutBuilder(builder: (context, constraints) {
return SizedBox(
width: MediaQuery.sizeOf(context).width,
height: MediaQuery.sizeOf(context).height,
child: WebViewWidget(
controller: controller,
gestureRecognizers: gestureRecognizers,
),
);
}),
));
}
}