mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-06 23:15:43 -06:00
Resetting filter doesn't reset sorting, some bugfixes and UI updates
This commit is contained in:
@@ -49,7 +49,6 @@ void main() async {
|
||||
|
||||
await getIt<ConnectivityCubit>().initialize();
|
||||
await getIt<ApplicationSettingsCubit>().initialize();
|
||||
await getIt<AuthenticationCubit>().initialize();
|
||||
});
|
||||
|
||||
// Mocked classes
|
||||
@@ -97,7 +96,6 @@ void main() async {
|
||||
|
||||
await getIt<ConnectivityCubit>().initialize();
|
||||
await getIt<ApplicationSettingsCubit>().initialize();
|
||||
await getIt<AuthenticationCubit>().initialize();
|
||||
});
|
||||
// Mocked classes
|
||||
|
||||
@@ -149,7 +147,6 @@ void main() async {
|
||||
));
|
||||
await getIt<ConnectivityCubit>().initialize();
|
||||
await getIt<ApplicationSettingsCubit>().initialize();
|
||||
await getIt<AuthenticationCubit>().initialize();
|
||||
});
|
||||
|
||||
await t.binding.waitUntilFirstFrameRasterized;
|
||||
@@ -199,7 +196,6 @@ void main() async {
|
||||
|
||||
await getIt<ConnectivityCubit>().initialize();
|
||||
await getIt<ApplicationSettingsCubit>().initialize();
|
||||
await getIt<AuthenticationCubit>().initialize();
|
||||
});
|
||||
|
||||
await t.binding.waitUntilFirstFrameRasterized;
|
||||
|
||||
@@ -2,6 +2,7 @@ import 'package:flutter/widgets.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:integration_test/integration_test.dart';
|
||||
import 'package:paperless_mobile/di_initializer.dart';
|
||||
import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart';
|
||||
import 'package:paperless_mobile/generated/l10n.dart';
|
||||
import 'package:paperless_mobile/main.dart';
|
||||
|
||||
@@ -35,5 +36,5 @@ Future<void> initAndLaunchTestApp(
|
||||
Future<void> Function() initializationCallback,
|
||||
) async {
|
||||
await initializationCallback();
|
||||
runApp(const PaperlessMobileEntrypoint());
|
||||
//runApp(const PaperlessMobileEntrypoint(authenticationCubit: ),));
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_api/src/models/saved_view_model.dart';
|
||||
import 'package:paperless_mobile/core/repository/saved_view_repository.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
@@ -8,11 +7,10 @@ class SavedViewRepositoryImpl implements SavedViewRepository {
|
||||
|
||||
SavedViewRepositoryImpl(this._api);
|
||||
|
||||
final BehaviorSubject<Map<int, SavedView>> _subject =
|
||||
BehaviorSubject.seeded({});
|
||||
final BehaviorSubject<Map<int, SavedView>?> _subject = BehaviorSubject();
|
||||
|
||||
@override
|
||||
Stream<Map<int, SavedView>> get savedViews =>
|
||||
Stream<Map<int, SavedView>?> get savedViews =>
|
||||
_subject.stream.asBroadcastStream();
|
||||
|
||||
@override
|
||||
@@ -23,7 +21,7 @@ class SavedViewRepositoryImpl implements SavedViewRepository {
|
||||
@override
|
||||
Future<SavedView> create(SavedView view) async {
|
||||
final created = await _api.save(view);
|
||||
final updatedState = {..._subject.value}
|
||||
final updatedState = {..._subject.valueOrNull ?? {}}
|
||||
..putIfAbsent(created.id!, () => created);
|
||||
_subject.add(updatedState);
|
||||
return created;
|
||||
@@ -32,7 +30,7 @@ class SavedViewRepositoryImpl implements SavedViewRepository {
|
||||
@override
|
||||
Future<int> delete(SavedView view) async {
|
||||
await _api.delete(view);
|
||||
final updatedState = {..._subject.value}..remove(view.id);
|
||||
final updatedState = {..._subject.valueOrNull ?? {}}..remove(view.id);
|
||||
_subject.add(updatedState);
|
||||
return view.id!;
|
||||
}
|
||||
@@ -40,7 +38,7 @@ class SavedViewRepositoryImpl implements SavedViewRepository {
|
||||
@override
|
||||
Future<SavedView?> find(int id) async {
|
||||
final found = await _api.find(id);
|
||||
final updatedState = {..._subject.value}
|
||||
final updatedState = {..._subject.valueOrNull ?? {}}
|
||||
..update(id, (_) => found, ifAbsent: () => found);
|
||||
_subject.add(updatedState);
|
||||
return found;
|
||||
@@ -50,7 +48,7 @@ class SavedViewRepositoryImpl implements SavedViewRepository {
|
||||
Future<Iterable<SavedView>> findAll([Iterable<int>? ids]) async {
|
||||
final found = await _api.findAll(ids);
|
||||
final updatedState = {
|
||||
..._subject.value,
|
||||
..._subject.valueOrNull ?? {},
|
||||
...{for (final view in found) view.id!: view},
|
||||
};
|
||||
_subject.add(updatedState);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
|
||||
abstract class SavedViewRepository {
|
||||
Stream<Map<int, SavedView>> get savedViews;
|
||||
Stream<Map<int, SavedView>?> get savedViews;
|
||||
|
||||
Future<SavedView> create(SavedView view);
|
||||
Future<SavedView?> find(int id);
|
||||
|
||||
@@ -2,7 +2,6 @@ import 'dart:io';
|
||||
|
||||
import 'package:paperless_mobile/di_initializer.config.dart';
|
||||
import 'package:paperless_mobile/di_modules.dart';
|
||||
import 'package:paperless_mobile/di_paperless_api.dart';
|
||||
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
|
||||
import 'package:get_it/get_it.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
@@ -21,7 +20,7 @@ void configureDependencies(String environment) =>
|
||||
///
|
||||
/// Registers new security context, which will be used by the HttpClient, see [RegisterModule].
|
||||
///
|
||||
void registerSecurityContext(ClientCertificate? cert) {
|
||||
Future<void> registerSecurityContext(ClientCertificate? cert) async {
|
||||
var context = SecurityContext();
|
||||
if (cert != null) {
|
||||
context = context
|
||||
@@ -29,6 +28,6 @@ void registerSecurityContext(ClientCertificate? cert) {
|
||||
..useCertificateChainBytes(cert.bytes, password: cert.passphrase)
|
||||
..setTrustedCertificatesBytes(cert.bytes, password: cert.passphrase);
|
||||
}
|
||||
getIt.unregister<SecurityContext>();
|
||||
await getIt.unregister<SecurityContext>();
|
||||
getIt.registerSingleton<SecurityContext>(context);
|
||||
}
|
||||
|
||||
@@ -107,11 +107,11 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
color: Colors
|
||||
.black, //TODO: check if there is a way to dynamically determine color...
|
||||
),
|
||||
onPressed: () => Navigator.pop(
|
||||
context,
|
||||
BlocProvider.of<DocumentDetailsCubit>(context)
|
||||
.state
|
||||
.document),
|
||||
onPressed: () => Navigator.of(context).pop(
|
||||
BlocProvider.of<DocumentDetailsCubit>(context)
|
||||
.state
|
||||
.document,
|
||||
),
|
||||
),
|
||||
floating: true,
|
||||
pinned: true,
|
||||
@@ -237,13 +237,13 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
return ListView(
|
||||
children: [
|
||||
_DetailsItem.text(DateFormat().format(document.modified),
|
||||
label: S.of(context).documentModifiedPropertyLabel,
|
||||
context: context),
|
||||
_separator(),
|
||||
label: S.of(context).documentModifiedPropertyLabel,
|
||||
context: context)
|
||||
.paddedOnly(bottom: 16),
|
||||
_DetailsItem.text(DateFormat().format(document.added),
|
||||
label: S.of(context).documentAddedPropertyLabel,
|
||||
context: context),
|
||||
_separator(),
|
||||
label: S.of(context).documentAddedPropertyLabel,
|
||||
context: context)
|
||||
.paddedSymmetrically(vertical: 16),
|
||||
_DetailsItem(
|
||||
label: S.of(context).documentArchiveSerialNumberPropertyLongLabel,
|
||||
content: document.archiveSerialNumber != null
|
||||
@@ -255,30 +255,26 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
onPressed:
|
||||
widget.allowEdit ? () => _assignAsn(document) : null,
|
||||
),
|
||||
),
|
||||
_separator(),
|
||||
).paddedSymmetrically(vertical: 16),
|
||||
_DetailsItem.text(
|
||||
meta.mediaFilename,
|
||||
context: context,
|
||||
label: S.of(context).documentMetaDataMediaFilenamePropertyLabel,
|
||||
),
|
||||
_separator(),
|
||||
).paddedSymmetrically(vertical: 16),
|
||||
_DetailsItem.text(
|
||||
meta.originalChecksum,
|
||||
context: context,
|
||||
label: S.of(context).documentMetaDataChecksumLabel,
|
||||
),
|
||||
_separator(),
|
||||
).paddedSymmetrically(vertical: 16),
|
||||
_DetailsItem.text(formatBytes(meta.originalSize, 2),
|
||||
label: S.of(context).documentMetaDataOriginalFileSizeLabel,
|
||||
context: context),
|
||||
_separator(),
|
||||
label: S.of(context).documentMetaDataOriginalFileSizeLabel,
|
||||
context: context)
|
||||
.paddedSymmetrically(vertical: 16),
|
||||
_DetailsItem.text(
|
||||
meta.originalMimeType,
|
||||
label: S.of(context).documentMetaDataOriginalMimeTypeLabel,
|
||||
context: context,
|
||||
),
|
||||
_separator(),
|
||||
).paddedSymmetrically(vertical: 16),
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -295,16 +291,13 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
|
||||
Widget _buildDocumentContentView(DocumentModel document, String? match) {
|
||||
return SingleChildScrollView(
|
||||
child: _DetailsItem(
|
||||
content: HighlightedText(
|
||||
text: document.content ?? "",
|
||||
highlights: match == null ? [] : match.split(" "),
|
||||
style: Theme.of(context).textTheme.bodyText2,
|
||||
caseSensitive: false,
|
||||
),
|
||||
label: S.of(context).documentDetailsPageTabContentLabel,
|
||||
child: HighlightedText(
|
||||
text: document.content ?? "",
|
||||
highlights: match == null ? [] : match.split(" "),
|
||||
style: Theme.of(context).textTheme.bodyText2,
|
||||
caseSensitive: false,
|
||||
),
|
||||
);
|
||||
).paddedOnly(top: 8);
|
||||
}
|
||||
|
||||
Widget _buildDocumentOverview(DocumentModel document, String? match) {
|
||||
@@ -314,60 +307,61 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
content: HighlightedText(
|
||||
text: document.title,
|
||||
highlights: match?.split(" ") ?? <String>[],
|
||||
style: Theme.of(context).textTheme.bodyLarge,
|
||||
),
|
||||
label: S.of(context).documentTitlePropertyLabel,
|
||||
),
|
||||
_separator(),
|
||||
).paddedOnly(bottom: 16),
|
||||
_DetailsItem.text(
|
||||
DateFormat.yMMMd().format(document.created),
|
||||
context: context,
|
||||
label: S.of(context).documentCreatedPropertyLabel,
|
||||
),
|
||||
_separator(),
|
||||
_DetailsItem(
|
||||
content: DocumentTypeWidget(
|
||||
isClickable: widget.isLabelClickable,
|
||||
documentTypeId: document.documentType,
|
||||
afterSelected: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
label: S.of(context).documentDocumentTypePropertyLabel,
|
||||
),
|
||||
_separator(),
|
||||
_DetailsItem(
|
||||
label: S.of(context).documentCorrespondentPropertyLabel,
|
||||
content: CorrespondentWidget(
|
||||
isClickable: widget.isLabelClickable,
|
||||
correspondentId: document.correspondent,
|
||||
afterSelected: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
_separator(),
|
||||
_DetailsItem(
|
||||
label: S.of(context).documentStoragePathPropertyLabel,
|
||||
content: StoragePathWidget(
|
||||
isClickable: widget.isLabelClickable,
|
||||
pathId: document.storagePath,
|
||||
afterSelected: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
),
|
||||
_separator(),
|
||||
_DetailsItem(
|
||||
label: S.of(context).documentTagsPropertyLabel,
|
||||
content: Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: TagsWidget(
|
||||
).paddedSymmetrically(vertical: 16),
|
||||
Visibility(
|
||||
visible: document.documentType != null,
|
||||
child: _DetailsItem(
|
||||
content: DocumentTypeWidget(
|
||||
textStyle: Theme.of(context).textTheme.bodyLarge,
|
||||
isClickable: widget.isLabelClickable,
|
||||
tagIds: document.tags,
|
||||
isSelectedPredicate: (_) => false,
|
||||
onTagSelected: (int tagId) {},
|
||||
documentTypeId: document.documentType,
|
||||
),
|
||||
),
|
||||
label: S.of(context).documentDocumentTypePropertyLabel,
|
||||
).paddedSymmetrically(vertical: 16),
|
||||
),
|
||||
Visibility(
|
||||
visible: document.correspondent != null,
|
||||
child: _DetailsItem(
|
||||
label: S.of(context).documentCorrespondentPropertyLabel,
|
||||
content: CorrespondentWidget(
|
||||
textStyle: Theme.of(context).textTheme.bodyLarge,
|
||||
isClickable: widget.isLabelClickable,
|
||||
correspondentId: document.correspondent,
|
||||
),
|
||||
).paddedSymmetrically(vertical: 16),
|
||||
),
|
||||
Visibility(
|
||||
visible: document.storagePath != null,
|
||||
child: _DetailsItem(
|
||||
label: S.of(context).documentStoragePathPropertyLabel,
|
||||
content: StoragePathWidget(
|
||||
isClickable: widget.isLabelClickable,
|
||||
pathId: document.storagePath,
|
||||
),
|
||||
).paddedSymmetrically(vertical: 16),
|
||||
),
|
||||
Visibility(
|
||||
visible: document.tags.isNotEmpty,
|
||||
child: _DetailsItem(
|
||||
label: S.of(context).documentTagsPropertyLabel,
|
||||
content: Padding(
|
||||
padding: const EdgeInsets.only(top: 8.0),
|
||||
child: TagsWidget(
|
||||
isClickable: widget.isLabelClickable,
|
||||
tagIds: document.tags,
|
||||
isSelectedPredicate: (_) => false,
|
||||
onTagSelected: (int tagId) {},
|
||||
),
|
||||
),
|
||||
).paddedSymmetrically(vertical: 16),
|
||||
),
|
||||
// _separator(),
|
||||
// FutureBuilder<List<SimilarDocumentModel>>(
|
||||
@@ -396,10 +390,6 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _separator() {
|
||||
return const SizedBox(height: 32.0);
|
||||
}
|
||||
|
||||
///
|
||||
/// Downloads file to temporary directory, from which it can then be shared.
|
||||
///
|
||||
@@ -477,10 +467,7 @@ class _DetailsItem extends StatelessWidget {
|
||||
children: [
|
||||
Text(
|
||||
label,
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.headline5
|
||||
?.copyWith(fontWeight: FontWeight.bold),
|
||||
style: Theme.of(context).textTheme.caption,
|
||||
),
|
||||
content,
|
||||
],
|
||||
@@ -492,7 +479,7 @@ class _DetailsItem extends StatelessWidget {
|
||||
String text, {
|
||||
required this.label,
|
||||
required BuildContext context,
|
||||
}) : content = Text(text, style: Theme.of(context).textTheme.bodyText2);
|
||||
}) : content = Text(text, style: Theme.of(context).textTheme.bodyLarge);
|
||||
}
|
||||
|
||||
class ColoredTabBar extends Container implements PreferredSizeWidget {
|
||||
|
||||
@@ -88,6 +88,13 @@ class DocumentsCubit extends Cubit<DocumentsState> {
|
||||
emit(DocumentsState(filter: filter, value: [result], isLoaded: true));
|
||||
}
|
||||
|
||||
Future<void> resetFilter() async {
|
||||
final filter = DocumentFilter.initial.copyWith(
|
||||
sortField: state.filter.sortField,
|
||||
sortOrder: state.filter.sortOrder,
|
||||
);
|
||||
}
|
||||
|
||||
///
|
||||
/// Convenience method which allows to directly use [DocumentFilter.copyWith] on the current filter.
|
||||
///
|
||||
|
||||
@@ -151,22 +151,28 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
switch (settings.preferredViewType) {
|
||||
case ViewType.list:
|
||||
child = DocumentListView(
|
||||
onTap: _openDetails,
|
||||
state: state,
|
||||
onTap: _openDetails,
|
||||
onSelected: _onSelected,
|
||||
pagingController: _pagingController,
|
||||
hasInternetConnection: isConnected,
|
||||
onTagSelected: _addTagToFilter,
|
||||
onCorrespondentSelected: _addCorrespondentToFilter,
|
||||
onDocumentTypeSelected: _addDocumentTypeToFilter,
|
||||
onStoragePathSelected: _addStoragePathToFilter,
|
||||
);
|
||||
break;
|
||||
case ViewType.grid:
|
||||
child = DocumentGridView(
|
||||
onTap: _openDetails,
|
||||
state: state,
|
||||
onTap: _openDetails,
|
||||
onSelected: _onSelected,
|
||||
pagingController: _pagingController,
|
||||
hasInternetConnection: isConnected,
|
||||
onTagSelected: _addTagToFilter,
|
||||
onCorrespondentSelected: _addCorrespondentToFilter,
|
||||
onDocumentTypeSelected: _addDocumentTypeToFilter,
|
||||
onStoragePathSelected: _addStoragePathToFilter,
|
||||
);
|
||||
break;
|
||||
}
|
||||
@@ -176,7 +182,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
child: DocumentsEmptyState(
|
||||
state: state,
|
||||
onReset: () {
|
||||
_documentsCubit.updateFilter();
|
||||
_documentsCubit.resetFilter();
|
||||
_savedViewCubit.resetSelection();
|
||||
},
|
||||
),
|
||||
@@ -195,7 +201,7 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
listener: (context, state) {
|
||||
try {
|
||||
if (state.selectedSavedViewId == null) {
|
||||
_documentsCubit.updateFilter();
|
||||
_documentsCubit.resetFilter();
|
||||
} else {
|
||||
final newFilter = state
|
||||
.value[state.selectedSavedViewId]
|
||||
@@ -280,6 +286,63 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
}
|
||||
}
|
||||
|
||||
void _addCorrespondentToFilter(int? correspondentId) {
|
||||
final cubit = BlocProvider.of<DocumentsCubit>(context);
|
||||
try {
|
||||
if (cubit.state.filter.correspondent.id == correspondentId) {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(correspondent: const CorrespondentQuery.unset()),
|
||||
);
|
||||
} else {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) => filter.copyWith(
|
||||
correspondent: CorrespondentQuery.fromId(correspondentId)),
|
||||
);
|
||||
}
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
void _addDocumentTypeToFilter(int? documentTypeId) {
|
||||
final cubit = BlocProvider.of<DocumentsCubit>(context);
|
||||
try {
|
||||
if (cubit.state.filter.documentType.id == documentTypeId) {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(documentType: const DocumentTypeQuery.unset()),
|
||||
);
|
||||
} else {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) => filter.copyWith(
|
||||
documentType: DocumentTypeQuery.fromId(documentTypeId)),
|
||||
);
|
||||
}
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
void _addStoragePathToFilter(int? pathId) {
|
||||
final cubit = BlocProvider.of<DocumentsCubit>(context);
|
||||
try {
|
||||
if (cubit.state.filter.correspondent.id == pathId) {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(storagePath: const StoragePathQuery.unset()),
|
||||
);
|
||||
} else {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(storagePath: StoragePathQuery.fromId(pathId)),
|
||||
);
|
||||
}
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _loadNewPage(int pageKey) async {
|
||||
final pageCount = _documentsCubit.state
|
||||
.inferPageCount(pageSize: _documentsCubit.state.filter.pageSize);
|
||||
@@ -299,9 +362,10 @@ class _DocumentsPageState extends State<DocumentsPage> {
|
||||
|
||||
Future<void> _onRefresh() async {
|
||||
try {
|
||||
await _documentsCubit.updateCurrentFilter(
|
||||
_documentsCubit.updateCurrentFilter(
|
||||
(filter) => filter.copyWith(page: 1),
|
||||
);
|
||||
_savedViewCubit.reload();
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,9 @@ class DocumentGridView extends StatelessWidget {
|
||||
final DocumentsState state;
|
||||
final bool hasInternetConnection;
|
||||
final void Function(int tagId) onTagSelected;
|
||||
final void Function(int correspondentId) onCorrespondentSelected;
|
||||
final void Function(int correspondentId) onDocumentTypeSelected;
|
||||
final void Function(int? id)? onStoragePathSelected;
|
||||
|
||||
const DocumentGridView({
|
||||
super.key,
|
||||
@@ -21,6 +24,9 @@ class DocumentGridView extends StatelessWidget {
|
||||
required this.onSelected,
|
||||
required this.hasInternetConnection,
|
||||
required this.onTagSelected,
|
||||
required this.onCorrespondentSelected,
|
||||
required this.onDocumentTypeSelected,
|
||||
this.onStoragePathSelected,
|
||||
});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/provider/label_repositories_provider.dart';
|
||||
import 'package:paperless_mobile/core/widgets/documents_list_loading_widget.dart';
|
||||
@@ -16,7 +15,10 @@ class DocumentListView extends StatelessWidget {
|
||||
final DocumentsState state;
|
||||
final bool hasInternetConnection;
|
||||
final bool isLabelClickable;
|
||||
final void Function(int tagId) onTagSelected;
|
||||
final void Function(int id)? onTagSelected;
|
||||
final void Function(int? id)? onCorrespondentSelected;
|
||||
final void Function(int? id)? onDocumentTypeSelected;
|
||||
final void Function(int? id)? onStoragePathSelected;
|
||||
|
||||
const DocumentListView({
|
||||
super.key,
|
||||
@@ -26,7 +28,10 @@ class DocumentListView extends StatelessWidget {
|
||||
required this.onSelected,
|
||||
required this.hasInternetConnection,
|
||||
this.isLabelClickable = true,
|
||||
required this.onTagSelected,
|
||||
this.onTagSelected,
|
||||
this.onCorrespondentSelected,
|
||||
this.onDocumentTypeSelected,
|
||||
this.onStoragePathSelected,
|
||||
});
|
||||
|
||||
@override
|
||||
@@ -52,6 +57,9 @@ class DocumentListView extends StatelessWidget {
|
||||
: false;
|
||||
},
|
||||
onTagSelected: onTagSelected,
|
||||
onCorrespondentSelected: onCorrespondentSelected,
|
||||
onDocumentTypeSelected: onDocumentTypeSelected,
|
||||
onStoragePathSelected: onStoragePathSelected,
|
||||
),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -14,7 +14,10 @@ class DocumentListItem extends StatelessWidget {
|
||||
final bool isLabelClickable;
|
||||
final bool Function(int tagId) isTagSelectedPredicate;
|
||||
|
||||
final void Function(int tagId) onTagSelected;
|
||||
final void Function(int tagId)? onTagSelected;
|
||||
final void Function(int? correspondentId)? onCorrespondentSelected;
|
||||
final void Function(int? documentTypeId)? onDocumentTypeSelected;
|
||||
final void Function(int? id)? onStoragePathSelected;
|
||||
|
||||
const DocumentListItem({
|
||||
Key? key,
|
||||
@@ -25,7 +28,10 @@ class DocumentListItem extends StatelessWidget {
|
||||
required this.isAtLeastOneSelected,
|
||||
this.isLabelClickable = true,
|
||||
required this.isTagSelectedPredicate,
|
||||
required this.onTagSelected,
|
||||
this.onTagSelected,
|
||||
this.onCorrespondentSelected,
|
||||
this.onDocumentTypeSelected,
|
||||
this.onStoragePathSelected,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -48,6 +54,7 @@ class DocumentListItem extends StatelessWidget {
|
||||
child: CorrespondentWidget(
|
||||
isClickable: isLabelClickable,
|
||||
correspondentId: document.correspondent,
|
||||
onSelected: onCorrespondentSelected,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -68,7 +75,7 @@ class DocumentListItem extends StatelessWidget {
|
||||
tagIds: document.tags,
|
||||
isMultiLine: false,
|
||||
isSelectedPredicate: isTagSelectedPredicate,
|
||||
onTagSelected: onTagSelected,
|
||||
onTagSelected: (id) => onTagSelected?.call(id),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -123,7 +123,12 @@ class _DocumentFilterPanelState extends State<DocumentFilterPanel> {
|
||||
|
||||
void _resetFilter() async {
|
||||
FocusScope.of(context).unfocus();
|
||||
Navigator.pop(context, DocumentFilter.initial);
|
||||
Navigator.pop(
|
||||
context,
|
||||
DocumentFilter.initial.copyWith(
|
||||
sortField: widget.initialFilter.sortField,
|
||||
sortOrder: widget.initialFilter.sortOrder,
|
||||
));
|
||||
}
|
||||
|
||||
Widget _buildDocumentTypeFormField() {
|
||||
|
||||
@@ -100,7 +100,7 @@ class _LabelFormState<T extends Label> extends State<LabelForm<T>> {
|
||||
),
|
||||
FormBuilderCheckbox(
|
||||
name: Label.isInsensitiveKey,
|
||||
initialValue: widget.initialValue?.isInsensitive,
|
||||
initialValue: widget.initialValue?.isInsensitive ?? true,
|
||||
title: Text(S.of(context).labelIsInsensivitePropertyLabel),
|
||||
),
|
||||
...widget.additionalFields,
|
||||
|
||||
@@ -5,7 +5,6 @@ import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||
import 'package:paperless_mobile/core/bloc/paperless_server_information_cubit.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/core/repository/saved_view_repository.dart';
|
||||
import 'package:paperless_mobile/core/widgets/offline_banner.dart';
|
||||
import 'package:paperless_mobile/di_initializer.dart';
|
||||
import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart';
|
||||
import 'package:paperless_mobile/features/documents/view/pages/documents_page.dart';
|
||||
|
||||
@@ -9,16 +9,18 @@ import 'package:paperless_mobile/util.dart';
|
||||
|
||||
class CorrespondentWidget extends StatelessWidget {
|
||||
final int? correspondentId;
|
||||
final void Function()? afterSelected;
|
||||
final void Function(int? id)? onSelected;
|
||||
final Color? textColor;
|
||||
final bool isClickable;
|
||||
final TextStyle? textStyle;
|
||||
|
||||
const CorrespondentWidget({
|
||||
Key? key,
|
||||
this.correspondentId,
|
||||
this.afterSelected,
|
||||
required this.correspondentId,
|
||||
this.textColor,
|
||||
this.isClickable = true,
|
||||
this.textStyle,
|
||||
this.onSelected,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -30,14 +32,15 @@ class CorrespondentWidget extends StatelessWidget {
|
||||
BlocBuilder<LabelCubit<Correspondent>, LabelState<Correspondent>>(
|
||||
builder: (context, state) {
|
||||
return GestureDetector(
|
||||
onTap: () => _addCorrespondentToFilter(context),
|
||||
onTap: () => onSelected?.call(correspondentId!),
|
||||
child: Text(
|
||||
(state.getLabel(correspondentId)?.name) ?? "-",
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: Theme.of(context).textTheme.bodyText2?.copyWith(
|
||||
color: textColor ?? Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
style: (textStyle ?? Theme.of(context).textTheme.bodyText2)
|
||||
?.copyWith(
|
||||
color: textColor ?? Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
@@ -45,24 +48,4 @@ class CorrespondentWidget extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _addCorrespondentToFilter(BuildContext context) {
|
||||
final cubit = BlocProvider.of<DocumentsCubit>(context);
|
||||
try {
|
||||
if (cubit.state.filter.correspondent.id == correspondentId) {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(correspondent: const CorrespondentQuery.unset()),
|
||||
);
|
||||
} else {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) => filter.copyWith(
|
||||
correspondent: CorrespondentQuery.fromId(correspondentId)),
|
||||
);
|
||||
}
|
||||
afterSelected?.call();
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,20 +2,20 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart';
|
||||
import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/labels/bloc/label_state.dart';
|
||||
import 'package:paperless_mobile/util.dart';
|
||||
|
||||
class DocumentTypeWidget extends StatelessWidget {
|
||||
final int? documentTypeId;
|
||||
final void Function()? afterSelected;
|
||||
final bool isClickable;
|
||||
final TextStyle? textStyle;
|
||||
final void Function(int? id)? onSelected;
|
||||
const DocumentTypeWidget({
|
||||
Key? key,
|
||||
required this.documentTypeId,
|
||||
this.afterSelected,
|
||||
this.isClickable = true,
|
||||
this.textStyle,
|
||||
this.onSelected,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -27,16 +27,14 @@ class DocumentTypeWidget extends StatelessWidget {
|
||||
child: AbsorbPointer(
|
||||
absorbing: !isClickable,
|
||||
child: GestureDetector(
|
||||
onTap: () => _addDocumentTypeToFilter(context),
|
||||
onTap: () => onSelected?.call(documentTypeId),
|
||||
child:
|
||||
BlocBuilder<LabelCubit<DocumentType>, LabelState<DocumentType>>(
|
||||
builder: (context, state) {
|
||||
return Text(
|
||||
state.labels[documentTypeId]?.toString() ?? "-",
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyText2!
|
||||
.copyWith(color: Theme.of(context).colorScheme.tertiary),
|
||||
style: (textStyle ?? Theme.of(context).textTheme.bodyText2)
|
||||
?.copyWith(color: Theme.of(context).colorScheme.tertiary),
|
||||
);
|
||||
},
|
||||
),
|
||||
@@ -44,24 +42,4 @@ class DocumentTypeWidget extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _addDocumentTypeToFilter(BuildContext context) {
|
||||
final cubit = BlocProvider.of<DocumentsCubit>(context);
|
||||
try {
|
||||
if (cubit.state.filter.documentType.id == documentTypeId) {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(documentType: const DocumentTypeQuery.unset()),
|
||||
);
|
||||
} else {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) => filter.copyWith(
|
||||
documentType: DocumentTypeQuery.fromId(documentTypeId)),
|
||||
);
|
||||
}
|
||||
afterSelected?.call();
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,23 +2,21 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||
import 'package:paperless_mobile/features/documents/bloc/documents_cubit.dart';
|
||||
import 'package:paperless_mobile/features/labels/bloc/label_cubit.dart';
|
||||
import 'package:paperless_mobile/features/labels/bloc/label_state.dart';
|
||||
import 'package:paperless_mobile/util.dart';
|
||||
|
||||
class StoragePathWidget extends StatelessWidget {
|
||||
final int? pathId;
|
||||
final void Function()? afterSelected;
|
||||
final Color? textColor;
|
||||
final bool isClickable;
|
||||
final void Function(int? id)? onSelected;
|
||||
|
||||
const StoragePathWidget({
|
||||
Key? key,
|
||||
this.pathId,
|
||||
this.afterSelected,
|
||||
this.textColor,
|
||||
this.isClickable = true,
|
||||
this.onSelected,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -32,7 +30,7 @@ class StoragePathWidget extends StatelessWidget {
|
||||
child: BlocBuilder<LabelCubit<StoragePath>, LabelState<StoragePath>>(
|
||||
builder: (context, state) {
|
||||
return GestureDetector(
|
||||
onTap: () => _addStoragePathToFilter(context),
|
||||
onTap: () => onSelected?.call(pathId),
|
||||
child: Text(
|
||||
state.getLabel(pathId)?.name ?? "-",
|
||||
maxLines: 1,
|
||||
@@ -47,24 +45,4 @@ class StoragePathWidget extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _addStoragePathToFilter(BuildContext context) {
|
||||
final cubit = BlocProvider.of<DocumentsCubit>(context);
|
||||
try {
|
||||
if (cubit.state.filter.correspondent.id == pathId) {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(storagePath: const StoragePathQuery.unset()),
|
||||
);
|
||||
} else {
|
||||
cubit.updateCurrentFilter(
|
||||
(filter) =>
|
||||
filter.copyWith(storagePath: StoragePathQuery.fromId(pathId)),
|
||||
);
|
||||
}
|
||||
afterSelected?.call();
|
||||
} on PaperlessServerException catch (error, stackTrace) {
|
||||
showErrorMessage(context, error, stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/store/local_vault.dart';
|
||||
import 'package:paperless_mobile/di_initializer.dart';
|
||||
@@ -11,12 +10,9 @@ import 'package:paperless_mobile/features/login/model/user_credentials.model.dar
|
||||
import 'package:paperless_mobile/features/login/services/authentication_service.dart';
|
||||
import 'package:paperless_mobile/features/settings/model/application_settings_state.dart';
|
||||
|
||||
@prod
|
||||
@test
|
||||
@singleton
|
||||
class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
final LocalAuthenticationService _localAuthService;
|
||||
final PaperlessAuthenticationApi _authApi;
|
||||
PaperlessAuthenticationApi _authApi;
|
||||
final LocalVault _localVault;
|
||||
|
||||
AuthenticationCubit(
|
||||
@@ -25,10 +21,6 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
this._authApi,
|
||||
) : super(AuthenticationState.initial);
|
||||
|
||||
Future<void> initialize() {
|
||||
return restoreSessionState();
|
||||
}
|
||||
|
||||
Future<void> login({
|
||||
required UserCredentials credentials,
|
||||
required String serverUrl,
|
||||
@@ -37,6 +29,8 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
assert(credentials.username != null && credentials.password != null);
|
||||
try {
|
||||
registerSecurityContext(clientCertificate);
|
||||
//TODO: Workaround for new architecture, listen for security context changes in timeout_client, possibly persisted in hive.
|
||||
_authApi = getIt<PaperlessAuthenticationApi>();
|
||||
// Store information required to make requests
|
||||
final currentAuth = AuthenticationInformation(
|
||||
serverUrl: serverUrl,
|
||||
@@ -82,13 +76,16 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
}
|
||||
if (storedAuth == null || !storedAuth.isValid) {
|
||||
return emit(
|
||||
AuthenticationState(isAuthenticated: false, wasLoginStored: false));
|
||||
AuthenticationState(isAuthenticated: false, wasLoginStored: false),
|
||||
);
|
||||
} else {
|
||||
if (appSettings.isLocalAuthenticationEnabled) {
|
||||
final localAuthSuccess = await _localAuthService
|
||||
.authenticateLocalUser("Authenticate to log back in");
|
||||
if (localAuthSuccess) {
|
||||
registerSecurityContext(storedAuth.clientCertificate);
|
||||
await registerSecurityContext(storedAuth.clientCertificate);
|
||||
//TODO: Workaround for new architecture, listen for security context changes in timeout_client, possibly persisted in hive.
|
||||
_authApi = getIt<PaperlessAuthenticationApi>();
|
||||
return emit(
|
||||
AuthenticationState(
|
||||
isAuthenticated: true,
|
||||
@@ -105,11 +102,13 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
||||
));
|
||||
}
|
||||
} else {
|
||||
return emit(AuthenticationState(
|
||||
await registerSecurityContext(storedAuth.clientCertificate);
|
||||
final authState = AuthenticationState(
|
||||
isAuthenticated: true,
|
||||
authentication: storedAuth,
|
||||
wasLoginStored: true,
|
||||
));
|
||||
);
|
||||
return emit(authState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:injectable/injectable.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/repository/saved_view_repository.dart';
|
||||
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_state.dart';
|
||||
@@ -12,22 +11,26 @@ class SavedViewCubit extends Cubit<SavedViewState> {
|
||||
|
||||
SavedViewCubit(this._repository) : super(SavedViewState(value: {})) {
|
||||
_subscription = _repository.savedViews.listen(
|
||||
(savedViews) => emit(state.copyWith(value: savedViews)),
|
||||
(savedViews) {
|
||||
if (savedViews == null) {
|
||||
emit(state.copyWith(isLoaded: false));
|
||||
} else {
|
||||
emit(state.copyWith(value: savedViews, isLoaded: true));
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
void selectView(SavedView? view) {
|
||||
emit(SavedViewState(value: state.value, selectedSavedViewId: view?.id));
|
||||
emit(state.copyWith(
|
||||
selectedSavedViewId: view?.id,
|
||||
overwriteSelectedSavedViewId: true,
|
||||
));
|
||||
}
|
||||
|
||||
Future<SavedView> add(SavedView view) async {
|
||||
final savedView = await _repository.create(view);
|
||||
emit(
|
||||
SavedViewState(
|
||||
value: {...state.value, savedView.id!: savedView},
|
||||
selectedSavedViewId: state.selectedSavedViewId,
|
||||
),
|
||||
);
|
||||
emit(state.copyWith(value: {...state.value, savedView.id!: savedView}));
|
||||
return savedView;
|
||||
}
|
||||
|
||||
@@ -42,11 +45,16 @@ class SavedViewCubit extends Cubit<SavedViewState> {
|
||||
Future<void> initialize() async {
|
||||
final views = await _repository.findAll();
|
||||
final values = {for (var element in views) element.id!: element};
|
||||
emit(SavedViewState(value: values));
|
||||
emit(SavedViewState(value: values, isLoaded: true));
|
||||
}
|
||||
|
||||
Future<void> reload() => initialize();
|
||||
|
||||
void resetSelection() {
|
||||
emit(SavedViewState(value: state.value));
|
||||
emit(SavedViewState(
|
||||
value: state.value,
|
||||
isLoaded: true,
|
||||
));
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -2,11 +2,13 @@ import 'package:equatable/equatable.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
|
||||
class SavedViewState with EquatableMixin {
|
||||
final bool isLoaded;
|
||||
final Map<int, SavedView> value;
|
||||
final int? selectedSavedViewId;
|
||||
|
||||
SavedViewState({
|
||||
required this.value,
|
||||
this.isLoaded = false,
|
||||
this.selectedSavedViewId,
|
||||
});
|
||||
|
||||
@@ -20,9 +22,11 @@ class SavedViewState with EquatableMixin {
|
||||
Map<int, SavedView>? value,
|
||||
int? selectedSavedViewId,
|
||||
bool overwriteSelectedSavedViewId = false,
|
||||
bool? isLoaded,
|
||||
}) {
|
||||
return SavedViewState(
|
||||
value: value ?? this.value,
|
||||
isLoaded: isLoaded ?? this.isLoaded,
|
||||
selectedSavedViewId: overwriteSelectedSavedViewId
|
||||
? selectedSavedViewId
|
||||
: this.selectedSavedViewId,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
@@ -8,6 +10,7 @@ import 'package:paperless_mobile/features/saved_view/cubit/saved_view_state.dart
|
||||
import 'package:paperless_mobile/features/saved_view/view/add_saved_view_page.dart';
|
||||
import 'package:paperless_mobile/generated/l10n.dart';
|
||||
import 'package:paperless_mobile/util.dart';
|
||||
import 'package:shimmer/shimmer.dart';
|
||||
|
||||
class SavedViewSelectionWidget extends StatelessWidget {
|
||||
final DocumentFilter currentFilter;
|
||||
@@ -29,6 +32,9 @@ class SavedViewSelectionWidget extends StatelessWidget {
|
||||
children: [
|
||||
BlocBuilder<SavedViewCubit, SavedViewState>(
|
||||
builder: (context, state) {
|
||||
if (!state.isLoaded) {
|
||||
return _buildLoadingWidget(context);
|
||||
}
|
||||
if (state.value.isEmpty) {
|
||||
return Text(S.of(context).savedViewsEmptyStateText);
|
||||
}
|
||||
@@ -58,32 +64,61 @@ class SavedViewSelectionWidget extends StatelessWidget {
|
||||
);
|
||||
},
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).savedViewsLabel,
|
||||
style: Theme.of(context).textTheme.titleSmall,
|
||||
),
|
||||
BlocBuilder<DocumentsCubit, DocumentsState>(
|
||||
buildWhen: (previous, current) =>
|
||||
previous.filter != current.filter,
|
||||
builder: (context, docState) {
|
||||
return TextButton.icon(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: enabled
|
||||
? () => _onCreatePressed(context, docState.filter)
|
||||
: null,
|
||||
label: Text(S.of(context).savedViewCreateNewLabel),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
BlocBuilder<SavedViewCubit, SavedViewState>(
|
||||
builder: (context, state) {
|
||||
return Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
S.of(context).savedViewsLabel,
|
||||
style: Theme.of(context).textTheme.titleSmall,
|
||||
),
|
||||
BlocBuilder<DocumentsCubit, DocumentsState>(
|
||||
buildWhen: (previous, current) =>
|
||||
previous.filter != current.filter,
|
||||
builder: (context, docState) {
|
||||
return TextButton.icon(
|
||||
icon: const Icon(Icons.add),
|
||||
onPressed: (enabled && state.isLoaded)
|
||||
? () => _onCreatePressed(context, docState.filter)
|
||||
: null,
|
||||
label: Text(S.of(context).savedViewCreateNewLabel),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildLoadingWidget(BuildContext context) {
|
||||
final r = Random(123456789);
|
||||
return SizedBox(
|
||||
height: height,
|
||||
width: double.infinity,
|
||||
child: Shimmer.fromColors(
|
||||
baseColor: Theme.of(context).brightness == Brightness.light
|
||||
? Colors.grey[300]!
|
||||
: Colors.grey[900]!,
|
||||
highlightColor: Theme.of(context).brightness == Brightness.light
|
||||
? Colors.grey[100]!
|
||||
: Colors.grey[600]!,
|
||||
child: ListView.separated(
|
||||
scrollDirection: Axis.horizontal,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: 10,
|
||||
itemBuilder: (context, index) => FilterChip(
|
||||
label: SizedBox(width: r.nextInt((index * 20) + 50).toDouble()),
|
||||
onSelected: null),
|
||||
separatorBuilder: (context, index) => SizedBox(width: 8.0),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _onCreatePressed(BuildContext context, DocumentFilter filter) async {
|
||||
final newView = await Navigator.of(context).push<SavedView?>(
|
||||
MaterialPageRoute(
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import 'dart:developer';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
@@ -34,6 +35,7 @@ import 'package:paperless_mobile/features/document_upload/cubit/document_upload_
|
||||
import 'package:paperless_mobile/features/document_upload/view/document_upload_preparation_page.dart';
|
||||
import 'package:paperless_mobile/features/home/view/home_page.dart';
|
||||
import 'package:paperless_mobile/features/login/bloc/authentication_cubit.dart';
|
||||
import 'package:paperless_mobile/features/login/services/authentication_service.dart';
|
||||
import 'package:paperless_mobile/features/login/view/login_page.dart';
|
||||
import 'package:paperless_mobile/features/settings/bloc/application_settings_cubit.dart';
|
||||
import 'package:paperless_mobile/features/settings/model/application_settings_state.dart';
|
||||
@@ -57,7 +59,13 @@ void main() async {
|
||||
// Load application settings and stored authentication data
|
||||
await getIt<ConnectivityCubit>().initialize();
|
||||
await getIt<ApplicationSettingsCubit>().initialize();
|
||||
await getIt<AuthenticationCubit>().initialize();
|
||||
|
||||
final authCubit = AuthenticationCubit(
|
||||
getIt<LocalVault>(),
|
||||
getIt<LocalAuthenticationService>(),
|
||||
getIt<PaperlessAuthenticationApi>(),
|
||||
);
|
||||
await authCubit.restoreSessionState();
|
||||
|
||||
// Create repositories
|
||||
final LabelRepository<Tag> tagRepository =
|
||||
@@ -80,13 +88,17 @@ void main() async {
|
||||
RepositoryProvider.value(value: storagePathRepository),
|
||||
RepositoryProvider.value(value: savedViewRepository),
|
||||
],
|
||||
child: const PaperlessMobileEntrypoint(),
|
||||
child: PaperlessMobileEntrypoint(authenticationCubit: authCubit),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
class PaperlessMobileEntrypoint extends StatefulWidget {
|
||||
const PaperlessMobileEntrypoint({Key? key}) : super(key: key);
|
||||
final AuthenticationCubit authenticationCubit;
|
||||
const PaperlessMobileEntrypoint({
|
||||
Key? key,
|
||||
required this.authenticationCubit,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<PaperlessMobileEntrypoint> createState() =>
|
||||
@@ -165,8 +177,8 @@ class _PaperlessMobileEntrypointState extends State<PaperlessMobileEntrypoint> {
|
||||
GlobalWidgetsLocalizations.delegate,
|
||||
FormBuilderLocalizations.delegate,
|
||||
],
|
||||
home: BlocProvider<AuthenticationCubit>.value(
|
||||
value: getIt<AuthenticationCubit>(),
|
||||
home: BlocProvider.value(
|
||||
value: widget.authenticationCubit,
|
||||
child: const AuthenticationWrapper(),
|
||||
),
|
||||
);
|
||||
@@ -291,10 +303,10 @@ class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
|
||||
if (authentication.isAuthenticated) {
|
||||
return const HomePage();
|
||||
} else {
|
||||
// if (authentication.wasLoginStored &&
|
||||
// !(authentication.wasLocalAuthenticationSuccessful ?? false)) {
|
||||
// return const BiometricAuthenticationPage();
|
||||
// }
|
||||
if (authentication.wasLoginStored &&
|
||||
!(authentication.wasLocalAuthenticationSuccessful ?? false)) {
|
||||
return const BiometricAuthenticationPage();
|
||||
}
|
||||
return const LoginPage();
|
||||
}
|
||||
},
|
||||
|
||||
@@ -261,7 +261,7 @@ class PaperlessLabelApiImpl implements PaperlessLabelsApi {
|
||||
@override
|
||||
Future<StoragePath?> getStoragePath(int id) {
|
||||
return getSingleResult(
|
||||
"/api/storage_paths/?page=1&page_size=100000",
|
||||
"/api/storage_paths/$id/",
|
||||
StoragePath.fromJson,
|
||||
ErrorCode.storagePathLoadFailed,
|
||||
client: client,
|
||||
|
||||
Reference in New Issue
Block a user