mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-06 21:15:50 -06:00
fix: Fixed saved views bug, formatted files, minor changes
This commit is contained in:
@@ -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";
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
),
|
||||
],
|
||||
|
||||
@@ -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,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -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(),
|
||||
],
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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> {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user