224 lines
7.0 KiB
Dart
224 lines
7.0 KiB
Dart
import 'package:didvan/views/widgets/didvan/text.dart';
|
||
import 'package:flutter/material.dart';
|
||
import 'package:syncfusion_flutter_pdfviewer/pdfviewer.dart';
|
||
import 'package:flutter/foundation.dart';
|
||
import 'package:didvan/services/network/request.dart';
|
||
import 'package:universal_html/html.dart' as html;
|
||
|
||
class PdfViewerPage extends StatefulWidget {
|
||
final String pdfUrl;
|
||
final String title;
|
||
|
||
const PdfViewerPage({
|
||
super.key,
|
||
required this.pdfUrl,
|
||
required this.title,
|
||
});
|
||
|
||
@override
|
||
State<PdfViewerPage> createState() => _PdfViewerPageState();
|
||
}
|
||
|
||
class _PdfViewerPageState extends State<PdfViewerPage> {
|
||
final PdfViewerController _pdfViewerController = PdfViewerController();
|
||
bool _isLoading = true;
|
||
String? _errorMessage;
|
||
late String _fullPdfUrl;
|
||
|
||
@override
|
||
void initState() {
|
||
super.initState();
|
||
// اگر URL کامل (http/https) بود همان را استفاده کن؛ در غیر این صورت
|
||
// به دامنهی legacy میچسبد. URLهای جدید content-service از s3-service
|
||
// بهصورت presigned کامل میآیند.
|
||
_fullPdfUrl = widget.pdfUrl.startsWith('http')
|
||
? widget.pdfUrl
|
||
: 'https://api.didvan.app${widget.pdfUrl}';
|
||
|
||
if (kDebugMode) {
|
||
print('Original PDF URL: ${widget.pdfUrl}');
|
||
print('Full PDF URL : $_fullPdfUrl');
|
||
}
|
||
|
||
// برای وب، PDF را مستقیماً در مرورگر باز میکند
|
||
if (kIsWeb) {
|
||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
_openPdfInBrowser();
|
||
});
|
||
}
|
||
}
|
||
|
||
void _openPdfInBrowser() {
|
||
final token = RequestService.token;
|
||
final pdfUrlWithAuth =
|
||
'$_fullPdfUrl${_fullPdfUrl.contains('?') ? '&' : '?'}token=$token';
|
||
|
||
// روش سازگار با تمام مرورگرها شامل Safari
|
||
try {
|
||
final anchor = html.AnchorElement(href: pdfUrlWithAuth)
|
||
..setAttribute('target', '_blank')
|
||
..setAttribute('rel', 'noopener');
|
||
html.document.body?.append(anchor);
|
||
anchor.click();
|
||
anchor.remove();
|
||
|
||
if (kDebugMode) {
|
||
print('PDF opened successfully in new tab');
|
||
}
|
||
} catch (e) {
|
||
if (kDebugMode) {
|
||
print('Error opening PDF: $e');
|
||
}
|
||
}
|
||
|
||
Future.delayed(const Duration(milliseconds: 500), () {
|
||
if (mounted) {
|
||
Navigator.of(context).pop();
|
||
}
|
||
});
|
||
}
|
||
|
||
@override
|
||
Widget build(BuildContext context) {
|
||
// برای وب، صفحهای نشان میدهد که PDF در تب جدیدی باز میشود
|
||
if (kIsWeb) {
|
||
return Scaffold(
|
||
resizeToAvoidBottomInset: true,
|
||
appBar: AppBar(
|
||
title: DidvanText(
|
||
widget.title,
|
||
style: const TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
centerTitle: true,
|
||
elevation: 0,
|
||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||
),
|
||
body: const Center(
|
||
child: Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
CircularProgressIndicator(),
|
||
SizedBox(height: 16),
|
||
DidvanText(
|
||
'درحال باز کردن PDF در مرورگر...',
|
||
style: TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
);
|
||
}
|
||
|
||
// برای پلتفرمهای دیگر، از SfPdfViewer استفاده کن
|
||
return Scaffold(
|
||
resizeToAvoidBottomInset: true,
|
||
appBar: AppBar(
|
||
title: DidvanText(
|
||
widget.title,
|
||
style: const TextStyle(
|
||
fontSize: 16,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
centerTitle: true,
|
||
elevation: 0,
|
||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||
),
|
||
body: Stack(
|
||
children: [
|
||
SfPdfViewer.network(
|
||
_fullPdfUrl,
|
||
controller: _pdfViewerController,
|
||
enableDoubleTapZooming: true,
|
||
enableTextSelection: true,
|
||
canShowScrollHead: true,
|
||
canShowScrollStatus: true,
|
||
pageLayoutMode: PdfPageLayoutMode.continuous,
|
||
// فقط برای دامنهی خودی توکن میفرستیم؛ presigned S3 با هدر
|
||
// Authorization پاسخ 403 میدهد.
|
||
headers: _fullPdfUrl.contains('didvan.com') ||
|
||
_fullPdfUrl.contains('didvan.app')
|
||
? {'Authorization': 'Bearer ${RequestService.token}'}
|
||
: const <String, String>{},
|
||
onDocumentLoaded: (PdfDocumentLoadedDetails details) {
|
||
setState(() {
|
||
_isLoading = false;
|
||
});
|
||
if (kDebugMode) {
|
||
print(
|
||
'PDF loaded successfully with ${details.document.pages.count} pages');
|
||
}
|
||
},
|
||
onDocumentLoadFailed: (PdfDocumentLoadFailedDetails details) {
|
||
setState(() {
|
||
_isLoading = false;
|
||
_errorMessage = details.error;
|
||
});
|
||
if (kDebugMode) {
|
||
print('PDF load failed: ${details.error}');
|
||
print('Description: ${details.description}');
|
||
}
|
||
},
|
||
),
|
||
if (_isLoading)
|
||
const Center(
|
||
child: CircularProgressIndicator(),
|
||
),
|
||
if (_errorMessage != null)
|
||
Center(
|
||
child: Padding(
|
||
padding: const EdgeInsets.all(20.0),
|
||
child: Column(
|
||
mainAxisAlignment: MainAxisAlignment.center,
|
||
children: [
|
||
const Icon(
|
||
Icons.error_outline,
|
||
size: 64,
|
||
color: Colors.red,
|
||
),
|
||
const SizedBox(height: 16),
|
||
const DidvanText(
|
||
'خطا در بارگذاری PDF',
|
||
style: TextStyle(
|
||
fontSize: 18,
|
||
fontWeight: FontWeight.bold,
|
||
),
|
||
),
|
||
const SizedBox(height: 8),
|
||
DidvanText(
|
||
_errorMessage!,
|
||
textAlign: TextAlign.center,
|
||
style: const TextStyle(fontSize: 14),
|
||
),
|
||
const SizedBox(height: 16),
|
||
ElevatedButton(
|
||
onPressed: () {
|
||
setState(() {
|
||
_isLoading = true;
|
||
_errorMessage = null;
|
||
});
|
||
},
|
||
child: const DidvanText('تلاش مجدد'),
|
||
),
|
||
],
|
||
),
|
||
),
|
||
),
|
||
],
|
||
),
|
||
);
|
||
}
|
||
|
||
@override
|
||
void dispose() {
|
||
_pdfViewerController.dispose();
|
||
super.dispose();
|
||
}
|
||
}
|