fix: Fixed saved views bug, formatted files, minor changes

This commit is contained in:
Anton Stubenbord
2023-06-10 16:29:12 +02:00
parent 3161343c35
commit 4c3f97136e
93 changed files with 1049 additions and 585 deletions

View File

@@ -91,8 +91,8 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
_notifier.notifyUpdated(updatedDocument);
} else {
final int autoAsn = await _api.findNextAsn();
final updatedDocument =
await _api.update(document.copyWith(archiveSerialNumber: () => autoAsn));
final updatedDocument = await _api
.update(document.copyWith(archiveSerialNumber: () => autoAsn));
_notifier.notifyUpdated(updatedDocument);
}
}
@@ -104,7 +104,8 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
if (state.metaData == null) {
await loadMetaData();
}
final desc = FileDescription.fromPath(state.metaData!.mediaFilename.replaceAll("/", " "));
final desc = FileDescription.fromPath(
state.metaData!.mediaFilename.replaceAll("/", " "));
final fileName = "${desc.filename}.pdf";
final file = File("${cacheDir.path}/$fileName");
@@ -138,7 +139,8 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
await FileService.downloadsDirectory,
);
final desc = FileDescription.fromPath(
state.metaData!.mediaFilename.replaceAll("/", " "), // Flatten directory structure
state.metaData!.mediaFilename
.replaceAll("/", " "), // Flatten directory structure
);
if (!File(filePath).existsSync()) {
File(filePath).createSync();
@@ -205,7 +207,8 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
if (state.metaData == null) {
await loadMetaData();
}
final filePath = _buildDownloadFilePath(false, await FileService.temporaryDirectory);
final filePath =
_buildDownloadFilePath(false, await FileService.temporaryDirectory);
await _api.downloadToFile(
state.document,
filePath,
@@ -223,7 +226,8 @@ class DocumentDetailsCubit extends Cubit<DocumentDetailsState> {
String _buildDownloadFilePath(bool original, Directory dir) {
final description = FileDescription.fromPath(
state.metaData!.mediaFilename.replaceAll("/", " "), // Flatten directory structure
state.metaData!.mediaFilename
.replaceAll("/", " "), // Flatten directory structure
);
final extension = original ? description.extension : 'pdf';
return "${dir.path}/${description.filename}.$extension";

View File

@@ -45,7 +45,8 @@ class _SelectFileTypeDialogState extends State<SelectFileTypeDialog> {
CheckboxListTile(
controlAffinity: ListTileControlAffinity.leading,
value: _rememberSelection,
onChanged: (value) => setState(() => _rememberSelection = value ?? false),
onChanged: (value) =>
setState(() => _rememberSelection = value ?? false),
title: Text(
S.of(context)!.rememberDecision,
style: Theme.of(context).textTheme.labelMedium,
@@ -61,7 +62,8 @@ class _SelectFileTypeDialogState extends State<SelectFileTypeDialog> {
if (_rememberSelection) {
widget.onRememberSelection(_downloadType);
}
Navigator.of(context).pop(_downloadType == FileDownloadType.original);
Navigator.of(context)
.pop(_downloadType == FileDownloadType.original);
},
),
],

View File

@@ -51,27 +51,35 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
final tabLength = 4 + (apiVersion.hasMultiUserSupport ? 1 : 0);
return WillPopScope(
onWillPop: () async {
Navigator.of(context).pop(context.read<DocumentDetailsCubit>().state.document);
Navigator.of(context)
.pop(context.read<DocumentDetailsCubit>().state.document);
return false;
},
child: DefaultTabController(
length: tabLength,
child: BlocListener<ConnectivityCubit, ConnectivityState>(
listenWhen: (previous, current) => !previous.isConnected && current.isConnected,
listenWhen: (previous, current) =>
!previous.isConnected && current.isConnected,
listener: (context, state) {
context.read<DocumentDetailsCubit>().loadMetaData();
},
child: Scaffold(
extendBodyBehindAppBar: false,
floatingActionButtonLocation: FloatingActionButtonLocation.endDocked,
floatingActionButtonLocation:
FloatingActionButtonLocation.endDocked,
floatingActionButton: _buildEditButton(),
bottomNavigationBar: _buildBottomAppBar(),
body: NestedScrollView(
headerSliverBuilder: (context, innerBoxIsScrolled) => [
SliverOverlapAbsorber(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
handle:
NestedScrollView.sliverOverlapAbsorberHandleFor(context),
sliver: SliverAppBar(
title: Text(context.watch<DocumentDetailsCubit>().state.document.title),
title: Text(context
.watch<DocumentDetailsCubit>()
.state
.document
.title),
leading: const BackButton(),
pinned: true,
forceElevated: innerBoxIsScrolled,
@@ -81,7 +89,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
background: Stack(
alignment: Alignment.topCenter,
children: [
BlocBuilder<DocumentDetailsCubit, DocumentDetailsState>(
BlocBuilder<DocumentDetailsCubit,
DocumentDetailsState>(
builder: (context, state) {
return Positioned.fill(
child: DocumentPreview(
@@ -97,8 +106,14 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
decoration: BoxDecoration(
gradient: LinearGradient(
colors: [
Theme.of(context).colorScheme.background.withOpacity(0.8),
Theme.of(context).colorScheme.background.withOpacity(0.5),
Theme.of(context)
.colorScheme
.background
.withOpacity(0.8),
Theme.of(context)
.colorScheme
.background
.withOpacity(0.5),
Colors.transparent,
Colors.transparent,
Colors.transparent,
@@ -120,7 +135,9 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
child: Text(
S.of(context)!.overview,
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimaryContainer,
color: Theme.of(context)
.colorScheme
.onPrimaryContainer,
),
),
),
@@ -128,7 +145,9 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
child: Text(
S.of(context)!.content,
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimaryContainer,
color: Theme.of(context)
.colorScheme
.onPrimaryContainer,
),
),
),
@@ -136,7 +155,9 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
child: Text(
S.of(context)!.metaData,
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimaryContainer,
color: Theme.of(context)
.colorScheme
.onPrimaryContainer,
),
),
),
@@ -144,7 +165,9 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
child: Text(
S.of(context)!.similarDocuments,
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimaryContainer,
color: Theme.of(context)
.colorScheme
.onPrimaryContainer,
),
),
),
@@ -153,7 +176,9 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
child: Text(
"Permissions",
style: TextStyle(
color: Theme.of(context).colorScheme.onPrimaryContainer,
color: Theme.of(context)
.colorScheme
.onPrimaryContainer,
),
),
),
@@ -182,7 +207,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
DocumentOverviewWidget(
document: state.document,
@@ -198,7 +224,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
DocumentContentWidget(
isFullContentLoaded: state.isFullContentLoaded,
@@ -211,7 +238,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
CustomScrollView(
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
DocumentMetaDataWidget(
document: state.document,
@@ -223,7 +251,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
controller: _pagingScrollController,
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
SimilarDocumentsView(
pagingScrollController: _pagingScrollController,
@@ -235,7 +264,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
controller: _pagingScrollController,
slivers: [
SliverOverlapInjector(
handle: NestedScrollView.sliverOverlapAbsorberHandleFor(context),
handle: NestedScrollView
.sliverOverlapAbsorberHandleFor(context),
),
DocumentPermissionsWidget(
document: state.document,
@@ -289,15 +319,16 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
final isConnected = connectivityState.isConnected;
final canDelete = isConnected &&
LocalUserAccount.current.paperlessUser
.hasPermission(PermissionAction.delete, PermissionTarget.document);
LocalUserAccount.current.paperlessUser.hasPermission(
PermissionAction.delete, PermissionTarget.document);
return Row(
mainAxisAlignment: MainAxisAlignment.start,
children: [
IconButton(
tooltip: S.of(context)!.deleteDocumentTooltip,
icon: const Icon(Icons.delete),
onPressed: canDelete ? () => _onDelete(state.document) : null,
onPressed:
canDelete ? () => _onDelete(state.document) : null,
).paddedSymmetrically(horizontal: 4),
DocumentDownloadButton(
document: state.document,
@@ -307,7 +338,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
IconButton(
tooltip: S.of(context)!.previewTooltip,
icon: const Icon(Icons.visibility),
onPressed: (isConnected) ? () => _onOpen(state.document) : null,
onPressed:
(isConnected) ? () => _onOpen(state.document) : null,
).paddedOnly(right: 4.0),
IconButton(
tooltip: S.of(context)!.openInSystemViewer,
@@ -317,7 +349,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
DocumentShareButton(document: state.document),
IconButton(
tooltip: S.of(context)!.print, //TODO: INTL
onPressed: () => context.read<DocumentDetailsCubit>().printDocument(),
onPressed: () =>
context.read<DocumentDetailsCubit>().printDocument(),
icon: const Icon(Icons.print),
),
],
@@ -350,7 +383,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
),
],
child: BlocListener<DocumentEditCubit, DocumentEditState>(
listenWhen: (previous, current) => previous.document != current.document,
listenWhen: (previous, current) =>
previous.document != current.document,
listener: (context, state) {
cubit.replace(state.document);
},
@@ -370,7 +404,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
}
void _onOpenFileInSystemViewer() async {
final status = await context.read<DocumentDetailsCubit>().openDocumentInSystemViewer();
final status =
await context.read<DocumentDetailsCubit>().openDocumentInSystemViewer();
if (status == ResultType.done) return;
if (status == ResultType.noAppToOpen) {
showGenericError(context, S.of(context)!.noAppToDisplayPDFFilesFound);
@@ -379,14 +414,16 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
showGenericError(context, translateError(context, ErrorCode.unknown));
}
if (status == ResultType.permissionDenied) {
showGenericError(context, S.of(context)!.couldNotOpenFilePermissionDenied);
showGenericError(
context, S.of(context)!.couldNotOpenFilePermissionDenied);
}
}
void _onDelete(DocumentModel document) async {
final delete = await showDialog(
context: context,
builder: (context) => DeleteDocumentConfirmationDialog(document: document),
builder: (context) =>
DeleteDocumentConfirmationDialog(document: document),
) ??
false;
if (delete) {
@@ -406,7 +443,8 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
Navigator.of(context).push(
MaterialPageRoute(
builder: (_) => DocumentView(
documentBytes: context.read<PaperlessDocumentsApi>().download(document),
documentBytes:
context.read<PaperlessDocumentsApi>().download(document),
title: document.title,
),
),

View File

@@ -18,7 +18,8 @@ class ArchiveSerialNumberField extends StatefulWidget {
});
@override
State<ArchiveSerialNumberField> createState() => _ArchiveSerialNumberFieldState();
State<ArchiveSerialNumberField> createState() =>
_ArchiveSerialNumberFieldState();
}
class _ArchiveSerialNumberFieldState extends State<ArchiveSerialNumberField> {
@@ -39,21 +40,25 @@ class _ArchiveSerialNumberFieldState extends State<ArchiveSerialNumberField> {
void _clearButtonListener() {
setState(() {
_showClearButton = _asnEditingController.text.isNotEmpty;
_canUpdate = int.tryParse(_asnEditingController.text) != widget.document.archiveSerialNumber;
_canUpdate = int.tryParse(_asnEditingController.text) !=
widget.document.archiveSerialNumber;
});
}
@override
Widget build(BuildContext context) {
final userCanEditDocument = LocalUserAccount.current.paperlessUser.hasPermission(
final userCanEditDocument =
LocalUserAccount.current.paperlessUser.hasPermission(
PermissionAction.change,
PermissionTarget.document,
);
return BlocListener<DocumentDetailsCubit, DocumentDetailsState>(
listenWhen: (previous, current) =>
previous.document.archiveSerialNumber != current.document.archiveSerialNumber,
previous.document.archiveSerialNumber !=
current.document.archiveSerialNumber,
listener: (context, state) {
_asnEditingController.text = state.document.archiveSerialNumber?.toString() ?? '';
_asnEditingController.text =
state.document.archiveSerialNumber?.toString() ?? '';
setState(() {
_canUpdate = false;
});
@@ -80,13 +85,17 @@ class _ArchiveSerialNumberFieldState extends State<ArchiveSerialNumberField> {
IconButton(
icon: const Icon(Icons.clear),
color: Theme.of(context).colorScheme.primary,
onPressed: userCanEditDocument ? _asnEditingController.clear : null,
onPressed: userCanEditDocument
? _asnEditingController.clear
: null,
),
IconButton(
icon: const Icon(Icons.plus_one_rounded),
color: Theme.of(context).colorScheme.primary,
onPressed:
context.watchInternetConnection && !_showClearButton ? _onAutoAssign : null,
context.watchInternetConnection && !_showClearButton
? _onAutoAssign
: null,
).paddedOnly(right: 8),
],
),
@@ -97,7 +106,9 @@ class _ArchiveSerialNumberFieldState extends State<ArchiveSerialNumberField> {
),
TextButton.icon(
icon: const Icon(Icons.done),
onPressed: context.watchInternetConnection && _canUpdate ? _onSubmitted : null,
onPressed: context.watchInternetConnection && _canUpdate
? _onSubmitted
: null,
label: Text(S.of(context)!.save),
).padded(),
],

View File

@@ -24,7 +24,8 @@ class DetailsItem extends StatelessWidget {
}
DetailsItem.text(
String text, {super.key,
String text, {
super.key,
required this.label,
required BuildContext context,
}) : content = Text(

View File

@@ -44,14 +44,16 @@ class _DocumentDownloadButtonState extends State<DocumentDownloadButton> {
width: 16,
)
: const Icon(Icons.download),
onPressed:
widget.document != null && widget.enabled ? () => _onDownload(widget.document!) : null,
onPressed: widget.document != null && widget.enabled
? () => _onDownload(widget.document!)
: null,
).paddedOnly(right: 4);
}
Future<void> _onDownload(DocumentModel document) async {
try {
final globalSettings = Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!;
final globalSettings =
Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!;
bool original;
switch (globalSettings.defaultDownloadType) {

View File

@@ -6,7 +6,8 @@ class DocumentPermissionsWidget extends StatefulWidget {
const DocumentPermissionsWidget({super.key, required this.document});
@override
State<DocumentPermissionsWidget> createState() => _DocumentPermissionsWidgetState();
State<DocumentPermissionsWidget> createState() =>
_DocumentPermissionsWidgetState();
}
class _DocumentPermissionsWidgetState extends State<DocumentPermissionsWidget> {

View File

@@ -43,14 +43,16 @@ class _DocumentShareButtonState extends State<DocumentShareButton> {
child: CircularProgressIndicator(),
)
: const Icon(Icons.share),
onPressed:
widget.document != null && widget.enabled ? () => _onShare(widget.document!) : null,
onPressed: widget.document != null && widget.enabled
? () => _onShare(widget.document!)
: null,
).paddedOnly(right: 4);
}
Future<void> _onShare(DocumentModel document) async {
try {
final globalSettings = Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!;
final globalSettings =
Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!;
bool original;
switch (globalSettings.defaultShareType) {