fix: Switch to pdfrx pdf rendering library

This commit is contained in:
Anton Stubenbord
2024-01-07 17:46:33 +01:00
parent 27c4f7c937
commit 30f1e64cd4
13 changed files with 330 additions and 289 deletions

View File

@@ -5,4 +5,4 @@ targets:
generate_for: generate_for:
- lib/**.dart - lib/**.dart
- test/**.dart - test/**.dart
- integration_test/**.dart - integration_test/src/mocks/**.dart

1
devtools_options.yaml Normal file
View File

@@ -0,0 +1 @@
extensions:

View File

@@ -126,13 +126,12 @@ class FormBuilderColorPickerField extends FormBuilderField<Color> {
onSaved: onSaved, onSaved: onSaved,
enabled: enabled, enabled: enabled,
onReset: onReset, onReset: onReset,
decoration: decoration,
focusNode: focusNode, focusNode: focusNode,
builder: (FormFieldState<Color?> field) { builder: (FormFieldState<Color?> field) {
final state = field as FormBuilderColorPickerFieldState; final state = field as FormBuilderColorPickerFieldState;
return TextField( return TextField(
style: style, style: style,
decoration: state.decoration.copyWith( decoration: decoration.copyWith(
suffixIcon: colorPreviewBuilder != null suffixIcon: colorPreviewBuilder != null
? colorPreviewBuilder(field.value) ? colorPreviewBuilder(field.value)
: LayoutBuilder( : LayoutBuilder(

View File

@@ -23,10 +23,11 @@ import 'package:paperless_mobile/helpers/message_helpers.dart';
import 'package:paperless_mobile/routing/routes/labels_route.dart'; import 'package:paperless_mobile/routing/routes/labels_route.dart';
import 'package:paperless_mobile/routing/routes/shells/authenticated_route.dart'; import 'package:paperless_mobile/routing/routes/shells/authenticated_route.dart';
typedef ItemBuilder<T> = Widget Function(BuildContext context, T itemData);
class DocumentEditPage extends StatefulWidget { class DocumentEditPage extends StatefulWidget {
const DocumentEditPage({ const DocumentEditPage({
Key? key, super.key
}) : super(key: key); });
@override @override
State<DocumentEditPage> createState() => _DocumentEditPageState(); State<DocumentEditPage> createState() => _DocumentEditPageState();

View File

@@ -1,8 +1,10 @@
import 'dart:math';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_animate/flutter_animate.dart'; import 'package:flutter_animate/flutter_animate.dart';
import 'package:paperless_mobile/core/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/core/extensions/flutter_extensions.dart';
import 'package:pdfx/pdfx.dart'; import 'package:pdfrx/pdfrx.dart';
class DocumentView extends StatefulWidget { class DocumentView extends StatefulWidget {
final Future<Uint8List> documentBytes; final Future<Uint8List> documentBytes;
@@ -10,27 +12,37 @@ class DocumentView extends StatefulWidget {
final bool showAppBar; final bool showAppBar;
final bool showControls; final bool showControls;
const DocumentView({ const DocumentView({
Key? key, super.key,
required this.documentBytes, required this.documentBytes,
this.showAppBar = true, this.showAppBar = true,
this.showControls = true, this.showControls = true,
this.title, this.title,
}) : super(key: key); });
@override @override
State<DocumentView> createState() => _DocumentViewState(); State<DocumentView> createState() => _DocumentViewState();
} }
class _DocumentViewState extends State<DocumentView> { class _DocumentViewState extends State<DocumentView> {
late final PdfController _controller; final PdfViewerController _controller = PdfViewerController();
int _currentPage = 1; int _currentPage = 1;
int? _totalPages; int? _totalPages;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
final document = _controller.addListener(() {
widget.documentBytes.then((value) => PdfDocument.openData(value)); if (mounted) {
_controller = PdfController(document: document); if (_controller.pageNumber != null) {
setState(() {
_currentPage = _controller.pageNumber!;
});
}
setState(() {
_totalPages = _controller.pages.length;
});
}
});
} }
@override @override
@@ -45,8 +57,7 @@ class _DocumentViewState extends State<DocumentView> {
? 0.milliseconds ? 0.milliseconds
: 100.milliseconds; : 100.milliseconds;
final canGoToNextPage = _totalPages != null && _currentPage < _totalPages!; final canGoToNextPage = _totalPages != null && _currentPage < _totalPages!;
final canGoToPreviousPage = final canGoToPreviousPage = _totalPages != null && _currentPage > 1;
_controller.pagesCount != null && _currentPage > 1;
return Scaffold( return Scaffold(
appBar: widget.showAppBar appBar: widget.showAppBar
? AppBar( ? AppBar(
@@ -63,9 +74,8 @@ class _DocumentViewState extends State<DocumentView> {
IconButton.filled( IconButton.filled(
onPressed: canGoToPreviousPage onPressed: canGoToPreviousPage
? () async { ? () async {
await _controller.previousPage( await _controller.goToPage(
duration: pageTransitionDuration, pageNumber: _currentPage - 1,
curve: Curves.easeOut,
); );
} }
: null, : null,
@@ -75,9 +85,8 @@ class _DocumentViewState extends State<DocumentView> {
IconButton.filled( IconButton.filled(
onPressed: canGoToNextPage onPressed: canGoToNextPage
? () async { ? () async {
await _controller.nextPage( await _controller.goToPage(
duration: pageTransitionDuration, pageNumber: _currentPage + 1,
curve: Curves.easeOut,
); );
} }
: null, : null,
@@ -86,14 +95,13 @@ class _DocumentViewState extends State<DocumentView> {
], ],
), ),
), ),
PdfPageNumber( Builder(
controller: _controller, builder: (context) {
builder: (context, loadingState, page, pagesCount) { if (_totalPages == null) {
if (loadingState != PdfLoadingState.success) {
return const Text("-/-"); return const Text("-/-");
} }
return Text( return Text(
"$page/$pagesCount", "$_currentPage/$_totalPages",
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
).padded(); ).padded();
}, },
@@ -102,21 +110,61 @@ class _DocumentViewState extends State<DocumentView> {
), ),
) )
: null, : null,
body: PdfView( body: FutureBuilder<Uint8List>(
controller: _controller, future: widget.documentBytes,
onDocumentLoaded: (document) { builder: (context, snapshot) {
if (mounted) { if (!snapshot.hasData) {
setState(() { return Center(
_totalPages = document.pagesCount; child: CircularProgressIndicator(),
}); );
}
},
onPageChanged: (page) {
if (mounted) {
setState(() {
_currentPage = page;
});
} }
return PdfViewer.data(
snapshot.data!,
controller: _controller,
anchor: PdfPageAnchor.all,
displayParams: PdfViewerParams(
backgroundColor: Theme.of(context).colorScheme.background,
margin: 0,
layoutPages: (pages, params) {
final height =
pages.fold(0.0, (prev, page) => max(prev, page.height)) +
params.margin * 2;
final pageLayouts = <Rect>[];
double x = params.margin;
for (var page in pages) {
pageLayouts.add(
Rect.fromLTWH(
x,
(height - page.height) / 2, // center vertically
page.width,
page.height,
),
);
x += page.width + params.margin;
}
return PdfPageLayout(
pageLayouts: pageLayouts,
documentSize: Size(x, height),
);
},
),
// controller: _controller,
// onDocumentLoaded: (document) {
// if (mounted) {
// setState(() {
// _totalPages = document.pagesCount;
// });
// }
// },
// onPageChanged: (page) {
// if (mounted) {
// setState(() {
// _currentPage = page;
// });
// }
// },
);
}, },
), ),
); );

View File

@@ -44,13 +44,15 @@ class DocumentListItem extends DocumentItem {
children: [ children: [
Row( Row(
children: [ children: [
AbsorbPointer( Flexible(
absorbing: isSelectionActive, child: AbsorbPointer(
child: CorrespondentWidget( absorbing: isSelectionActive,
isClickable: isLabelClickable, child: CorrespondentWidget(
correspondent: isClickable: isLabelClickable,
labelRepository.correspondents[document.correspondent], correspondent:
onSelected: onCorrespondentSelected, labelRepository.correspondents[document.correspondent],
onSelected: onCorrespondentSelected,
),
), ),
), ),
], ],

View File

@@ -9,13 +9,13 @@ class CorrespondentWidget extends StatelessWidget {
final TextStyle? textStyle; final TextStyle? textStyle;
const CorrespondentWidget({ const CorrespondentWidget({
Key? key, super.key,
required this.correspondent, required this.correspondent,
this.textColor, this.textColor,
this.isClickable = true, this.isClickable = true,
this.textStyle, this.textStyle,
this.onSelected, this.onSelected,
}) : super(key: key); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@@ -44,7 +44,7 @@ class LocalNotificationService {
await _plugin await _plugin
.resolvePlatformSpecificImplementation< .resolvePlatformSpecificImplementation<
AndroidFlutterLocalNotificationsPlugin>() AndroidFlutterLocalNotificationsPlugin>()
?.requestPermission(); ?.requestNotificationsPermission();
} }
Future<void> notifyFileDownload({ Future<void> notifyFileDownload({
@@ -56,7 +56,7 @@ class LocalNotificationService {
"File download complete.", "File download complete.",
NotificationDetails( NotificationDetails(
android: AndroidNotificationDetails( android: AndroidNotificationDetails(
NotificationChannel.fileDownload.id + "_${filePath.hashCode}", "${NotificationChannel.fileDownload.id}_${filePath.hashCode}",
NotificationChannel.fileDownload.name, NotificationChannel.fileDownload.name,
importance: Importance.max, importance: Importance.max,
priority: Priority.high, priority: Priority.high,
@@ -92,7 +92,7 @@ class LocalNotificationService {
: tr.notificationDownloadingDocument, : tr.notificationDownloadingDocument,
NotificationDetails( NotificationDetails(
android: AndroidNotificationDetails( android: AndroidNotificationDetails(
NotificationChannel.documentDownload.id + "_${document.id}", "${NotificationChannel.documentDownload.id}_${document.id}",
NotificationChannel.documentDownload.name, NotificationChannel.documentDownload.name,
progress: ((progress ?? 0) * 100).toInt(), progress: ((progress ?? 0) * 100).toInt(),
maxProgress: 100, maxProgress: 100,
@@ -146,7 +146,7 @@ class LocalNotificationService {
: tr.notificationDownloadingDocument, : tr.notificationDownloadingDocument,
NotificationDetails( NotificationDetails(
android: AndroidNotificationDetails( android: AndroidNotificationDetails(
NotificationChannel.documentDownload.id + "_$filename", "${NotificationChannel.documentDownload.id}_$filename",
NotificationChannel.documentDownload.name, NotificationChannel.documentDownload.name,
ongoing: !finished, ongoing: !finished,
indeterminate: true, indeterminate: true,

View File

@@ -1,7 +1,6 @@
name: mock_server name: mock_server
description: A new Flutter package project. description: A new Flutter package project.
version: 0.0.1 version: 0.0.1
homepage:
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'
@@ -13,12 +12,12 @@ dependencies:
logging: ^1.1.1 logging: ^1.1.1
flutter: flutter:
sdk: flutter sdk: flutter
http: ^0.13.5 http: ^1.1.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:
sdk: flutter sdk: flutter
flutter_lints: ^2.0.0 flutter_lints: ^2.0.3
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec # following page: https://dart.dev/tools/pub/pubspec

View File

@@ -69,13 +69,13 @@ class RelativeDateRangeQuery extends DateRangeQuery {
DateTime get dateTime { DateTime get dateTime {
switch (unit) { switch (unit) {
case DateRangeUnit.day: case DateRangeUnit.day:
return Jiffy().subtract(days: offset).dateTime; return Jiffy.now().subtract(days: offset).dateTime;
case DateRangeUnit.week: case DateRangeUnit.week:
return Jiffy().subtract(weeks: offset).dateTime; return Jiffy.now().subtract(weeks: offset).dateTime;
case DateRangeUnit.month: case DateRangeUnit.month:
return Jiffy().subtract(months: offset).dateTime; return Jiffy.now().subtract(months: offset).dateTime;
case DateRangeUnit.year: case DateRangeUnit.year:
return Jiffy().subtract(years: offset).dateTime; return Jiffy.now().subtract(years: offset).dateTime;
} }
} }

View File

@@ -16,10 +16,10 @@ dependencies:
equatable: ^2.0.5 equatable: ^2.0.5
http: ^1.0.0 http: ^1.0.0
json_annotation: ^4.8.1 json_annotation: ^4.8.1
intl: ^0.18.1 intl: ^0.19.0
dio: ^5.0.0 dio: ^5.0.0
collection: ^1.17.0 collection: ^1.17.0
jiffy: ^5.0.0 jiffy: ^6.2.2
freezed_annotation: ^2.4.1 freezed_annotation: ^2.4.1
hive: ^2.2.3 hive: ^2.2.3
mockito: ^5.4.4 mockito: ^5.4.4

View File

File diff suppressed because it is too large Load Diff

View File

@@ -40,33 +40,33 @@ dependencies:
path_provider: ^2.0.10 path_provider: ^2.0.10
image: ^4.0.17 image: ^4.0.17
photo_view: ^0.14.0 photo_view: ^0.14.0
intl: ^0.18.1 intl: ^0.19.0
flutter_svg: ^2.0.7 flutter_svg: ^2.0.7
url_launcher: ^6.1.2 url_launcher: ^6.1.2
file_picker: ^5.2.4 file_picker: ^6.1.1
web_socket_channel: ^2.2.0 web_socket_channel: ^2.2.0
http: ^1.0.0 http: ^1.1.2
flutter_cache_manager: ^3.3.0 flutter_cache_manager: ^3.3.0
cached_network_image: ^3.2.1 cached_network_image: ^3.2.1
shimmer: ^2.0.0 shimmer: ^3.0.0
flutter_bloc: ^8.1.1 flutter_bloc: ^8.1.1
equatable: ^2.0.5 equatable: ^2.0.5
flutter_form_builder: ^8.0.0 flutter_form_builder: ^9.1.1
package_info_plus: ^4.0.1 package_info_plus: ^5.0.1
local_auth: ^2.1.2 local_auth: ^2.1.2
connectivity_plus: ^4.0.0 connectivity_plus: ^5.0.2
flutter_native_splash: ^2.2.11 flutter_native_splash: ^2.2.11
share_plus: ^4.5.3 share_plus: ^7.2.1
introduction_screen: ^3.0.2 introduction_screen: ^3.0.2
receive_sharing_intent: ^1.4.5 receive_sharing_intent: ^1.4.5
uuid: ^4.1.0 uuid: ^4.1.0
flutter_typeahead: ^4.3.3 flutter_typeahead: ^5.0.1
fluttertoast: ^8.1.1 fluttertoast: ^8.1.1
paperless_api: paperless_api:
path: packages/paperless_api path: packages/paperless_api
hive: ^2.2.3 hive: ^2.2.3
rxdart: ^0.27.7 rxdart: ^0.27.7
badges: ^2.0.3 badges: ^3.1.2
flutter_colorpicker: ^1.0.3 flutter_colorpicker: ^1.0.3
provider: ^6.0.5 provider: ^6.0.5
dio: ^5.0.0 dio: ^5.0.0
@@ -75,21 +75,21 @@ dependencies:
pretty_dio_logger: ^1.2.0-beta-1 pretty_dio_logger: ^1.2.0-beta-1
collection: ^1.17.0 collection: ^1.17.0
device_info_plus: ^9.0.3 device_info_plus: ^9.0.3
flutter_local_notifications: ^13.0.0 flutter_local_notifications: ^16.3.0
responsive_builder: ^0.4.3 responsive_builder: ^0.7.0
open_filex: ^4.3.2 open_filex: ^4.3.2
flutter_displaymode: ^0.5.0 flutter_displaymode: ^0.6.0
dynamic_color: ^1.5.4 dynamic_color: ^1.5.4
flutter_html: ^3.0.0-alpha.6 flutter_html: ^3.0.0-alpha.6
freezed_annotation: ^2.4.1 freezed_annotation: ^2.4.1
animations: ^2.0.7 animations: ^2.0.7
hive_flutter: ^1.1.0 hive_flutter: ^1.1.0
flutter_secure_storage: ^8.0.0 flutter_secure_storage: ^9.0.0
sliver_tools: ^0.2.10 sliver_tools: ^0.2.10
webview_flutter: ^4.2.1 webview_flutter: ^4.2.1
printing: ^5.11.0 printing: ^5.11.0
go_router: ^10.0.0 go_router: ^13.0.1
fl_chart: ^0.63.0 fl_chart: ^0.66.0
palette_generator: ^0.3.3+2 palette_generator: ^0.3.3+2
defer_pointer: ^0.0.2 defer_pointer: ^0.0.2
transparent_image: ^2.0.1 transparent_image: ^2.0.1
@@ -107,11 +107,10 @@ dependencies:
ref: '4be9de9ffed5398fd7d5f44bbb07dcd3d3f1711b' ref: '4be9de9ffed5398fd7d5f44bbb07dcd3d3f1711b'
path: packages/pdfx path: packages/pdfx
markdown: ^7.1.1 markdown: ^7.1.1
pdfrx: ^0.4.3
dependency_overrides: dependency_overrides:
intl: ^0.18.1 intl: ^0.18.1
http: ^1.0.0
dev_dependencies: dev_dependencies:
integration_test: integration_test:
@@ -121,7 +120,7 @@ dev_dependencies:
build_runner: ^2.4.6 build_runner: ^2.4.6
bloc_test: ^9.1.0 bloc_test: ^9.1.0
dependency_validator: ^3.0.0 dependency_validator: ^3.0.0
flutter_lints: ^1.0.0 flutter_lints: ^3.0.1
json_serializable: ^6.5.4 json_serializable: ^6.5.4
freezed: ^2.4.1 freezed: ^2.4.1
hive_generator: ^2.0.1 hive_generator: ^2.0.1