Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions lib/l10n/app_en.arb
Original file line number Diff line number Diff line change
Expand Up @@ -561,6 +561,18 @@
}
}
},
"zoomOut":"Zoom out",
"@zoomOut":{},
"zoomIn":"Zoom in",
"@zoomIn":{},
"goToFirstPage":"Go to first page",
"@goToFirstPage":{},
"goToLastPage":"Go to last page",
"@goToLastPage":{},
"nextMatch":"Next match",
"@nextMatch":{},
"previousMatch":"Previous match",
"@previousMatch":{},
"sourceCode": "Source code",
"@sourceCode": {},
"reportIssue": "Report an issue",
Expand Down
40 changes: 28 additions & 12 deletions lib/screens/article_website.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart';
import 'package:http/io_client.dart';
import 'package:wispar/generated_l10n/app_localizations.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:wispar/services/unpaywall_api.dart';
Expand All @@ -8,7 +9,7 @@ import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';
import 'dart:io' as io;
import 'package:http/http.dart' as http;
import 'package:wispar/services/logs_helper.dart';
import 'package:wispar/webview_env.dart';
Expand Down Expand Up @@ -58,7 +59,7 @@ class ArticleWebsiteState extends State<ArticleWebsite> {
_initWebViewSettings();
checkUnpaywallAvailability();

pullToRefreshController = Platform.isAndroid || Platform.isIOS
pullToRefreshController = io.Platform.isAndroid || io.Platform.isIOS
? PullToRefreshController(
settings: PullToRefreshSettings(
color: Colors.deepPurple,
Expand Down Expand Up @@ -97,15 +98,15 @@ class ArticleWebsiteState extends State<ArticleWebsite> {
}

String _getPlatformUserAgent() {
if (Platform.isAndroid) {
if (io.Platform.isAndroid) {
return "Mozilla/5.0 (Android 16; Mobile; LG-M255; rv:140.0) Gecko/140.0 Firefox/140.0";
} else if (Platform.isIOS) {
} else if (io.Platform.isIOS) {
return "Mozilla/5.0 (iPhone; CPU iPhone OS 18_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.0 Mobile Safari/604.1";
} else if (Platform.isMacOS) {
} else if (io.Platform.isMacOS) {
return "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko)";
} else if (Platform.isWindows) {
} else if (io.Platform.isWindows) {
return "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:142.0) Gecko/20100101 Firefox/142.0";
} else if (Platform.isLinux) {
} else if (io.Platform.isLinux) {
return "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.3";
} else {
return "Mozilla/5.0 (Linux; Android 13; Pixel 7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0 Mobile Safari/537.36";
Expand Down Expand Up @@ -309,7 +310,7 @@ class ArticleWebsiteState extends State<ArticleWebsite> {
? InAppWebView(
key: webViewKey,
webViewEnvironment:
Platform.isWindows ? webViewEnvironment : null,
io.Platform.isWindows ? webViewEnvironment : null,
initialUrlRequest: URLRequest(url: WebUri(pdfUrl)),
initialSettings: settings,
pullToRefreshController: pullToRefreshController,
Expand Down Expand Up @@ -403,7 +404,7 @@ class ArticleWebsiteState extends State<ArticleWebsite> {
return ServerTrustAuthResponse(
action: ServerTrustAuthResponseAction.PROCEED);
},
onDownloadStartRequest: (controller, urlInfo) async {
onDownloadStarting: (controller, urlInfo) async {
final Uri downloadUri = urlInfo.url;
final String? mimeType = urlInfo.mimeType;
final String? suggestedFilename =
Expand Down Expand Up @@ -946,7 +947,22 @@ class ArticleWebsiteState extends State<ArticleWebsite> {
logger.info(
'Full HTTP Request Headers being sent: $headers');

final client = http.Client();
final io.HttpClient innerHttpClient = io.HttpClient()
..badCertificateCallback =
((io.X509Certificate cert, String host, int port) {
final configuredProxyHost =
Uri.tryParse(proxyUrl)?.host;

if (configuredProxyHost != null &&
host.contains(configuredProxyHost)) {
logger.info(
'Trusting certificate for proxy host: $host');
return true;
}
return false;
});

final client = IOClient(innerHttpClient);

final request = http.Request('GET', finalDownloadUri)
..headers.addAll(headers)
Expand Down Expand Up @@ -982,7 +998,7 @@ class ArticleWebsiteState extends State<ArticleWebsite> {

if (useCustomPath && customPath != null) {
baseDirPath = customPath;
} else if (Platform.isWindows) {
} else if (io.Platform.isWindows) {
final defaultAppDir =
await getApplicationSupportDirectory();
baseDirPath = defaultAppDir.path;
Expand All @@ -1001,7 +1017,7 @@ class ArticleWebsiteState extends State<ArticleWebsite> {
}

final fileName = '$cleanedDoi.pdf';
final pdfFile = File('$baseDirPath/$fileName');
final pdfFile = io.File('$baseDirPath/$fileName');
await pdfFile.writeAsBytes(response.bodyBytes);
if (mounted) {
Navigator.of(this.context).push(MaterialPageRoute(
Expand Down
70 changes: 65 additions & 5 deletions lib/screens/pdf_reader.dart
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
import 'dart:io';
import 'package:flutter/material.dart';
import '../generated_l10n/app_localizations.dart';
import 'package:wispar/generated_l10n/app_localizations.dart';
import 'package:pdfrx/pdfrx.dart';
import '../widgets/publication_card/publication_card.dart';
import '../services/database_helper.dart';
import 'package:wispar/widgets/pdf_control_overlay.dart';
import 'package:wispar/widgets/publication_card/publication_card.dart';
import 'package:wispar/services/database_helper.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path_provider/path_provider.dart';
import 'package:path/path.dart' as p;
import 'package:shared_preferences/shared_preferences.dart';
import '../services/logs_helper.dart';
import '../screens/chat_screen.dart';
import 'package:wispar/services/logs_helper.dart';
import 'package:wispar/screens/chat_screen.dart';
import 'dart:math';

class PdfReader extends StatefulWidget {
Expand Down Expand Up @@ -38,9 +39,14 @@ class PdfReaderState extends State<PdfReader> {
bool _darkPdfTheme = false;
int _pdfOrientation = 0;
bool _isZoomed = false;
bool _overlayVisible = true;

PdfTextSearcher? textSearcher;

@override
void dispose() {
textSearcher?.removeListener(_update);
textSearcher?.dispose();
super.dispose();
}

Expand All @@ -53,6 +59,10 @@ class PdfReaderState extends State<PdfReader> {
});
}

void _update() {
if (mounted) setState(() {});
}

Future<void> _loadPreferences() async {
final prefs = await SharedPreferences.getInstance();
final pdfThemeOption = prefs.getInt('pdfThemeOption') ?? 0;
Expand Down Expand Up @@ -189,6 +199,16 @@ class PdfReaderState extends State<PdfReader> {
child: PdfViewer.file(resolvedPdfPath,
controller: controller,
params: PdfViewerParams(
onViewerReady: (document, controller) {
setState(() {
textSearcher = PdfTextSearcher(controller)
..addListener(_update);
});
},
pagePaintCallbacks: [
if (textSearcher != null)
textSearcher!.pageTextMatchPaintCallback,
],
layoutPages: _pdfOrientation == 1
? (pages, params) {
final height = pages.fold(
Expand Down Expand Up @@ -254,12 +274,52 @@ class PdfReaderState extends State<PdfReader> {
},
onTapUp: (details) {
handleLinkTap(details.localPosition);

setState(() {
_overlayVisible = !_overlayVisible;
});
},
child: IgnorePointer(
child: SizedBox(
width: size.width, height: size.height),
),
),
PdfViewerScrollThumb(
controller: controller,
orientation: _pdfOrientation == 1
? ScrollbarOrientation.bottom
: ScrollbarOrientation.right,
thumbSize: _pdfOrientation == 1
? const Size(60, 26)
: const Size(40, 26),
thumbBuilder:
(context, thumbSize, pageNumber, controller) {
return AnimatedOpacity(
duration: const Duration(milliseconds: 200),
curve: Curves.easeOut,
opacity: _overlayVisible ? 1 : 0,
child: Container(
decoration: BoxDecoration(
color:
Colors.black.withValues(alpha: 0.75),
borderRadius: BorderRadius.circular(12),
),
alignment: Alignment.center,
child: Text(
pageNumber.toString(),
style: const TextStyle(
color: Colors.white,
),
),
),
);
},
),
PdfControlOverlay(
controller: controller,
textSearcher: textSearcher,
overlayVisible: _overlayVisible,
),
],
)))
])
Expand Down
Loading
Loading