mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2026-01-31 08:25:00 -06:00
chore+fix+feat: Apply dart fixes after upgrade to flutter 3.10, add permission checks, make most api calls work again
This commit is contained in:
@@ -0,0 +1,5 @@
|
|||||||
|
class ServerMessageException implements Exception {
|
||||||
|
final String message;
|
||||||
|
|
||||||
|
ServerMessageException(this.message);
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/core/exception/server_message_exception.dart';
|
||||||
import 'package:paperless_mobile/core/type/types.dart';
|
import 'package:paperless_mobile/core/type/types.dart';
|
||||||
|
|
||||||
class DioHttpErrorInterceptor extends Interceptor {
|
class DioHttpErrorInterceptor extends Interceptor {
|
||||||
@@ -16,14 +17,15 @@ class DioHttpErrorInterceptor extends Interceptor {
|
|||||||
return _handlePlainError(data, handler, err);
|
return _handlePlainError(data, handler, err);
|
||||||
}
|
}
|
||||||
} else if (err.response?.statusCode == 403) {
|
} else if (err.response?.statusCode == 403) {
|
||||||
handler.reject(
|
var data = err.response!.data;
|
||||||
DioError(
|
if (data is Map && data.containsKey("detail")) {
|
||||||
|
handler.reject(DioError(
|
||||||
requestOptions: err.requestOptions,
|
requestOptions: err.requestOptions,
|
||||||
error: const PaperlessServerException(ErrorCode.notAuthorized),
|
error: ServerMessageException(data['detail']),
|
||||||
response: err.response,
|
response: err.response,
|
||||||
),
|
));
|
||||||
);
|
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
} else if (err.error is SocketException) {
|
} else if (err.error is SocketException) {
|
||||||
final ex = err.error as SocketException;
|
final ex = err.error as SocketException;
|
||||||
if (ex.osError?.errorCode == _OsErrorCodes.serverUnreachable.code) {
|
if (ex.osError?.errorCode == _OsErrorCodes.serverUnreachable.code) {
|
||||||
@@ -84,8 +86,7 @@ class DioHttpErrorInterceptor extends Interceptor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum _OsErrorCodes {
|
enum _OsErrorCodes {
|
||||||
serverUnreachable(101),
|
serverUnreachable(101);
|
||||||
hostNotFound(7);
|
|
||||||
|
|
||||||
const _OsErrorCodes(this.code);
|
const _OsErrorCodes(this.code);
|
||||||
final int code;
|
final int code;
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart';
|
||||||
@@ -12,13 +13,19 @@ import 'package:paperless_mobile/core/repository/user_repository.dart';
|
|||||||
import 'package:paperless_mobile/features/document_search/cubit/document_search_cubit.dart';
|
import 'package:paperless_mobile/features/document_search/cubit/document_search_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/document_search/view/document_search_page.dart';
|
import 'package:paperless_mobile/features/document_search/view/document_search_page.dart';
|
||||||
import 'package:paperless_mobile/features/home/view/model/api_version.dart';
|
import 'package:paperless_mobile/features/home/view/model/api_version.dart';
|
||||||
|
import 'package:paperless_mobile/features/linked_documents/cubit/linked_documents_cubit.dart';
|
||||||
|
import 'package:paperless_mobile/features/linked_documents/view/linked_documents_page.dart';
|
||||||
import 'package:paperless_mobile/features/notifications/services/local_notification_service.dart';
|
import 'package:paperless_mobile/features/notifications/services/local_notification_service.dart';
|
||||||
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
|
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
|
||||||
|
import 'package:paperless_mobile/features/saved_view/view/add_saved_view_page.dart';
|
||||||
import 'package:paperless_mobile/features/saved_view_details/cubit/saved_view_details_cubit.dart';
|
import 'package:paperless_mobile/features/saved_view_details/cubit/saved_view_details_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/saved_view_details/view/saved_view_details_page.dart';
|
import 'package:paperless_mobile/features/saved_view_details/view/saved_view_details_page.dart';
|
||||||
import 'package:paperless_mobile/routes/document_details_route.dart';
|
import 'package:paperless_mobile/routes/document_details_route.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
// These are convenience methods for nativating to views without having to pass providers around explicitly.
|
||||||
|
// Providers unfortunately have to be passed to the routes since they are children of the Navigator, not ancestors.
|
||||||
|
|
||||||
Future<void> pushDocumentSearchPage(BuildContext context) {
|
Future<void> pushDocumentSearchPage(BuildContext context) {
|
||||||
final currentUser =
|
final currentUser =
|
||||||
Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!.currentLoggedInUser;
|
Hive.box<GlobalSettings>(HiveBoxes.globalSettings).getValue()!.currentLoggedInUser;
|
||||||
@@ -64,6 +71,7 @@ Future<void> pushDocumentDetailsRoute(
|
|||||||
Provider.value(value: context.read<PaperlessDocumentsApi>()),
|
Provider.value(value: context.read<PaperlessDocumentsApi>()),
|
||||||
Provider.value(value: context.read<LocalNotificationService>()),
|
Provider.value(value: context.read<LocalNotificationService>()),
|
||||||
Provider.value(value: context.read<CacheManager>()),
|
Provider.value(value: context.read<CacheManager>()),
|
||||||
|
Provider.value(value: context.read<ConnectivityCubit>()),
|
||||||
if (context.read<ApiVersion>().hasMultiUserSupport)
|
if (context.read<ApiVersion>().hasMultiUserSupport)
|
||||||
Provider.value(value: context.read<UserRepository>()),
|
Provider.value(value: context.read<UserRepository>()),
|
||||||
],
|
],
|
||||||
@@ -76,19 +84,23 @@ Future<void> pushDocumentDetailsRoute(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> pushSavedViewDetailsRoute(BuildContext context, {required SavedView savedView}) {
|
Future<void> pushSavedViewDetailsRoute(
|
||||||
|
BuildContext context, {
|
||||||
|
required SavedView savedView,
|
||||||
|
}) {
|
||||||
|
final apiVersion = context.read<ApiVersion>();
|
||||||
return Navigator.of(context).push(
|
return Navigator.of(context).push(
|
||||||
MaterialPageRoute(
|
MaterialPageRoute(
|
||||||
builder: (_) => MultiProvider(
|
builder: (_) => MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
|
Provider.value(value: apiVersion),
|
||||||
|
if (apiVersion.hasMultiUserSupport) Provider.value(value: context.read<UserRepository>()),
|
||||||
Provider.value(value: context.read<LabelRepository>()),
|
Provider.value(value: context.read<LabelRepository>()),
|
||||||
Provider.value(value: context.read<DocumentChangedNotifier>()),
|
Provider.value(value: context.read<DocumentChangedNotifier>()),
|
||||||
Provider.value(value: context.read<PaperlessDocumentsApi>()),
|
Provider.value(value: context.read<PaperlessDocumentsApi>()),
|
||||||
Provider.value(value: context.read<CacheManager>()),
|
Provider.value(value: context.read<CacheManager>()),
|
||||||
|
Provider.value(value: context.read<ConnectivityCubit>()),
|
||||||
],
|
],
|
||||||
child: SavedViewDetailsPage(
|
|
||||||
onDelete: context.read<SavedViewCubit>().remove,
|
|
||||||
),
|
|
||||||
builder: (_, child) {
|
builder: (_, child) {
|
||||||
return BlocProvider(
|
return BlocProvider(
|
||||||
create: (context) => SavedViewDetailsCubit(
|
create: (context) => SavedViewDetailsCubit(
|
||||||
@@ -105,3 +117,47 @@ Future<void> pushSavedViewDetailsRoute(BuildContext context, {required SavedView
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<SavedView?> pushAddSavedViewRoute(BuildContext context, {required DocumentFilter filter}) {
|
||||||
|
return Navigator.of(context).push<SavedView?>(
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) => AddSavedViewPage(
|
||||||
|
currentFilter: filter,
|
||||||
|
correspondents: context.read<LabelRepository>().state.correspondents,
|
||||||
|
documentTypes: context.read<LabelRepository>().state.documentTypes,
|
||||||
|
storagePaths: context.read<LabelRepository>().state.storagePaths,
|
||||||
|
tags: context.read<LabelRepository>().state.tags,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> pushLinkedDocumentsView(BuildContext context, {required DocumentFilter filter}) {
|
||||||
|
return Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (_) => MultiProvider(
|
||||||
|
providers: [
|
||||||
|
Provider.value(value: context.read<ApiVersion>()),
|
||||||
|
Provider.value(value: context.read<LabelRepository>()),
|
||||||
|
Provider.value(value: context.read<DocumentChangedNotifier>()),
|
||||||
|
Provider.value(value: context.read<PaperlessDocumentsApi>()),
|
||||||
|
Provider.value(value: context.read<LocalNotificationService>()),
|
||||||
|
Provider.value(value: context.read<CacheManager>()),
|
||||||
|
Provider.value(value: context.read<ConnectivityCubit>()),
|
||||||
|
if (context.read<ApiVersion>().hasMultiUserSupport)
|
||||||
|
Provider.value(value: context.read<UserRepository>()),
|
||||||
|
],
|
||||||
|
builder: (context, _) => BlocProvider(
|
||||||
|
create: (context) => LinkedDocumentsCubit(
|
||||||
|
filter,
|
||||||
|
context.read(),
|
||||||
|
context.read(),
|
||||||
|
context.read(),
|
||||||
|
),
|
||||||
|
child: const LinkedDocumentsPage(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/repository/label_repository_state.dart';
|
import 'package:paperless_mobile/core/repository/label_repository_state.dart';
|
||||||
import 'package:paperless_mobile/core/repository/persistent_repository.dart';
|
import 'package:paperless_mobile/core/repository/persistent_repository.dart';
|
||||||
@@ -9,7 +8,9 @@ import 'package:paperless_mobile/core/repository/persistent_repository.dart';
|
|||||||
class LabelRepository extends PersistentRepository<LabelRepositoryState> {
|
class LabelRepository extends PersistentRepository<LabelRepositoryState> {
|
||||||
final PaperlessLabelsApi _api;
|
final PaperlessLabelsApi _api;
|
||||||
|
|
||||||
LabelRepository(this._api) : super(const LabelRepositoryState());
|
LabelRepository(this._api) : super(const LabelRepositoryState()) {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> initialize() {
|
Future<void> initialize() {
|
||||||
debugPrint("Initializing labels...");
|
debugPrint("Initializing labels...");
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import 'package:paperless_mobile/core/repository/saved_view_repository_state.dar
|
|||||||
class SavedViewRepository extends PersistentRepository<SavedViewRepositoryState> {
|
class SavedViewRepository extends PersistentRepository<SavedViewRepositoryState> {
|
||||||
final PaperlessSavedViewsApi _api;
|
final PaperlessSavedViewsApi _api;
|
||||||
|
|
||||||
SavedViewRepository(this._api) : super(const SavedViewRepositoryState());
|
SavedViewRepository(this._api) : super(const SavedViewRepositoryState()) {
|
||||||
|
initialize();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> initialize() {
|
Future<void> initialize() {
|
||||||
return findAll();
|
return findAll();
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:paperless_mobile/core/model/github_error_report.model.dart';
|
import 'package:paperless_mobile/core/model/github_error_report.model.dart';
|
||||||
|
|||||||
@@ -1,16 +1,8 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:dio/dio.dart';
|
import 'package:dio/dio.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:http/http.dart';
|
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
|
||||||
import 'package:paperless_mobile/core/bloc/document_status_cubit.dart';
|
|
||||||
import 'package:paperless_mobile/core/model/document_processing_status.dart';
|
|
||||||
import 'package:paperless_mobile/features/login/model/authentication_information.dart';
|
|
||||||
import 'package:paperless_mobile/constants.dart';
|
|
||||||
import 'package:paperless_mobile/core/database/tables/user_credentials.dart';
|
import 'package:paperless_mobile/core/database/tables/user_credentials.dart';
|
||||||
import 'package:web_socket_channel/io.dart';
|
// import 'package:web_socket_channel/io.dart';
|
||||||
|
|
||||||
abstract class StatusService {
|
abstract class StatusService {
|
||||||
Future<void> startListeningBeforeDocumentUpload(
|
Future<void> startListeningBeforeDocumentUpload(
|
||||||
@@ -19,7 +11,7 @@ abstract class StatusService {
|
|||||||
|
|
||||||
class WebSocketStatusService implements StatusService {
|
class WebSocketStatusService implements StatusService {
|
||||||
late WebSocket? socket;
|
late WebSocket? socket;
|
||||||
late IOWebSocketChannel? _channel;
|
// late IOWebSocketChannel? _channel;
|
||||||
|
|
||||||
WebSocketStatusService();
|
WebSocketStatusService();
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,5 @@ String translateError(BuildContext context, ErrorCode code) {
|
|||||||
return S.of(context)!.couldNotLoadSuggestions;
|
return S.of(context)!.couldNotLoadSuggestions;
|
||||||
case ErrorCode.acknowledgeTasksError:
|
case ErrorCode.acknowledgeTasksError:
|
||||||
return S.of(context)!.couldNotAcknowledgeTasks;
|
return S.of(context)!.couldNotAcknowledgeTasks;
|
||||||
case ErrorCode.notAuthorized:
|
|
||||||
return "You do not have the permission to perform this action."; //TODO: INTL
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import 'package:paperless_api/paperless_api.dart';
|
|
||||||
import 'package:rxdart/subjects.dart';
|
|
||||||
|
|
||||||
typedef JSON = Map<String, dynamic>;
|
typedef JSON = Map<String, dynamic>;
|
||||||
typedef PaperlessValidationErrors = Map<String, String>;
|
typedef PaperlessValidationErrors = Map<String, String>;
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:flutter/src/widgets/placeholder.dart';
|
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
class DialogCancelButton extends StatelessWidget {
|
class DialogCancelButton extends StatelessWidget {
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:flutter/src/widgets/placeholder.dart';
|
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
enum DialogConfirmButtonStyle {
|
enum DialogConfirmButtonStyle {
|
||||||
|
|||||||
@@ -181,8 +181,7 @@ class FormBuilderColorPickerField extends FormBuilderField<Color> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
FormBuilderColorPickerFieldState createState() =>
|
FormBuilderColorPickerFieldState createState() => FormBuilderColorPickerFieldState();
|
||||||
FormBuilderColorPickerFieldState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class FormBuilderColorPickerFieldState
|
class FormBuilderColorPickerFieldState
|
||||||
@@ -217,8 +216,6 @@ class FormBuilderColorPickerFieldState
|
|||||||
final selected = await showDialog<bool>(
|
final selected = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
final materialLocalizations = S.of(context)!;
|
|
||||||
|
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
// title: null, //const Text('Pick a color!'),
|
// title: null, //const Text('Pick a color!'),
|
||||||
content: _buildColorPicker(),
|
content: _buildColorPicker(),
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -27,8 +27,7 @@ import 'package:flutter/services.dart';
|
|||||||
|
|
||||||
typedef ChipsInputSuggestions<T> = Future<List<T>> Function(String query);
|
typedef ChipsInputSuggestions<T> = Future<List<T>> Function(String query);
|
||||||
typedef ChipSelected<T> = void Function(T data, bool selected);
|
typedef ChipSelected<T> = void Function(T data, bool selected);
|
||||||
typedef ChipsBuilder<T> = Widget Function(
|
typedef ChipsBuilder<T> = Widget Function(BuildContext context, ChipsInputState<T> state, T data);
|
||||||
BuildContext context, ChipsInputState<T> state, T data);
|
|
||||||
|
|
||||||
class ChipsInput<T> extends StatefulWidget {
|
class ChipsInput<T> extends StatefulWidget {
|
||||||
const ChipsInput({
|
const ChipsInput({
|
||||||
@@ -71,8 +70,7 @@ class ChipsInputState<T> extends State<ChipsInput<T>> {
|
|||||||
|
|
||||||
TextEditingValue get currentTextEditingValue => _value;
|
TextEditingValue get currentTextEditingValue => _value;
|
||||||
|
|
||||||
bool get _hasInputConnection =>
|
bool get _hasInputConnection => _connection != null && (_connection?.attached ?? false);
|
||||||
_connection != null && (_connection?.attached ?? false);
|
|
||||||
|
|
||||||
void requestKeyboard() {
|
void requestKeyboard() {
|
||||||
if (_focusNode.hasFocus) {
|
if (_focusNode.hasFocus) {
|
||||||
@@ -191,8 +189,7 @@ class ChipsInputState<T> extends State<ChipsInput<T>> {
|
|||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
itemCount: _suggestions.length,
|
itemCount: _suggestions.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
return widget.suggestionBuilder(
|
return widget.suggestionBuilder(context, this, _suggestions[index]);
|
||||||
context, this, _suggestions[index]);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -213,14 +210,11 @@ class ChipsInputState<T> extends State<ChipsInput<T>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int _countReplacements(TextEditingValue value) {
|
int _countReplacements(TextEditingValue value) {
|
||||||
return value.text.codeUnits
|
return value.text.codeUnits.where((ch) => ch == kObjectReplacementChar).length;
|
||||||
.where((ch) => ch == kObjectReplacementChar)
|
|
||||||
.length;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _updateTextInputState() {
|
void _updateTextInputState() {
|
||||||
final text =
|
final text = String.fromCharCodes(_chips.map((_) => kObjectReplacementChar));
|
||||||
String.fromCharCodes(_chips.map((_) => kObjectReplacementChar));
|
|
||||||
_value = TextEditingValue(
|
_value = TextEditingValue(
|
||||||
text: text,
|
text: text,
|
||||||
selection: TextSelection.collapsed(offset: text.length),
|
selection: TextSelection.collapsed(offset: text.length),
|
||||||
@@ -233,35 +227,30 @@ class ChipsInputState<T> extends State<ChipsInput<T>> {
|
|||||||
final localId = ++_searchId;
|
final localId = ++_searchId;
|
||||||
final results = await widget.findSuggestions(value);
|
final results = await widget.findSuggestions(value);
|
||||||
if (_searchId == localId && mounted) {
|
if (_searchId == localId && mounted) {
|
||||||
setState(() => _suggestions = results
|
setState(() => _suggestions =
|
||||||
.where((profile) => !_chips.contains(profile))
|
results.where((profile) => !_chips.contains(profile)).toList(growable: false));
|
||||||
.toList(growable: false));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TextCaret extends StatefulWidget {
|
class _TextCaret extends StatefulWidget {
|
||||||
const _TextCaret({
|
const _TextCaret({
|
||||||
this.duration = const Duration(milliseconds: 500),
|
|
||||||
this.resumed = false,
|
this.resumed = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Duration duration;
|
|
||||||
final bool resumed;
|
final bool resumed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
_TextCursorState createState() => _TextCursorState();
|
_TextCursorState createState() => _TextCursorState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _TextCursorState extends State<_TextCaret>
|
class _TextCursorState extends State<_TextCaret> with SingleTickerProviderStateMixin {
|
||||||
with SingleTickerProviderStateMixin {
|
|
||||||
bool _displayed = false;
|
bool _displayed = false;
|
||||||
late Timer _timer;
|
late Timer _timer;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_timer = Timer.periodic(widget.duration, _onTimer);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onTimer(Timer timer) {
|
void _onTimer(Timer timer) {
|
||||||
|
|||||||
@@ -251,7 +251,6 @@ abstract class SearchDelegate<T> {
|
|||||||
///
|
///
|
||||||
/// Setting the query string programmatically moves the cursor to the end of the text field.
|
/// Setting the query string programmatically moves the cursor to the end of the text field.
|
||||||
set query(String value) {
|
set query(String value) {
|
||||||
assert(query != null);
|
|
||||||
_queryTextController.text = value;
|
_queryTextController.text = value;
|
||||||
if (_queryTextController.text.isNotEmpty) {
|
if (_queryTextController.text.isNotEmpty) {
|
||||||
_queryTextController.selection = TextSelection.fromPosition(
|
_queryTextController.selection = TextSelection.fromPosition(
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import 'dart:ui';
|
|||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
|
||||||
|
|
||||||
const int _kOpenViewMilliseconds = 600;
|
const int _kOpenViewMilliseconds = 600;
|
||||||
const Duration _kOpenViewDuration =
|
const Duration _kOpenViewDuration =
|
||||||
@@ -1649,7 +1648,6 @@ class SearchBarTheme extends InheritedWidget {
|
|||||||
final SearchBarTheme? searchBarTheme =
|
final SearchBarTheme? searchBarTheme =
|
||||||
context.dependOnInheritedWidgetOfExactType<SearchBarTheme>();
|
context.dependOnInheritedWidgetOfExactType<SearchBarTheme>();
|
||||||
return searchBarTheme?.data ?? const SearchBarThemeData();
|
return searchBarTheme?.data ?? const SearchBarThemeData();
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
import 'package:paperless_mobile/constants.dart';
|
import 'package:paperless_mobile/constants.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/paperless_logo.dart';
|
import 'package:paperless_mobile/core/widgets/paperless_logo.dart';
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class _ApplicationIntroSlideshowState extends State<ApplicationIntroSlideshow> {
|
|||||||
image: AssetImages.organizeDocuments.image,
|
image: AssetImages.organizeDocuments.image,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
bodyWidget: Column(
|
bodyWidget: const Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
@@ -70,7 +70,7 @@ class _ApplicationIntroSlideshowState extends State<ApplicationIntroSlideshow> {
|
|||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Image(image: AssetImages.secureDocuments.image),
|
child: Image(image: AssetImages.secureDocuments.image),
|
||||||
),
|
),
|
||||||
bodyWidget: Column(
|
bodyWidget: const Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
@@ -90,8 +90,8 @@ class _ApplicationIntroSlideshowState extends State<ApplicationIntroSlideshow> {
|
|||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
child: Image(image: AssetImages.success.image),
|
child: Image(image: AssetImages.success.image),
|
||||||
),
|
),
|
||||||
bodyWidget: Column(
|
bodyWidget: const Column(
|
||||||
children: const [
|
children: [
|
||||||
BiometricAuthenticationSetting(),
|
BiometricAuthenticationSetting(),
|
||||||
LanguageSelectionSetting(),
|
LanguageSelectionSetting(),
|
||||||
ThemeModeSetting(),
|
ThemeModeSetting(),
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import 'dart:async';
|
|||||||
|
|
||||||
import 'package:bloc/bloc.dart';
|
import 'package:bloc/bloc.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:equatable/equatable.dart';
|
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ class BulkEditLabelBottomSheet<T extends Label> extends StatefulWidget {
|
|||||||
final LabelOptionsSelector<T> availableOptionsSelector;
|
final LabelOptionsSelector<T> availableOptionsSelector;
|
||||||
final void Function(int? selectedId) onSubmit;
|
final void Function(int? selectedId) onSubmit;
|
||||||
final int? initialValue;
|
final int? initialValue;
|
||||||
|
final bool canCreateNewLabel;
|
||||||
|
|
||||||
const BulkEditLabelBottomSheet({
|
const BulkEditLabelBottomSheet({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -26,6 +27,7 @@ class BulkEditLabelBottomSheet<T extends Label> extends StatefulWidget {
|
|||||||
required this.availableOptionsSelector,
|
required this.availableOptionsSelector,
|
||||||
required this.onSubmit,
|
required this.onSubmit,
|
||||||
this.initialValue,
|
this.initialValue,
|
||||||
|
required this.canCreateNewLabel,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -58,6 +60,7 @@ class _BulkEditLabelBottomSheetState<T extends Label> extends State<BulkEditLabe
|
|||||||
initialValue: widget.initialValue != null
|
initialValue: widget.initialValue != null
|
||||||
? IdQueryParameter.fromId(widget.initialValue!)
|
? IdQueryParameter.fromId(widget.initialValue!)
|
||||||
: const IdQueryParameter.unset(),
|
: const IdQueryParameter.unset(),
|
||||||
|
canCreateNewLabel: widget.canCreateNewLabel,
|
||||||
name: "labelFormField",
|
name: "labelFormField",
|
||||||
options: widget.availableOptionsSelector(state),
|
options: widget.availableOptionsSelector(state),
|
||||||
labelText: widget.formFieldLabel,
|
labelText: widget.formFieldLabel,
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:flutter/src/widgets/placeholder.dart';
|
|
||||||
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_cancel_button.dart';
|
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_cancel_button.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_confirm_button.dart';
|
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_confirm_button.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|||||||
+2
-2
@@ -26,8 +26,8 @@ class _FullscreenBulkEditTagsWidgetState
|
|||||||
/// Tags not assigned to at least one document in the selection
|
/// Tags not assigned to at least one document in the selection
|
||||||
late final List<int> _nonSharedTags;
|
late final List<int> _nonSharedTags;
|
||||||
|
|
||||||
List<int> _addTags = [];
|
final List<int> _addTags = [];
|
||||||
List<int> _removeTags = [];
|
final List<int> _removeTags = [];
|
||||||
late List<int> _filteredTags;
|
late List<int> _filteredTags;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ class _SelectFileTypeDialogState extends State<SelectFileTypeDialog> {
|
|||||||
},
|
},
|
||||||
title: Text(S.of(context)!.archivedPdf),
|
title: Text(S.of(context)!.archivedPdf),
|
||||||
),
|
),
|
||||||
Divider(),
|
const Divider(),
|
||||||
CheckboxListTile(
|
CheckboxListTile(
|
||||||
controlAffinity: ListTileControlAffinity.leading,
|
controlAffinity: ListTileControlAffinity.leading,
|
||||||
value: _rememberSelection,
|
value: _rememberSelection,
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:hive_flutter/adapters.dart';
|
|
||||||
import 'package:open_filex/open_filex.dart';
|
import 'package:open_filex/open_filex.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/repository/user_repository.dart';
|
|
||||||
import 'package:paperless_mobile/core/translation/error_code_localization_mapper.dart';
|
import 'package:paperless_mobile/core/translation/error_code_localization_mapper.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/material/colored_tab_bar.dart';
|
import 'package:paperless_mobile/core/widgets/material/colored_tab_bar.dart';
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
@@ -57,7 +53,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final apiVersion = context.watch<ApiVersion>();
|
final apiVersion = context.watch<ApiVersion>();
|
||||||
|
|
||||||
final tabLength = 4 + (apiVersion.supportsPermissions ? 1 : 0);
|
final tabLength = 4 + (apiVersion.hasMultiUserSupport ? 1 : 0);
|
||||||
return WillPopScope(
|
return WillPopScope(
|
||||||
onWillPop: () async {
|
onWillPop: () async {
|
||||||
Navigator.of(context).pop(context.read<DocumentDetailsCubit>().state.document);
|
Navigator.of(context).pop(context.read<DocumentDetailsCubit>().state.document);
|
||||||
@@ -155,7 +151,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (apiVersion.supportsPermissions)
|
if (apiVersion.hasMultiUserSupport)
|
||||||
Tab(
|
Tab(
|
||||||
child: Text(
|
child: Text(
|
||||||
"Permissions",
|
"Permissions",
|
||||||
@@ -260,13 +256,9 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildEditButton() {
|
Widget _buildEditButton() {
|
||||||
bool canEdit = context.watchInternetConnection;
|
bool canEdit = context.watchInternetConnection &&
|
||||||
final apiVersion = context.watch<ApiVersion>();
|
LocalUserAccount.current.paperlessUser
|
||||||
|
.hasPermission(PermissionAction.change, PermissionTarget.document);
|
||||||
if (apiVersion.supportsPermissions) {
|
|
||||||
canEdit =
|
|
||||||
LocalUserAccount.current.paperlessUser.hasPermission(UserPermissions.changeDocument);
|
|
||||||
}
|
|
||||||
if (!canEdit) {
|
if (!canEdit) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
}
|
}
|
||||||
@@ -281,7 +273,7 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
verticalOffset: 40,
|
verticalOffset: 40,
|
||||||
child: FloatingActionButton(
|
child: FloatingActionButton(
|
||||||
child: const Icon(Icons.edit),
|
child: const Icon(Icons.edit),
|
||||||
onPressed: canEdit ? () => _onEdit(state.document) : null,
|
onPressed: () => _onEdit(state.document),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -296,15 +288,16 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
|||||||
builder: (context, connectivityState) {
|
builder: (context, connectivityState) {
|
||||||
final isConnected = connectivityState.isConnected;
|
final isConnected = connectivityState.isConnected;
|
||||||
|
|
||||||
final canDelete = LocalUserAccount.current.paperlessUser
|
final canDelete = isConnected &&
|
||||||
.hasPermission(UserPermissions.deleteDocument);
|
LocalUserAccount.current.paperlessUser
|
||||||
|
.hasPermission(PermissionAction.delete, PermissionTarget.document);
|
||||||
return Row(
|
return Row(
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
IconButton(
|
IconButton(
|
||||||
tooltip: S.of(context)!.deleteDocumentTooltip,
|
tooltip: S.of(context)!.deleteDocumentTooltip,
|
||||||
icon: const Icon(Icons.delete),
|
icon: const Icon(Icons.delete),
|
||||||
onPressed: (isConnected && canDelete) ? () => _onDelete(state.document) : null,
|
onPressed: canDelete ? () => _onDelete(state.document) : null,
|
||||||
).paddedSymmetrically(horizontal: 4),
|
).paddedSymmetrically(horizontal: 4),
|
||||||
DocumentDownloadButton(
|
DocumentDownloadButton(
|
||||||
document: state.document,
|
document: state.document,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:flutter/services.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/type/types.dart';
|
import 'package:paperless_mobile/core/type/types.dart';
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/features/document_details/cubit/document_details_cubit.dart';
|
import 'package:paperless_mobile/features/document_details/cubit/document_details_cubit.dart';
|
||||||
@@ -17,8 +18,7 @@ class ArchiveSerialNumberField extends StatefulWidget {
|
|||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<ArchiveSerialNumberField> createState() =>
|
State<ArchiveSerialNumberField> createState() => _ArchiveSerialNumberFieldState();
|
||||||
_ArchiveSerialNumberFieldState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _ArchiveSerialNumberFieldState extends State<ArchiveSerialNumberField> {
|
class _ArchiveSerialNumberFieldState extends State<ArchiveSerialNumberField> {
|
||||||
@@ -39,20 +39,21 @@ class _ArchiveSerialNumberFieldState extends State<ArchiveSerialNumberField> {
|
|||||||
void _clearButtonListener() {
|
void _clearButtonListener() {
|
||||||
setState(() {
|
setState(() {
|
||||||
_showClearButton = _asnEditingController.text.isNotEmpty;
|
_showClearButton = _asnEditingController.text.isNotEmpty;
|
||||||
_canUpdate = int.tryParse(_asnEditingController.text) !=
|
_canUpdate = int.tryParse(_asnEditingController.text) != widget.document.archiveSerialNumber;
|
||||||
widget.document.archiveSerialNumber;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final userCanEditDocument = LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.change,
|
||||||
|
PermissionTarget.document,
|
||||||
|
);
|
||||||
return BlocListener<DocumentDetailsCubit, DocumentDetailsState>(
|
return BlocListener<DocumentDetailsCubit, DocumentDetailsState>(
|
||||||
listenWhen: (previous, current) =>
|
listenWhen: (previous, current) =>
|
||||||
previous.document.archiveSerialNumber !=
|
previous.document.archiveSerialNumber != current.document.archiveSerialNumber,
|
||||||
current.document.archiveSerialNumber,
|
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
_asnEditingController.text =
|
_asnEditingController.text = state.document.archiveSerialNumber?.toString() ?? '';
|
||||||
state.document.archiveSerialNumber?.toString() ?? '';
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_canUpdate = false;
|
_canUpdate = false;
|
||||||
});
|
});
|
||||||
@@ -61,6 +62,7 @@ class _ArchiveSerialNumberFieldState extends State<ArchiveSerialNumberField> {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
TextFormField(
|
TextFormField(
|
||||||
|
enabled: userCanEditDocument,
|
||||||
controller: _asnEditingController,
|
controller: _asnEditingController,
|
||||||
keyboardType: TextInputType.number,
|
keyboardType: TextInputType.number,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
@@ -78,15 +80,13 @@ class _ArchiveSerialNumberFieldState extends State<ArchiveSerialNumberField> {
|
|||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.clear),
|
icon: const Icon(Icons.clear),
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
onPressed: _asnEditingController.clear,
|
onPressed: userCanEditDocument ? _asnEditingController.clear : null,
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.plus_one_rounded),
|
icon: const Icon(Icons.plus_one_rounded),
|
||||||
color: Theme.of(context).colorScheme.primary,
|
color: Theme.of(context).colorScheme.primary,
|
||||||
onPressed:
|
onPressed:
|
||||||
context.watchInternetConnection && !_showClearButton
|
context.watchInternetConnection && !_showClearButton ? _onAutoAssign : null,
|
||||||
? _onAutoAssign
|
|
||||||
: null,
|
|
||||||
).paddedOnly(right: 8),
|
).paddedOnly(right: 8),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -97,9 +97,7 @@ class _ArchiveSerialNumberFieldState extends State<ArchiveSerialNumberField> {
|
|||||||
),
|
),
|
||||||
TextButton.icon(
|
TextButton.icon(
|
||||||
icon: const Icon(Icons.done),
|
icon: const Icon(Icons.done),
|
||||||
onPressed: context.watchInternetConnection && _canUpdate
|
onPressed: context.watchInternetConnection && _canUpdate ? _onSubmitted : null,
|
||||||
? _onSubmitted
|
|
||||||
: null,
|
|
||||||
label: Text(S.of(context)!.save),
|
label: Text(S.of(context)!.save),
|
||||||
).padded(),
|
).padded(),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class DetailsItem extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
DetailsItem.text(
|
DetailsItem.text(
|
||||||
String text, {
|
String text, {super.key,
|
||||||
required this.label,
|
required this.label,
|
||||||
required BuildContext context,
|
required BuildContext context,
|
||||||
}) : content = Text(
|
}) : content = Text(
|
||||||
|
|||||||
@@ -29,8 +29,8 @@ class _DocumentMetaDataWidgetState extends State<DocumentMetaDataWidget> {
|
|||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
debugPrint("Building state...");
|
debugPrint("Building state...");
|
||||||
if (state.metaData == null) {
|
if (state.metaData == null) {
|
||||||
return SliverToBoxAdapter(
|
return const SliverToBoxAdapter(
|
||||||
child: const Center(
|
child: Center(
|
||||||
child: CircularProgressIndicator(),
|
child: CircularProgressIndicator(),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import 'package:paperless_api/paperless_api.dart';
|
|||||||
import 'package:paperless_mobile/core/widgets/highlighted_text.dart';
|
import 'package:paperless_mobile/core/widgets/highlighted_text.dart';
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/features/document_details/view/widgets/details_item.dart';
|
import 'package:paperless_mobile/features/document_details/view/widgets/details_item.dart';
|
||||||
import 'package:paperless_mobile/features/labels/storage_path/view/widgets/storage_path_widget.dart';
|
|
||||||
import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_widget.dart';
|
import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_widget.dart';
|
||||||
import 'package:paperless_mobile/features/labels/view/widgets/label_text.dart';
|
import 'package:paperless_mobile/features/labels/view/widgets/label_text.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
@@ -8,6 +7,7 @@ import 'package:flutter_typeahead/flutter_typeahead.dart';
|
|||||||
|
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||||
import 'package:paperless_mobile/core/workarounds/colored_chip.dart';
|
import 'package:paperless_mobile/core/workarounds/colored_chip.dart';
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
@@ -16,7 +16,6 @@ import 'package:paperless_mobile/features/edit_label/view/impl/add_correspondent
|
|||||||
import 'package:paperless_mobile/features/edit_label/view/impl/add_document_type_page.dart';
|
import 'package:paperless_mobile/features/edit_label/view/impl/add_document_type_page.dart';
|
||||||
import 'package:paperless_mobile/features/edit_label/view/impl/add_storage_path_page.dart';
|
import 'package:paperless_mobile/features/edit_label/view/impl/add_storage_path_page.dart';
|
||||||
import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart';
|
import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart';
|
||||||
import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart';
|
|
||||||
import 'package:paperless_mobile/features/labels/view/widgets/label_form_field.dart';
|
import 'package:paperless_mobile/features/labels/view/widgets/label_form_field.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
@@ -117,6 +116,11 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
|||||||
name: fkCorrespondent,
|
name: fkCorrespondent,
|
||||||
prefixIcon: const Icon(Icons.person_outlined),
|
prefixIcon: const Icon(Icons.person_outlined),
|
||||||
allowSelectUnassigned: true,
|
allowSelectUnassigned: true,
|
||||||
|
canCreateNewLabel:
|
||||||
|
LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add,
|
||||||
|
PermissionTarget.correspondent,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
if (_filteredSuggestions?.hasSuggestedCorrespondents ?? false)
|
if (_filteredSuggestions?.hasSuggestedCorrespondents ?? false)
|
||||||
_buildSuggestionsSkeleton<int>(
|
_buildSuggestionsSkeleton<int>(
|
||||||
@@ -144,6 +148,11 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
|||||||
initialName: currentInput,
|
initialName: currentInput,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
canCreateNewLabel:
|
||||||
|
LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add,
|
||||||
|
PermissionTarget.documentType,
|
||||||
|
),
|
||||||
addLabelText: S.of(context)!.addDocumentType,
|
addLabelText: S.of(context)!.addDocumentType,
|
||||||
labelText: S.of(context)!.documentType,
|
labelText: S.of(context)!.documentType,
|
||||||
initialValue: state.document.documentType != null
|
initialValue: state.document.documentType != null
|
||||||
@@ -177,6 +186,11 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
|||||||
value: context.read<LabelRepository>(),
|
value: context.read<LabelRepository>(),
|
||||||
child: AddStoragePathPage(initalName: initialValue),
|
child: AddStoragePathPage(initalName: initialValue),
|
||||||
),
|
),
|
||||||
|
canCreateNewLabel:
|
||||||
|
LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add,
|
||||||
|
PermissionTarget.storagePath,
|
||||||
|
),
|
||||||
addLabelText: S.of(context)!.addStoragePath,
|
addLabelText: S.of(context)!.addStoragePath,
|
||||||
labelText: S.of(context)!.storagePath,
|
labelText: S.of(context)!.storagePath,
|
||||||
options: state.storagePaths,
|
options: state.storagePaths,
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ class _ScannedImageItemState extends State<ScannedImageItem> {
|
|||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
child: TextButton(
|
child: TextButton(
|
||||||
onPressed: widget.onDelete,
|
onPressed: widget.onDelete,
|
||||||
child: Text("Remove"),
|
child: const Text("Remove"),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -3,15 +3,7 @@ import 'dart:async';
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
|
||||||
import 'package:hive/hive.dart';
|
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
|
||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart';
|
|
||||||
import 'package:paperless_mobile/core/navigation/push_routes.dart';
|
import 'package:paperless_mobile/core/navigation/push_routes.dart';
|
||||||
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/features/document_search/cubit/document_search_cubit.dart';
|
import 'package:paperless_mobile/features/document_search/cubit/document_search_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/document_search/view/remove_history_entry_dialog.dart';
|
import 'package:paperless_mobile/features/document_search/view/remove_history_entry_dialog.dart';
|
||||||
@@ -19,10 +11,8 @@ import 'package:paperless_mobile/features/documents/view/widgets/adaptive_docume
|
|||||||
import 'package:paperless_mobile/features/documents/view/widgets/selection/view_type_selection_widget.dart';
|
import 'package:paperless_mobile/features/documents/view/widgets/selection/view_type_selection_widget.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:paperless_mobile/routes/document_details_route.dart';
|
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
import 'package:provider/provider.dart';
|
|
||||||
|
|
||||||
class DocumentSearchPage extends StatefulWidget {
|
class DocumentSearchPage extends StatefulWidget {
|
||||||
const DocumentSearchPage({super.key});
|
const DocumentSearchPage({super.key});
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:hive_flutter/adapters.dart';
|
import 'package:hive_flutter/adapters.dart';
|
||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
|
|||||||
@@ -35,6 +35,7 @@ class DocumentUploadCubit extends Cubit<DocumentUploadState> {
|
|||||||
int? correspondent,
|
int? correspondent,
|
||||||
Iterable<int> tags = const [],
|
Iterable<int> tags = const [],
|
||||||
DateTime? createdAt,
|
DateTime? createdAt,
|
||||||
|
int? asn,
|
||||||
}) async {
|
}) async {
|
||||||
return await _documentApi.create(
|
return await _documentApi.create(
|
||||||
bytes,
|
bytes,
|
||||||
@@ -44,6 +45,7 @@ class DocumentUploadCubit extends Cubit<DocumentUploadState> {
|
|||||||
documentType: documentType,
|
documentType: documentType,
|
||||||
tags: tags,
|
tags: tags,
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
|
asn: asn,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:flutter_form_builder/flutter_form_builder.dart';
|
|||||||
import 'package:intl/date_symbol_data_local.dart';
|
import 'package:intl/date_symbol_data_local.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||||
import 'package:paperless_mobile/core/type/types.dart';
|
import 'package:paperless_mobile/core/type/types.dart';
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
@@ -32,7 +33,6 @@ class DocumentUploadPreparationPage extends StatefulWidget {
|
|||||||
final String? filename;
|
final String? filename;
|
||||||
final String? fileExtension;
|
final String? fileExtension;
|
||||||
|
|
||||||
|
|
||||||
const DocumentUploadPreparationPage({
|
const DocumentUploadPreparationPage({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.fileBytes,
|
required this.fileBytes,
|
||||||
@@ -193,6 +193,10 @@ class _DocumentUploadPreparationPageState extends State<DocumentUploadPreparatio
|
|||||||
options: state.correspondents,
|
options: state.correspondents,
|
||||||
prefixIcon: const Icon(Icons.person_outline),
|
prefixIcon: const Icon(Icons.person_outline),
|
||||||
allowSelectUnassigned: true,
|
allowSelectUnassigned: true,
|
||||||
|
canCreateNewLabel: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add,
|
||||||
|
PermissionTarget.correspondent,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
// Document type
|
// Document type
|
||||||
LabelFormField<DocumentType>(
|
LabelFormField<DocumentType>(
|
||||||
@@ -208,6 +212,10 @@ class _DocumentUploadPreparationPageState extends State<DocumentUploadPreparatio
|
|||||||
options: state.documentTypes,
|
options: state.documentTypes,
|
||||||
prefixIcon: const Icon(Icons.description_outlined),
|
prefixIcon: const Icon(Icons.description_outlined),
|
||||||
allowSelectUnassigned: true,
|
allowSelectUnassigned: true,
|
||||||
|
canCreateNewLabel: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add,
|
||||||
|
PermissionTarget.documentType,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
TagsFormField(
|
TagsFormField(
|
||||||
name: DocumentModel.tagsKey,
|
name: DocumentModel.tagsKey,
|
||||||
@@ -239,10 +247,14 @@ class _DocumentUploadPreparationPageState extends State<DocumentUploadPreparatio
|
|||||||
|
|
||||||
final createdAt = fv[DocumentModel.createdKey] as DateTime?;
|
final createdAt = fv[DocumentModel.createdKey] as DateTime?;
|
||||||
final title = fv[DocumentModel.titleKey] as String;
|
final title = fv[DocumentModel.titleKey] as String;
|
||||||
final docType = fv[DocumentModel.documentTypeKey] as SetIdQueryParameter;
|
final docType = (fv[DocumentModel.documentTypeKey] as IdQueryParameter?)
|
||||||
final tags = fv[DocumentModel.tagsKey] as IdsTagsQuery;
|
?.whenOrNull(fromId: (id) => id);
|
||||||
final correspondent = fv[DocumentModel.correspondentKey] as SetIdQueryParameter;
|
final tags = (fv[DocumentModel.tagsKey] as TagsQuery?)
|
||||||
|
?.whenOrNull(ids: (include, exclude) => include) ??
|
||||||
|
[];
|
||||||
|
final correspondent = (fv[DocumentModel.correspondentKey] as IdQueryParameter?)
|
||||||
|
?.whenOrNull(fromId: (id) => id);
|
||||||
|
final asn = fv[DocumentModel.asnKey] as int?;
|
||||||
final taskId = await cubit.upload(
|
final taskId = await cubit.upload(
|
||||||
widget.fileBytes,
|
widget.fileBytes,
|
||||||
filename: _padWithExtension(
|
filename: _padWithExtension(
|
||||||
@@ -250,10 +262,11 @@ class _DocumentUploadPreparationPageState extends State<DocumentUploadPreparatio
|
|||||||
widget.fileExtension,
|
widget.fileExtension,
|
||||||
),
|
),
|
||||||
title: title,
|
title: title,
|
||||||
documentType: docType.id,
|
documentType: docType,
|
||||||
correspondent: correspondent.id,
|
correspondent: correspondent,
|
||||||
tags: tags.include,
|
tags: tags,
|
||||||
createdAt: createdAt,
|
createdAt: createdAt,
|
||||||
|
asn: asn,
|
||||||
);
|
);
|
||||||
showSnackBar(
|
showSnackBar(
|
||||||
context,
|
context,
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class DocumentView extends StatefulWidget {
|
class DocumentView extends StatefulWidget {
|
||||||
final Future<Uint8List> documentBytes;
|
final Future<Uint8List> documentBytes;
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import 'package:paperless_api/paperless_api.dart';
|
|||||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||||
import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_header_delegate.dart';
|
import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_header_delegate.dart';
|
||||||
import 'package:paperless_mobile/core/navigation/push_routes.dart';
|
import 'package:paperless_mobile/core/navigation/push_routes.dart';
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
|
||||||
import 'package:paperless_mobile/core/widgets/material/colored_tab_bar.dart';
|
import 'package:paperless_mobile/core/widgets/material/colored_tab_bar.dart';
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
|
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
|
||||||
@@ -19,12 +18,10 @@ import 'package:paperless_mobile/features/documents/view/widgets/selection/docum
|
|||||||
import 'package:paperless_mobile/features/documents/view/widgets/selection/view_type_selection_widget.dart';
|
import 'package:paperless_mobile/features/documents/view/widgets/selection/view_type_selection_widget.dart';
|
||||||
import 'package:paperless_mobile/features/documents/view/widgets/sort_documents_button.dart';
|
import 'package:paperless_mobile/features/documents/view/widgets/sort_documents_button.dart';
|
||||||
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
|
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/saved_view/view/add_saved_view_page.dart';
|
|
||||||
import 'package:paperless_mobile/features/saved_view/view/saved_view_list.dart';
|
import 'package:paperless_mobile/features/saved_view/view/saved_view_list.dart';
|
||||||
import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart';
|
import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
||||||
import 'package:paperless_mobile/routes/document_details_route.dart';
|
|
||||||
|
|
||||||
class DocumentFilterIntent {
|
class DocumentFilterIntent {
|
||||||
final DocumentFilter? filter;
|
final DocumentFilter? filter;
|
||||||
@@ -370,21 +367,7 @@ class _DocumentsPageState extends State<DocumentsPage> with SingleTickerProvider
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _onCreateSavedView(DocumentFilter filter) async {
|
void _onCreateSavedView(DocumentFilter filter) async {
|
||||||
final newView = await Navigator.of(context).push<SavedView?>(
|
final newView = await pushAddSavedViewRoute(context, filter: filter);
|
||||||
MaterialPageRoute(
|
|
||||||
builder: (context) => BlocBuilder<SavedViewCubit, SavedViewState>(
|
|
||||||
builder: (context, state) {
|
|
||||||
return AddSavedViewPage(
|
|
||||||
currentFilter: filter,
|
|
||||||
correspondents: context.read<LabelRepository>().state.correspondents,
|
|
||||||
documentTypes: context.read<LabelRepository>().state.documentTypes,
|
|
||||||
storagePaths: context.read<LabelRepository>().state.storagePaths,
|
|
||||||
tags: context.read<LabelRepository>().state.tags,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
if (newView != null) {
|
if (newView != null) {
|
||||||
try {
|
try {
|
||||||
await context.read<SavedViewCubit>().add(newView);
|
await context.read<SavedViewCubit>().add(newView);
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
|
||||||
import 'package:paperless_mobile/features/documents/view/widgets/document_preview.dart';
|
import 'package:paperless_mobile/features/documents/view/widgets/document_preview.dart';
|
||||||
import 'package:paperless_mobile/features/documents/view/widgets/items/document_item.dart';
|
import 'package:paperless_mobile/features/documents/view/widgets/items/document_item.dart';
|
||||||
import 'package:paperless_mobile/features/labels/correspondent/view/widgets/correspondent_widget.dart';
|
import 'package:paperless_mobile/features/labels/correspondent/view/widgets/correspondent_widget.dart';
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ class DocumentsListLoadingWidget extends StatelessWidget {
|
|||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||||
children: [
|
children: [
|
||||||
TagsPlaceholder(count: 2, dense: true),
|
const TagsPlaceholder(count: 2, dense: true),
|
||||||
SizedBox(height: 2),
|
const SizedBox(height: 2),
|
||||||
TextPlaceholder(
|
TextPlaceholder(
|
||||||
length: 250,
|
length: 250,
|
||||||
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize!,
|
fontSize: Theme.of(context).textTheme.labelSmall!.fontSize!,
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/form_builder_fields/extended_date_range_form_field/form_builder_extended_date_range_picker.dart';
|
import 'package:paperless_mobile/core/widgets/form_builder_fields/extended_date_range_form_field/form_builder_extended_date_range_picker.dart';
|
||||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
|
||||||
import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart';
|
|
||||||
import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart';
|
import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_form_field.dart';
|
||||||
import 'package:paperless_mobile/features/labels/view/widgets/label_form_field.dart';
|
import 'package:paperless_mobile/features/labels/view/widgets/label_form_field.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
@@ -156,6 +154,10 @@ class _DocumentFilterFormState extends State<DocumentFilterForm> {
|
|||||||
initialValue: widget.initialFilter.documentType,
|
initialValue: widget.initialFilter.documentType,
|
||||||
prefixIcon: const Icon(Icons.description_outlined),
|
prefixIcon: const Icon(Icons.description_outlined),
|
||||||
allowSelectUnassigned: false,
|
allowSelectUnassigned: false,
|
||||||
|
canCreateNewLabel: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add,
|
||||||
|
PermissionTarget.documentType,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -167,6 +169,10 @@ class _DocumentFilterFormState extends State<DocumentFilterForm> {
|
|||||||
initialValue: widget.initialFilter.correspondent,
|
initialValue: widget.initialFilter.correspondent,
|
||||||
prefixIcon: const Icon(Icons.person_outline),
|
prefixIcon: const Icon(Icons.person_outline),
|
||||||
allowSelectUnassigned: false,
|
allowSelectUnassigned: false,
|
||||||
|
canCreateNewLabel: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add,
|
||||||
|
PermissionTarget.correspondent,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +184,10 @@ class _DocumentFilterFormState extends State<DocumentFilterForm> {
|
|||||||
initialValue: widget.initialFilter.storagePath,
|
initialValue: widget.initialFilter.storagePath,
|
||||||
prefixIcon: const Icon(Icons.folder_outlined),
|
prefixIcon: const Icon(Icons.folder_outlined),
|
||||||
allowSelectUnassigned: false,
|
allowSelectUnassigned: false,
|
||||||
|
canCreateNewLabel: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add,
|
||||||
|
PermissionTarget.storagePath,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/form_builder_fields/form_builder_type_ahead.dart';
|
|
||||||
import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart';
|
import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ class EditLabelPage<T extends Label> extends StatelessWidget {
|
|||||||
final List<Widget> additionalFields;
|
final List<Widget> additionalFields;
|
||||||
final Future<T> Function(BuildContext context, T label) onSubmit;
|
final Future<T> Function(BuildContext context, T label) onSubmit;
|
||||||
final Future<void> Function(BuildContext context, T label) onDelete;
|
final Future<void> Function(BuildContext context, T label) onDelete;
|
||||||
|
final bool canDelete;
|
||||||
|
|
||||||
const EditLabelPage({
|
const EditLabelPage({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -26,6 +27,7 @@ class EditLabelPage<T extends Label> extends StatelessWidget {
|
|||||||
this.additionalFields = const [],
|
this.additionalFields = const [],
|
||||||
required this.onSubmit,
|
required this.onSubmit,
|
||||||
required this.onDelete,
|
required this.onDelete,
|
||||||
|
required this.canDelete,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -40,6 +42,7 @@ class EditLabelPage<T extends Label> extends StatelessWidget {
|
|||||||
fromJsonT: fromJsonT,
|
fromJsonT: fromJsonT,
|
||||||
onSubmit: onSubmit,
|
onSubmit: onSubmit,
|
||||||
onDelete: onDelete,
|
onDelete: onDelete,
|
||||||
|
canDelete: canDelete,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -51,6 +54,7 @@ class EditLabelForm<T extends Label> extends StatelessWidget {
|
|||||||
final List<Widget> additionalFields;
|
final List<Widget> additionalFields;
|
||||||
final Future<T> Function(BuildContext context, T label) onSubmit;
|
final Future<T> Function(BuildContext context, T label) onSubmit;
|
||||||
final Future<void> Function(BuildContext context, T label) onDelete;
|
final Future<void> Function(BuildContext context, T label) onDelete;
|
||||||
|
final bool canDelete;
|
||||||
|
|
||||||
const EditLabelForm({
|
const EditLabelForm({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -59,6 +63,7 @@ class EditLabelForm<T extends Label> extends StatelessWidget {
|
|||||||
required this.additionalFields,
|
required this.additionalFields,
|
||||||
required this.onSubmit,
|
required this.onSubmit,
|
||||||
required this.onDelete,
|
required this.onDelete,
|
||||||
|
required this.canDelete,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -68,7 +73,7 @@ class EditLabelForm<T extends Label> extends StatelessWidget {
|
|||||||
title: Text(S.of(context)!.edit),
|
title: Text(S.of(context)!.edit),
|
||||||
actions: [
|
actions: [
|
||||||
IconButton(
|
IconButton(
|
||||||
onPressed: () => _onDelete(context),
|
onPressed: canDelete ? () => _onDelete(context) : null,
|
||||||
icon: const Icon(Icons.delete),
|
icon: const Icon(Icons.delete),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
||||||
|
|
||||||
@@ -19,10 +20,12 @@ class EditCorrespondentPage extends StatelessWidget {
|
|||||||
return EditLabelPage<Correspondent>(
|
return EditLabelPage<Correspondent>(
|
||||||
label: correspondent,
|
label: correspondent,
|
||||||
fromJsonT: Correspondent.fromJson,
|
fromJsonT: Correspondent.fromJson,
|
||||||
onSubmit: (context, label) =>
|
onSubmit: (context, label) => context.read<EditLabelCubit>().replaceCorrespondent(label),
|
||||||
context.read<EditLabelCubit>().replaceCorrespondent(label),
|
onDelete: (context, label) => context.read<EditLabelCubit>().removeCorrespondent(label),
|
||||||
onDelete: (context, label) =>
|
canDelete: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
context.read<EditLabelCubit>().removeCorrespondent(label),
|
PermissionAction.delete,
|
||||||
|
PermissionTarget.correspondent,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
||||||
|
|
||||||
@@ -18,10 +18,12 @@ class EditDocumentTypePage extends StatelessWidget {
|
|||||||
child: EditLabelPage<DocumentType>(
|
child: EditLabelPage<DocumentType>(
|
||||||
label: documentType,
|
label: documentType,
|
||||||
fromJsonT: DocumentType.fromJson,
|
fromJsonT: DocumentType.fromJson,
|
||||||
onSubmit: (context, label) =>
|
onSubmit: (context, label) => context.read<EditLabelCubit>().replaceDocumentType(label),
|
||||||
context.read<EditLabelCubit>().replaceDocumentType(label),
|
onDelete: (context, label) => context.read<EditLabelCubit>().removeDocumentType(label),
|
||||||
onDelete: (context, label) =>
|
canDelete: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
context.read<EditLabelCubit>().removeDocumentType(label),
|
PermissionAction.delete,
|
||||||
|
PermissionTarget.documentType,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
||||||
import 'package:paperless_mobile/features/labels/storage_path/view/widgets/storage_path_autofill_form_builder_field.dart';
|
import 'package:paperless_mobile/features/labels/storage_path/view/widgets/storage_path_autofill_form_builder_field.dart';
|
||||||
@@ -18,10 +19,12 @@ class EditStoragePathPage extends StatelessWidget {
|
|||||||
child: EditLabelPage<StoragePath>(
|
child: EditLabelPage<StoragePath>(
|
||||||
label: storagePath,
|
label: storagePath,
|
||||||
fromJsonT: StoragePath.fromJson,
|
fromJsonT: StoragePath.fromJson,
|
||||||
onSubmit: (context, label) =>
|
onSubmit: (context, label) => context.read<EditLabelCubit>().replaceStoragePath(label),
|
||||||
context.read<EditLabelCubit>().replaceStoragePath(label),
|
onDelete: (context, label) => context.read<EditLabelCubit>().removeStoragePath(label),
|
||||||
onDelete: (context, label) =>
|
canDelete: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
context.read<EditLabelCubit>().removeStoragePath(label),
|
PermissionAction.delete,
|
||||||
|
PermissionTarget.storagePath,
|
||||||
|
),
|
||||||
additionalFields: [
|
additionalFields: [
|
||||||
StoragePathAutofillFormBuilderField(
|
StoragePathAutofillFormBuilderField(
|
||||||
name: StoragePath.pathKey,
|
name: StoragePath.pathKey,
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/form_builder_fields/form_builder_color_picker.dart';
|
import 'package:paperless_mobile/core/widgets/form_builder_fields/form_builder_color_picker.dart';
|
||||||
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
import 'package:paperless_mobile/features/edit_label/cubit/edit_label_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
import 'package:paperless_mobile/features/edit_label/view/edit_label_page.dart';
|
||||||
@@ -21,10 +22,12 @@ class EditTagPage extends StatelessWidget {
|
|||||||
child: EditLabelPage<Tag>(
|
child: EditLabelPage<Tag>(
|
||||||
label: tag,
|
label: tag,
|
||||||
fromJsonT: Tag.fromJson,
|
fromJsonT: Tag.fromJson,
|
||||||
onSubmit: (context, label) =>
|
onSubmit: (context, label) => context.read<EditLabelCubit>().replaceTag(label),
|
||||||
context.read<EditLabelCubit>().replaceTag(label),
|
onDelete: (context, label) => context.read<EditLabelCubit>().removeTag(label),
|
||||||
onDelete: (context, label) =>
|
canDelete: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
context.read<EditLabelCubit>().removeTag(label),
|
PermissionAction.delete,
|
||||||
|
PermissionTarget.tag,
|
||||||
|
),
|
||||||
additionalFields: [
|
additionalFields: [
|
||||||
FormBuilderColorPickerField(
|
FormBuilderColorPickerField(
|
||||||
initialValue: tag.color,
|
initialValue: tag.color,
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
|||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
||||||
import 'package:paperless_mobile/constants.dart';
|
|
||||||
|
|
||||||
class SubmitButtonConfig<T extends Label> {
|
class SubmitButtonConfig<T extends Label> {
|
||||||
final Widget icon;
|
final Widget icon;
|
||||||
|
|||||||
@@ -6,38 +6,26 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:hive/hive.dart';
|
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart';
|
|
||||||
import 'package:paperless_mobile/core/global/constants.dart';
|
import 'package:paperless_mobile/core/global/constants.dart';
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.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/repository/saved_view_repository.dart';
|
||||||
import 'package:paperless_mobile/core/repository/user_repository.dart';
|
|
||||||
import 'package:paperless_mobile/core/service/file_description.dart';
|
import 'package:paperless_mobile/core/service/file_description.dart';
|
||||||
import 'package:paperless_mobile/core/translation/error_code_localization_mapper.dart';
|
import 'package:paperless_mobile/core/translation/error_code_localization_mapper.dart';
|
||||||
import 'package:paperless_mobile/features/document_scan/cubit/document_scanner_cubit.dart';
|
|
||||||
import 'package:paperless_mobile/features/document_scan/view/scanner_page.dart';
|
import 'package:paperless_mobile/features/document_scan/view/scanner_page.dart';
|
||||||
import 'package:paperless_mobile/features/document_upload/cubit/document_upload_cubit.dart';
|
import 'package:paperless_mobile/features/document_upload/cubit/document_upload_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/document_upload/view/document_upload_preparation_page.dart';
|
import 'package:paperless_mobile/features/document_upload/view/document_upload_preparation_page.dart';
|
||||||
import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart';
|
|
||||||
import 'package:paperless_mobile/features/documents/view/pages/documents_page.dart';
|
import 'package:paperless_mobile/features/documents/view/pages/documents_page.dart';
|
||||||
import 'package:paperless_mobile/features/home/view/route_description.dart';
|
import 'package:paperless_mobile/features/home/view/route_description.dart';
|
||||||
import 'package:paperless_mobile/features/inbox/cubit/inbox_cubit.dart';
|
import 'package:paperless_mobile/features/inbox/cubit/inbox_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/inbox/view/pages/inbox_page.dart';
|
import 'package:paperless_mobile/features/inbox/view/pages/inbox_page.dart';
|
||||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
|
||||||
import 'package:paperless_mobile/features/labels/view/pages/labels_page.dart';
|
import 'package:paperless_mobile/features/labels/view/pages/labels_page.dart';
|
||||||
import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart';
|
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
|
||||||
import 'package:paperless_mobile/features/notifications/services/local_notification_service.dart';
|
import 'package:paperless_mobile/features/notifications/services/local_notification_service.dart';
|
||||||
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
|
|
||||||
import 'package:paperless_mobile/features/sharing/share_intent_queue.dart';
|
import 'package:paperless_mobile/features/sharing/share_intent_queue.dart';
|
||||||
import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart';
|
import 'package:paperless_mobile/features/tasks/cubit/task_status_cubit.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:paperless_mobile/helpers/message_helpers.dart';
|
|
||||||
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
||||||
import 'package:responsive_builder/responsive_builder.dart';
|
import 'package:responsive_builder/responsive_builder.dart';
|
||||||
|
|
||||||
@@ -196,7 +184,8 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
|||||||
),
|
),
|
||||||
label: S.of(context)!.documents,
|
label: S.of(context)!.documents,
|
||||||
),
|
),
|
||||||
if (LocalUserAccount.current.paperlessUser.hasPermission(UserPermissions.addDocument))
|
if (LocalUserAccount.current.paperlessUser
|
||||||
|
.hasPermission(PermissionAction.add, PermissionTarget.document))
|
||||||
RouteDescription(
|
RouteDescription(
|
||||||
icon: const Icon(Icons.document_scanner_outlined),
|
icon: const Icon(Icons.document_scanner_outlined),
|
||||||
selectedIcon: Icon(
|
selectedIcon: Icon(
|
||||||
@@ -222,32 +211,31 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
|||||||
label: S.of(context)!.inbox,
|
label: S.of(context)!.inbox,
|
||||||
badgeBuilder: (icon) => BlocBuilder<InboxCubit, InboxState>(
|
badgeBuilder: (icon) => BlocBuilder<InboxCubit, InboxState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.itemsInInboxCount > 0) {
|
|
||||||
return Badge.count(
|
return Badge.count(
|
||||||
|
isLabelVisible: state.itemsInInboxCount > 0,
|
||||||
count: state.itemsInInboxCount,
|
count: state.itemsInInboxCount,
|
||||||
child: icon,
|
child: icon,
|
||||||
);
|
);
|
||||||
}
|
|
||||||
return icon;
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
final routes = <Widget>[
|
final routes = <Widget>[
|
||||||
const DocumentsPage(),
|
const DocumentsPage(),
|
||||||
if (LocalUserAccount.current.paperlessUser.hasPermission(UserPermissions.addDocument))
|
if (LocalUserAccount.current.paperlessUser
|
||||||
|
.hasPermission(PermissionAction.add, PermissionTarget.document))
|
||||||
const ScannerPage(),
|
const ScannerPage(),
|
||||||
const LabelsPage(),
|
const LabelsPage(),
|
||||||
const InboxPage(),
|
const InboxPage(),
|
||||||
];
|
];
|
||||||
|
|
||||||
return MultiBlocListener(
|
return MultiBlocListener(
|
||||||
listeners: [
|
listeners: [
|
||||||
BlocListener<ConnectivityCubit, ConnectivityState>(
|
BlocListener<ConnectivityCubit, ConnectivityState>(
|
||||||
//Only re-initialize data if the connectivity changed from not connected to connected
|
// If app was started offline, load data once it comes back online.
|
||||||
listenWhen: (previous, current) => current == ConnectivityState.connected,
|
listenWhen: (previous, current) => current == ConnectivityState.connected,
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
_initializeData(context);
|
context.read<LabelRepository>().initialize();
|
||||||
|
context.read<SavedViewRepository>().initialize();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
BlocListener<TaskStatusCubit, TaskStatusState>(
|
BlocListener<TaskStatusCubit, TaskStatusState>(
|
||||||
@@ -299,14 +287,4 @@ class _HomePageState extends State<HomePage> with WidgetsBindingObserver {
|
|||||||
setState(() => _currentIndex = index);
|
setState(() => _currentIndex = index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _initializeData(BuildContext context) {
|
|
||||||
Future.wait([
|
|
||||||
context.read<LabelRepository>().initialize(),
|
|
||||||
context.read<SavedViewRepository>().findAll(),
|
|
||||||
]).onError<PaperlessServerException>((error, stackTrace) {
|
|
||||||
showErrorMessage(context, error, stackTrace);
|
|
||||||
throw error;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
||||||
import 'package:hive_flutter/adapters.dart';
|
import 'package:hive_flutter/adapters.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
@@ -45,9 +44,10 @@ class HomeRoute extends StatelessWidget {
|
|||||||
return GlobalSettingsBuilder(
|
return GlobalSettingsBuilder(
|
||||||
builder: (context, settings) {
|
builder: (context, settings) {
|
||||||
final currentLocalUserId = settings.currentLoggedInUser!;
|
final currentLocalUserId = settings.currentLoggedInUser!;
|
||||||
|
final apiVersion = ApiVersion(paperlessApiVersion);
|
||||||
return MultiProvider(
|
return MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
Provider.value(value: ApiVersion(paperlessApiVersion)),
|
Provider.value(value: apiVersion),
|
||||||
Provider<CacheManager>(
|
Provider<CacheManager>(
|
||||||
create: (context) => CacheManager(
|
create: (context) => CacheManager(
|
||||||
Config(
|
Config(
|
||||||
@@ -87,7 +87,7 @@ class HomeRoute extends StatelessWidget {
|
|||||||
apiVersion: paperlessApiVersion,
|
apiVersion: paperlessApiVersion,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (paperlessApiVersion >= 3)
|
if (apiVersion.hasMultiUserSupport)
|
||||||
ProxyProvider<SessionManager, PaperlessUserApiV3>(
|
ProxyProvider<SessionManager, PaperlessUserApiV3>(
|
||||||
update: (context, value, previous) => PaperlessUserApiV3Impl(
|
update: (context, value, previous) => PaperlessUserApiV3Impl(
|
||||||
value.client,
|
value.client,
|
||||||
@@ -98,7 +98,7 @@ class HomeRoute extends StatelessWidget {
|
|||||||
return MultiProvider(
|
return MultiProvider(
|
||||||
providers: [
|
providers: [
|
||||||
ProxyProvider<PaperlessLabelsApi, LabelRepository>(
|
ProxyProvider<PaperlessLabelsApi, LabelRepository>(
|
||||||
update: (context, value, previous) => LabelRepository(value)..initialize(),
|
update: (context, value, previous) => LabelRepository(value),
|
||||||
),
|
),
|
||||||
ProxyProvider<PaperlessSavedViewsApi, SavedViewRepository>(
|
ProxyProvider<PaperlessSavedViewsApi, SavedViewRepository>(
|
||||||
update: (context, value, previous) => SavedViewRepository(value)..initialize(),
|
update: (context, value, previous) => SavedViewRepository(value)..initialize(),
|
||||||
|
|||||||
@@ -3,6 +3,5 @@ class ApiVersion {
|
|||||||
|
|
||||||
ApiVersion(this.version);
|
ApiVersion(this.version);
|
||||||
|
|
||||||
bool get supportsPermissions => version >= 3;
|
|
||||||
bool get hasMultiUserSupport => version >= 3;
|
bool get hasMultiUserSupport => version >= 3;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.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/repository/saved_view_repository.dart';
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart';
|
import 'package:paperless_mobile/features/login/cubit/authentication_cubit.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
|
||||||
|
|
||||||
import 'package:paperless_mobile/features/settings/view/widgets/user_settings_builder.dart';
|
import 'package:paperless_mobile/features/settings/view/widgets/user_settings_builder.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:intl/intl.dart';
|
import 'package:intl/intl.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/core/exception/server_message_exception.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_cancel_button.dart';
|
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_cancel_button.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_confirm_button.dart';
|
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_confirm_button.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/hint_card.dart';
|
import 'package:paperless_mobile/core/widgets/hint_card.dart';
|
||||||
@@ -10,7 +11,6 @@ import 'package:paperless_mobile/extensions/dart_extensions.dart';
|
|||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
|
import 'package:paperless_mobile/features/app_drawer/view/app_drawer.dart';
|
||||||
import 'package:paperless_mobile/features/document_search/view/sliver_search_bar.dart';
|
import 'package:paperless_mobile/features/document_search/view/sliver_search_bar.dart';
|
||||||
import 'package:paperless_mobile/features/documents/view/widgets/placeholder/documents_list_loading_widget.dart';
|
|
||||||
import 'package:paperless_mobile/features/inbox/cubit/inbox_cubit.dart';
|
import 'package:paperless_mobile/features/inbox/cubit/inbox_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/inbox/view/widgets/inbox_empty_widget.dart';
|
import 'package:paperless_mobile/features/inbox/view/widgets/inbox_empty_widget.dart';
|
||||||
import 'package:paperless_mobile/features/inbox/view/widgets/inbox_item.dart';
|
import 'package:paperless_mobile/features/inbox/view/widgets/inbox_item.dart';
|
||||||
@@ -26,10 +26,8 @@ class InboxPage extends StatefulWidget {
|
|||||||
State<InboxPage> createState() => _InboxPageState();
|
State<InboxPage> createState() => _InboxPageState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _InboxPageState extends State<InboxPage>
|
class _InboxPageState extends State<InboxPage> with DocumentPagingViewMixin<InboxPage, InboxCubit> {
|
||||||
with DocumentPagingViewMixin<InboxPage, InboxCubit> {
|
final SliverOverlapAbsorberHandle searchBarHandle = SliverOverlapAbsorberHandle();
|
||||||
final SliverOverlapAbsorberHandle searchBarHandle =
|
|
||||||
SliverOverlapAbsorberHandle();
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
final pagingScrollController = ScrollController();
|
final pagingScrollController = ScrollController();
|
||||||
@@ -80,8 +78,7 @@ class _InboxPageState extends State<InboxPage>
|
|||||||
} else if (state.documents.isEmpty) {
|
} else if (state.documents.isEmpty) {
|
||||||
return Center(
|
return Center(
|
||||||
child: InboxEmptyWidget(
|
child: InboxEmptyWidget(
|
||||||
emptyStateRefreshIndicatorKey:
|
emptyStateRefreshIndicatorKey: _emptyStateRefreshIndicatorKey,
|
||||||
_emptyStateRefreshIndicatorKey,
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
@@ -92,8 +89,7 @@ class _InboxPageState extends State<InboxPage>
|
|||||||
SliverToBoxAdapter(
|
SliverToBoxAdapter(
|
||||||
child: HintCard(
|
child: HintCard(
|
||||||
show: !state.isHintAcknowledged,
|
show: !state.isHintAcknowledged,
|
||||||
hintText:
|
hintText: S.of(context)!.swipeLeftToMarkADocumentAsSeen,
|
||||||
S.of(context)!.swipeLeftToMarkADocumentAsSeen,
|
|
||||||
onHintAcknowledged: () =>
|
onHintAcknowledged: () =>
|
||||||
context.read<InboxCubit>().acknowledgeHint(),
|
context.read<InboxCubit>().acknowledgeHint(),
|
||||||
),
|
),
|
||||||
@@ -108,13 +104,10 @@ class _InboxPageState extends State<InboxPage>
|
|||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.centerLeft,
|
alignment: Alignment.centerLeft,
|
||||||
child: ClipRRect(
|
child: ClipRRect(
|
||||||
borderRadius:
|
borderRadius: BorderRadius.circular(32.0),
|
||||||
BorderRadius.circular(32.0),
|
|
||||||
child: Text(
|
child: Text(
|
||||||
entry.key,
|
entry.key,
|
||||||
style: Theme.of(context)
|
style: Theme.of(context).textTheme.bodySmall,
|
||||||
.textTheme
|
|
||||||
.bodySmall,
|
|
||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
).padded(),
|
).padded(),
|
||||||
),
|
),
|
||||||
@@ -182,7 +175,7 @@ class _InboxPageState extends State<InboxPage>
|
|||||||
],
|
],
|
||||||
).padded(),
|
).padded(),
|
||||||
confirmDismiss: (_) => _onItemDismissed(doc),
|
confirmDismiss: (_) => _onItemDismissed(doc),
|
||||||
key: UniqueKey(),
|
key: ValueKey(doc.id),
|
||||||
child: InboxItem(document: doc),
|
child: InboxItem(document: doc),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -227,14 +220,15 @@ class _InboxPageState extends State<InboxPage>
|
|||||||
return true;
|
return true;
|
||||||
} on PaperlessServerException catch (error, stackTrace) {
|
} on PaperlessServerException catch (error, stackTrace) {
|
||||||
showErrorMessage(context, error, stackTrace);
|
showErrorMessage(context, error, stackTrace);
|
||||||
return false;
|
} on ServerMessageException catch (error) {
|
||||||
|
showGenericError(context, error.message);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
showErrorMessage(
|
showErrorMessage(
|
||||||
context,
|
context,
|
||||||
const PaperlessServerException.unknown(),
|
const PaperlessServerException.unknown(),
|
||||||
);
|
);
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _onUndoMarkAsSeen(
|
Future<void> _onUndoMarkAsSeen(
|
||||||
@@ -242,9 +236,7 @@ class _InboxPageState extends State<InboxPage>
|
|||||||
Iterable<int> removedTags,
|
Iterable<int> removedTags,
|
||||||
) async {
|
) async {
|
||||||
try {
|
try {
|
||||||
await context
|
await context.read<InboxCubit>().undoRemoveFromInbox(document, removedTags);
|
||||||
.read<InboxCubit>()
|
|
||||||
.undoRemoveFromInbox(document, removedTags);
|
|
||||||
} on PaperlessServerException catch (error, stackTrace) {
|
} on PaperlessServerException catch (error, stackTrace) {
|
||||||
showErrorMessage(context, error, stackTrace);
|
showErrorMessage(context, error, stackTrace);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:collection/collection.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/navigation/push_routes.dart';
|
import 'package:paperless_mobile/core/navigation/push_routes.dart';
|
||||||
import 'package:paperless_mobile/core/workarounds/colored_chip.dart';
|
import 'package:paperless_mobile/core/workarounds/colored_chip.dart';
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
@@ -12,8 +13,6 @@ import 'package:paperless_mobile/features/labels/tags/view/widgets/tags_widget.d
|
|||||||
import 'package:paperless_mobile/features/labels/view/widgets/label_text.dart';
|
import 'package:paperless_mobile/features/labels/view/widgets/label_text.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:paperless_mobile/routes/document_details_route.dart';
|
|
||||||
|
|
||||||
class InboxItem extends StatefulWidget {
|
class InboxItem extends StatefulWidget {
|
||||||
static const a4AspectRatio = 1 / 1.4142;
|
static const a4AspectRatio = 1 / 1.4142;
|
||||||
|
|
||||||
@@ -108,8 +107,8 @@ class _InboxItemState extends State<InboxItem> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
SizedBox(
|
LimitedBox(
|
||||||
height: 56,
|
maxHeight: 56,
|
||||||
child: _buildActions(context),
|
child: _buildActions(context),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -121,12 +120,17 @@ class _InboxItemState extends State<InboxItem> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildActions(BuildContext context) {
|
Widget _buildActions(BuildContext context) {
|
||||||
|
final canEdit = LocalUserAccount.current.paperlessUser
|
||||||
|
.hasPermission(PermissionAction.change, PermissionTarget.document);
|
||||||
|
final canDelete = LocalUserAccount.current.paperlessUser
|
||||||
|
.hasPermission(PermissionAction.delete, PermissionTarget.document);
|
||||||
final chipShape = RoundedRectangleBorder(
|
final chipShape = RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(32),
|
borderRadius: BorderRadius.circular(32),
|
||||||
);
|
);
|
||||||
final actions = [
|
final actions = [
|
||||||
_buildAssignAsnAction(chipShape, context),
|
if (canEdit) _buildAssignAsnAction(chipShape, context),
|
||||||
const SizedBox(width: 8.0),
|
if (canEdit && canDelete) const SizedBox(width: 8.0),
|
||||||
|
if (canDelete)
|
||||||
ColoredChipWrapper(
|
ColoredChipWrapper(
|
||||||
child: ActionChip(
|
child: ActionChip(
|
||||||
avatar: const Icon(Icons.delete_outline),
|
avatar: const Icon(Icons.delete_outline),
|
||||||
@@ -135,7 +139,8 @@ class _InboxItemState extends State<InboxItem> {
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final shouldDelete = await showDialog<bool>(
|
final shouldDelete = await showDialog<bool>(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => DeleteDocumentConfirmationDialog(document: widget.document),
|
builder: (context) =>
|
||||||
|
DeleteDocumentConfirmationDialog(document: widget.document),
|
||||||
) ??
|
) ??
|
||||||
false;
|
false;
|
||||||
if (shouldDelete) {
|
if (shouldDelete) {
|
||||||
@@ -145,34 +150,16 @@ class _InboxItemState extends State<InboxItem> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
if (actions.isEmpty) {
|
||||||
// return FutureBuilder<FieldSuggestions>(
|
return const SizedBox.shrink();
|
||||||
// future: _fieldSuggestions,
|
}
|
||||||
// builder: (context, snapshot) {
|
|
||||||
// List<Widget>? suggestions;
|
|
||||||
// if (!snapshot.hasData) {
|
|
||||||
// suggestions = [
|
|
||||||
// const SizedBox(width: 4),
|
|
||||||
// ];
|
|
||||||
// } else {
|
|
||||||
// if (snapshot.data!.hasSuggestions) {
|
|
||||||
// suggestions = [
|
|
||||||
// const SizedBox(width: 4),
|
|
||||||
// ..._buildSuggestionChips(
|
|
||||||
// chipShape,
|
|
||||||
// snapshot.data!,
|
|
||||||
// context.watch<InboxCubit>().state,
|
|
||||||
// ),
|
|
||||||
// ];
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
const Icon(Icons.bolt_outlined),
|
const Icon(Icons.auto_awesome),
|
||||||
ConstrainedBox(
|
ConstrainedBox(
|
||||||
constraints: const BoxConstraints(
|
constraints: const BoxConstraints(
|
||||||
maxWidth: 50,
|
maxWidth: 50,
|
||||||
@@ -229,6 +216,7 @@ class _InboxItemState extends State<InboxItem> {
|
|||||||
setState(() {
|
setState(() {
|
||||||
_isAsnAssignLoading = true;
|
_isAsnAssignLoading = true;
|
||||||
});
|
});
|
||||||
|
|
||||||
context.read<InboxCubit>().assignAsn(widget.document).whenComplete(
|
context.read<InboxCubit>().assignAsn(widget.document).whenComplete(
|
||||||
() => setState(() => _isAsnAssignLoading = false),
|
() => setState(() => _isAsnAssignLoading = false),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import 'package:paperless_mobile/core/widgets/shimmer_placeholder.dart';
|
|||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/features/documents/view/widgets/placeholder/tags_placeholder.dart';
|
import 'package:paperless_mobile/features/documents/view/widgets/placeholder/tags_placeholder.dart';
|
||||||
import 'package:paperless_mobile/features/documents/view/widgets/placeholder/text_placeholder.dart';
|
import 'package:paperless_mobile/features/documents/view/widgets/placeholder/text_placeholder.dart';
|
||||||
import 'package:paperless_mobile/features/inbox/view/widgets/inbox_item.dart';
|
|
||||||
|
|
||||||
class InboxListLoadingWidget extends StatelessWidget {
|
class InboxListLoadingWidget extends StatelessWidget {
|
||||||
const InboxListLoadingWidget({super.key});
|
const InboxListLoadingWidget({super.key});
|
||||||
@@ -48,10 +47,10 @@ class InboxListLoadingWidget extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: 8),
|
const SizedBox(width: 8),
|
||||||
Flexible(
|
const Flexible(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: const [
|
children: [
|
||||||
Spacer(),
|
Spacer(),
|
||||||
TextPlaceholder(length: 200, fontSize: 14),
|
TextPlaceholder(length: 200, fontSize: 14),
|
||||||
Spacer(),
|
Spacer(),
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||||
|
|||||||
@@ -1,10 +1,9 @@
|
|||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:animations/animations.dart';
|
import 'package:animations/animations.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/workarounds/colored_chip.dart';
|
import 'package:paperless_mobile/core/workarounds/colored_chip.dart';
|
||||||
import 'package:paperless_mobile/features/labels/tags/view/widgets/fullscreen_tags_form.dart';
|
import 'package:paperless_mobile/features/labels/tags/view/widgets/fullscreen_tags_form.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
@@ -72,7 +71,11 @@ class TagsFormField extends StatelessWidget {
|
|||||||
onSubmit: closeForm,
|
onSubmit: closeForm,
|
||||||
initialValue: field.value,
|
initialValue: field.value,
|
||||||
allowOnlySelection: allowOnlySelection,
|
allowOnlySelection: allowOnlySelection,
|
||||||
allowCreation: allowCreation,
|
allowCreation: allowCreation &&
|
||||||
|
LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add,
|
||||||
|
PermissionTarget.tag,
|
||||||
|
),
|
||||||
allowExclude: allowExclude,
|
allowExclude: allowExclude,
|
||||||
),
|
),
|
||||||
onClosed: (data) {
|
onClosed: (data) {
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||||
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_header_delegate.dart';
|
import 'package:paperless_mobile/core/delegate/customizable_sliver_persistent_header_delegate.dart';
|
||||||
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
import 'package:paperless_mobile/core/repository/label_repository.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/material/colored_tab_bar.dart';
|
import 'package:paperless_mobile/core/widgets/material/colored_tab_bar.dart';
|
||||||
@@ -16,7 +17,6 @@ import 'package:paperless_mobile/features/edit_label/view/impl/edit_document_typ
|
|||||||
import 'package:paperless_mobile/features/edit_label/view/impl/edit_storage_path_page.dart';
|
import 'package:paperless_mobile/features/edit_label/view/impl/edit_storage_path_page.dart';
|
||||||
import 'package:paperless_mobile/features/edit_label/view/impl/edit_tag_page.dart';
|
import 'package:paperless_mobile/features/edit_label/view/impl/edit_tag_page.dart';
|
||||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
import 'package:paperless_mobile/features/labels/cubit/label_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/labels/cubit/label_cubit_mixin.dart';
|
|
||||||
import 'package:paperless_mobile/features/labels/view/widgets/label_tab_view.dart';
|
import 'package:paperless_mobile/features/labels/view/widgets/label_tab_view.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
@@ -148,6 +148,10 @@ class _LabelsPageState extends State<LabelsPage> with SingleTickerProviderStateM
|
|||||||
correspondent: IdQueryParameter.fromId(label.id!),
|
correspondent: IdQueryParameter.fromId(label.id!),
|
||||||
pageSize: label.documentCount ?? 0,
|
pageSize: label.documentCount ?? 0,
|
||||||
),
|
),
|
||||||
|
canEdit: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.change, PermissionTarget.correspondent),
|
||||||
|
canAddNew: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add, PermissionTarget.correspondent),
|
||||||
onEdit: _openEditCorrespondentPage,
|
onEdit: _openEditCorrespondentPage,
|
||||||
emptyStateActionButtonLabel: S.of(context)!.addNewCorrespondent,
|
emptyStateActionButtonLabel: S.of(context)!.addNewCorrespondent,
|
||||||
emptyStateDescription: S.of(context)!.noCorrespondentsSetUp,
|
emptyStateDescription: S.of(context)!.noCorrespondentsSetUp,
|
||||||
@@ -169,6 +173,10 @@ class _LabelsPageState extends State<LabelsPage> with SingleTickerProviderStateM
|
|||||||
documentType: IdQueryParameter.fromId(label.id!),
|
documentType: IdQueryParameter.fromId(label.id!),
|
||||||
pageSize: label.documentCount ?? 0,
|
pageSize: label.documentCount ?? 0,
|
||||||
),
|
),
|
||||||
|
canEdit: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.change, PermissionTarget.documentType),
|
||||||
|
canAddNew: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add, PermissionTarget.documentType),
|
||||||
onEdit: _openEditDocumentTypePage,
|
onEdit: _openEditDocumentTypePage,
|
||||||
emptyStateActionButtonLabel: S.of(context)!.addNewDocumentType,
|
emptyStateActionButtonLabel: S.of(context)!.addNewDocumentType,
|
||||||
emptyStateDescription: S.of(context)!.noDocumentTypesSetUp,
|
emptyStateDescription: S.of(context)!.noDocumentTypesSetUp,
|
||||||
@@ -190,6 +198,10 @@ class _LabelsPageState extends State<LabelsPage> with SingleTickerProviderStateM
|
|||||||
tags: TagsQuery.ids(include: [label.id!]),
|
tags: TagsQuery.ids(include: [label.id!]),
|
||||||
pageSize: label.documentCount ?? 0,
|
pageSize: label.documentCount ?? 0,
|
||||||
),
|
),
|
||||||
|
canEdit: LocalUserAccount.current.paperlessUser
|
||||||
|
.hasPermission(PermissionAction.change, PermissionTarget.tag),
|
||||||
|
canAddNew: LocalUserAccount.current.paperlessUser
|
||||||
|
.hasPermission(PermissionAction.add, PermissionTarget.tag),
|
||||||
onEdit: _openEditTagPage,
|
onEdit: _openEditTagPage,
|
||||||
leadingBuilder: (t) => CircleAvatar(
|
leadingBuilder: (t) => CircleAvatar(
|
||||||
backgroundColor: t.color,
|
backgroundColor: t.color,
|
||||||
@@ -221,6 +233,10 @@ class _LabelsPageState extends State<LabelsPage> with SingleTickerProviderStateM
|
|||||||
storagePath: IdQueryParameter.fromId(label.id!),
|
storagePath: IdQueryParameter.fromId(label.id!),
|
||||||
pageSize: label.documentCount ?? 0,
|
pageSize: label.documentCount ?? 0,
|
||||||
),
|
),
|
||||||
|
canEdit: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.change, PermissionTarget.storagePath),
|
||||||
|
canAddNew: LocalUserAccount.current.paperlessUser.hasPermission(
|
||||||
|
PermissionAction.add, PermissionTarget.storagePath),
|
||||||
contentBuilder: (path) => Text(path.path),
|
contentBuilder: (path) => Text(path.path),
|
||||||
emptyStateActionButtonLabel: S.of(context)!.addNewStoragePath,
|
emptyStateActionButtonLabel: S.of(context)!.addNewStoragePath,
|
||||||
emptyStateDescription: S.of(context)!.noStoragePathsSetUp,
|
emptyStateDescription: S.of(context)!.noStoragePathsSetUp,
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ class FullscreenLabelForm<T extends Label> extends StatefulWidget {
|
|||||||
final String? addNewLabelText;
|
final String? addNewLabelText;
|
||||||
final bool autofocus;
|
final bool autofocus;
|
||||||
final bool allowSelectUnassigned;
|
final bool allowSelectUnassigned;
|
||||||
|
final bool canCreateNewLabel;
|
||||||
|
|
||||||
FullscreenLabelForm({
|
FullscreenLabelForm({
|
||||||
super.key,
|
super.key,
|
||||||
@@ -29,6 +30,7 @@ class FullscreenLabelForm<T extends Label> extends StatefulWidget {
|
|||||||
this.addNewLabelText,
|
this.addNewLabelText,
|
||||||
this.autofocus = true,
|
this.autofocus = true,
|
||||||
this.allowSelectUnassigned = true,
|
this.allowSelectUnassigned = true,
|
||||||
|
required this.canCreateNewLabel,
|
||||||
}) : assert(
|
}) : assert(
|
||||||
!(initialValue?.isOnlyAssigned() ?? false) || showAnyAssignedOption,
|
!(initialValue?.isOnlyAssigned() ?? false) || showAnyAssignedOption,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:animations/animations.dart';
|
import 'package:animations/animations.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@@ -28,6 +26,7 @@ class LabelFormField<T extends Label> extends StatelessWidget {
|
|||||||
final List<T> suggestions;
|
final List<T> suggestions;
|
||||||
final String? addLabelText;
|
final String? addLabelText;
|
||||||
final bool allowSelectUnassigned;
|
final bool allowSelectUnassigned;
|
||||||
|
final bool canCreateNewLabel;
|
||||||
|
|
||||||
const LabelFormField({
|
const LabelFormField({
|
||||||
Key? key,
|
Key? key,
|
||||||
@@ -44,6 +43,7 @@ class LabelFormField<T extends Label> extends StatelessWidget {
|
|||||||
this.suggestions = const [],
|
this.suggestions = const [],
|
||||||
this.addLabelText,
|
this.addLabelText,
|
||||||
required this.allowSelectUnassigned,
|
required this.allowSelectUnassigned,
|
||||||
|
required this.canCreateNewLabel,
|
||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
String _buildText(BuildContext context, IdQueryParameter? value) {
|
String _buildText(BuildContext context, IdQueryParameter? value) {
|
||||||
@@ -103,6 +103,7 @@ class LabelFormField<T extends Label> extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
openBuilder: (context, closeForm) => FullscreenLabelForm<T>(
|
openBuilder: (context, closeForm) => FullscreenLabelForm<T>(
|
||||||
allowSelectUnassigned: allowSelectUnassigned,
|
allowSelectUnassigned: allowSelectUnassigned,
|
||||||
|
canCreateNewLabel: canCreateNewLabel,
|
||||||
addNewLabelText: addLabelText,
|
addNewLabelText: addLabelText,
|
||||||
leadingIcon: prefixIcon,
|
leadingIcon: prefixIcon,
|
||||||
onCreateNewLabel: addLabelPageBuilder != null
|
onCreateNewLabel: addLabelPageBuilder != null
|
||||||
|
|||||||
@@ -1,19 +1,14 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:hive/hive.dart';
|
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
|
||||||
import 'package:paperless_mobile/features/linked_documents/cubit/linked_documents_cubit.dart';
|
|
||||||
import 'package:paperless_mobile/features/linked_documents/view/linked_documents_page.dart';
|
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
import 'package:paperless_mobile/core/navigation/push_routes.dart';
|
||||||
import 'package:paperless_mobile/helpers/format_helpers.dart';
|
import 'package:paperless_mobile/helpers/format_helpers.dart';
|
||||||
|
|
||||||
class LabelItem<T extends Label> extends StatelessWidget {
|
class LabelItem<T extends Label> extends StatelessWidget {
|
||||||
final T label;
|
final T label;
|
||||||
final String name;
|
final String name;
|
||||||
final Widget content;
|
final Widget content;
|
||||||
final void Function(T) onOpenEditPage;
|
final void Function(T)? onOpenEditPage;
|
||||||
final DocumentFilter Function(T) filterBuilder;
|
final DocumentFilter Function(T) filterBuilder;
|
||||||
final Widget? leading;
|
final Widget? leading;
|
||||||
|
|
||||||
@@ -33,38 +28,25 @@ class LabelItem<T extends Label> extends StatelessWidget {
|
|||||||
title: Text(name),
|
title: Text(name),
|
||||||
subtitle: content,
|
subtitle: content,
|
||||||
leading: leading,
|
leading: leading,
|
||||||
onTap: () => onOpenEditPage(label),
|
onTap: onOpenEditPage != null ? () => onOpenEditPage!(label) : null,
|
||||||
trailing: _buildReferencedDocumentsWidget(context),
|
trailing: _buildReferencedDocumentsWidget(context),
|
||||||
isThreeLine: true,
|
isThreeLine: true,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildReferencedDocumentsWidget(BuildContext context) {
|
Widget _buildReferencedDocumentsWidget(BuildContext context) {
|
||||||
|
final canOpen = (label.documentCount ?? 0) > 0 &&
|
||||||
|
LocalUserAccount.current.paperlessUser
|
||||||
|
.hasPermission(PermissionAction.view, PermissionTarget.document);
|
||||||
return TextButton.icon(
|
return TextButton.icon(
|
||||||
label: const Icon(Icons.link),
|
label: const Icon(Icons.link),
|
||||||
icon: Text(formatMaxCount(label.documentCount)),
|
icon: Text(formatMaxCount(label.documentCount)),
|
||||||
onPressed: (label.documentCount ?? 0) == 0
|
onPressed: canOpen
|
||||||
? null
|
? () {
|
||||||
: () {
|
|
||||||
final currentUser = Hive.box<GlobalSettings>(HiveBoxes.globalSettings)
|
|
||||||
.getValue()!
|
|
||||||
.currentLoggedInUser!;
|
|
||||||
final filter = filterBuilder(label);
|
final filter = filterBuilder(label);
|
||||||
Navigator.push(
|
pushLinkedDocumentsView(context, filter: filter);
|
||||||
context,
|
}
|
||||||
MaterialPageRoute(
|
: null,
|
||||||
builder: (context) => BlocProvider(
|
|
||||||
create: (context) => LinkedDocumentsCubit(
|
|
||||||
filter,
|
|
||||||
context.read(),
|
|
||||||
context.read(),
|
|
||||||
context.read(),
|
|
||||||
),
|
|
||||||
child: const LinkedDocumentsPage(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,9 @@ class LabelTabView<T extends Label> extends StatelessWidget {
|
|||||||
final Map<int, T> labels;
|
final Map<int, T> labels;
|
||||||
final DocumentFilter Function(Label) filterBuilder;
|
final DocumentFilter Function(Label) filterBuilder;
|
||||||
final void Function(T) onEdit;
|
final void Function(T) onEdit;
|
||||||
|
final bool canEdit;
|
||||||
final void Function() onAddNew;
|
final void Function() onAddNew;
|
||||||
|
final bool canAddNew;
|
||||||
|
|
||||||
/// Displayed as the subtitle of the [ListTile]
|
/// Displayed as the subtitle of the [ListTile]
|
||||||
final Widget Function(T)? contentBuilder;
|
final Widget Function(T)? contentBuilder;
|
||||||
@@ -33,6 +35,8 @@ class LabelTabView<T extends Label> extends StatelessWidget {
|
|||||||
required this.onAddNew,
|
required this.onAddNew,
|
||||||
required this.emptyStateActionButtonLabel,
|
required this.emptyStateActionButtonLabel,
|
||||||
required this.labels,
|
required this.labels,
|
||||||
|
required this.canEdit,
|
||||||
|
required this.canAddNew,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -54,7 +58,7 @@ class LabelTabView<T extends Label> extends StatelessWidget {
|
|||||||
textAlign: TextAlign.center,
|
textAlign: TextAlign.center,
|
||||||
),
|
),
|
||||||
TextButton(
|
TextButton(
|
||||||
onPressed: onAddNew,
|
onPressed: canAddNew ? onAddNew : null,
|
||||||
child: Text(emptyStateActionButtonLabel),
|
child: Text(emptyStateActionButtonLabel),
|
||||||
),
|
),
|
||||||
].padded(),
|
].padded(),
|
||||||
@@ -70,14 +74,11 @@ class LabelTabView<T extends Label> extends StatelessWidget {
|
|||||||
name: l.name,
|
name: l.name,
|
||||||
content: contentBuilder?.call(l) ??
|
content: contentBuilder?.call(l) ??
|
||||||
Text(
|
Text(
|
||||||
translateMatchingAlgorithmName(
|
translateMatchingAlgorithmName(context, l.matchingAlgorithm) +
|
||||||
context, l.matchingAlgorithm) +
|
((l.match?.isNotEmpty ?? false) ? ": ${l.match}" : ""),
|
||||||
((l.match?.isNotEmpty ?? false)
|
|
||||||
? ": ${l.match}"
|
|
||||||
: ""),
|
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
),
|
),
|
||||||
onOpenEditPage: onEdit,
|
onOpenEditPage: canEdit ? onEdit : null,
|
||||||
filterBuilder: filterBuilder,
|
filterBuilder: filterBuilder,
|
||||||
leading: leadingBuilder?.call(l),
|
leading: leadingBuilder?.call(l),
|
||||||
label: l,
|
label: l,
|
||||||
|
|||||||
@@ -20,6 +20,5 @@ class LabelText<T extends Label> extends StatelessWidget {
|
|||||||
maxLines: 1,
|
maxLines: 1,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
);
|
);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import 'package:paperless_mobile/features/linked_documents/cubit/linked_document
|
|||||||
import 'package:paperless_mobile/features/paged_document_view/view/document_paging_view_mixin.dart';
|
import 'package:paperless_mobile/features/paged_document_view/view/document_paging_view_mixin.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:paperless_mobile/routes/document_details_route.dart';
|
|
||||||
|
|
||||||
class LinkedDocumentsPage extends StatefulWidget {
|
class LinkedDocumentsPage extends StatefulWidget {
|
||||||
const LinkedDocumentsPage({super.key});
|
const LinkedDocumentsPage({super.key});
|
||||||
|
|||||||
@@ -179,6 +179,7 @@ class AuthenticationCubit extends Cubit<AuthenticationState> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
final userCredentialsBox = await _getUserCredentialsBox();
|
final userCredentialsBox = await _getUserCredentialsBox();
|
||||||
final authentication = userCredentialsBox.get(globalSettings.currentLoggedInUser!);
|
final authentication = userCredentialsBox.get(globalSettings.currentLoggedInUser!);
|
||||||
await userCredentialsBox.close();
|
await userCredentialsBox.close();
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
||||||
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
|
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
import 'package:hive_flutter/adapters.dart';
|
import 'package:hive_flutter/adapters.dart';
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'dart:convert';
|
|
||||||
import 'dart:typed_data';
|
import 'dart:typed_data';
|
||||||
|
|
||||||
class ClientCertificateFormModel {
|
class ClientCertificateFormModel {
|
||||||
|
|||||||
@@ -4,12 +4,9 @@ import 'package:file_picker/file_picker.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
|
|
||||||
import 'package:paperless_mobile/features/login/model/client_certificate_form_model.dart';
|
import 'package:paperless_mobile/features/login/model/client_certificate_form_model.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
import 'package:paperless_mobile/constants.dart';
|
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
|
||||||
|
|
||||||
import 'obscured_input_text_form_field.dart';
|
import 'obscured_input_text_form_field.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
@@ -49,6 +48,7 @@ class _ServerAddressFormFieldState extends State<ServerAddressFormField> {
|
|||||||
if (!RegExp(r"https?://.*").hasMatch(value!)) {
|
if (!RegExp(r"https?://.*").hasMatch(value!)) {
|
||||||
return S.of(context)!.serverAddressMustIncludeAScheme;
|
return S.of(context)!.serverAddressMustIncludeAScheme;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
hintText: "http://192.168.1.50:8000",
|
hintText: "http://192.168.1.50:8000",
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ class _UserCredentialsFormFieldState extends State<UserCredentialsFormField> {
|
|||||||
if (value?.trim().isEmpty ?? true) {
|
if (value?.trim().isEmpty ?? true) {
|
||||||
return S.of(context)!.usernameMustNotBeEmpty;
|
return S.of(context)!.usernameMustNotBeEmpty;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
autofillHints: const [AutofillHints.username],
|
autofillHints: const [AutofillHints.username],
|
||||||
decoration: InputDecoration(
|
decoration: InputDecoration(
|
||||||
@@ -56,6 +57,7 @@ class _UserCredentialsFormFieldState extends State<UserCredentialsFormField> {
|
|||||||
if (value?.trim().isEmpty ?? true) {
|
if (value?.trim().isEmpty ?? true) {
|
||||||
return S.of(context)!.passwordMustNotBeEmpty;
|
return S.of(context)!.passwordMustNotBeEmpty;
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
].map((child) => child.padded()).toList(),
|
].map((child) => child.padded()).toList(),
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
import 'package:flutter_form_builder/flutter_form_builder.dart';
|
||||||
import 'package:paperless_mobile/core/service/connectivity_status_service.dart';
|
import 'package:paperless_mobile/core/service/connectivity_status_service.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/paperless_logo.dart';
|
|
||||||
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
import 'package:paperless_mobile/extensions/flutter_extensions.dart';
|
||||||
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
|
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
|
||||||
import 'package:paperless_mobile/features/login/model/client_certificate_form_model.dart';
|
import 'package:paperless_mobile/features/login/model/client_certificate_form_model.dart';
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'dart:developer';
|
import 'dart:developer';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
import 'package:flutter_local_notifications/flutter_local_notifications.dart';
|
||||||
import 'package:open_filex/open_filex.dart';
|
import 'package:open_filex/open_filex.dart';
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
|
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import 'dart:async';
|
|||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.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/repository/saved_view_repository.dart';
|
||||||
|
|
||||||
part 'saved_view_state.dart';
|
part 'saved_view_state.dart';
|
||||||
|
|||||||
@@ -1,15 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:hive/hive.dart';
|
|
||||||
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
import 'package:paperless_mobile/core/bloc/connectivity_cubit.dart';
|
||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart';
|
|
||||||
import 'package:paperless_mobile/core/navigation/push_routes.dart';
|
import 'package:paperless_mobile/core/navigation/push_routes.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/hint_card.dart';
|
import 'package:paperless_mobile/core/widgets/hint_card.dart';
|
||||||
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
|
import 'package:paperless_mobile/features/saved_view/cubit/saved_view_cubit.dart';
|
||||||
import 'package:paperless_mobile/features/saved_view_details/cubit/saved_view_details_cubit.dart';
|
|
||||||
import 'package:paperless_mobile/features/saved_view_details/view/saved_view_details_page.dart';
|
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|
||||||
class SavedViewList extends StatelessWidget {
|
class SavedViewList extends StatelessWidget {
|
||||||
@@ -23,7 +17,7 @@ class SavedViewList extends StatelessWidget {
|
|||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
return state.when(
|
return state.when(
|
||||||
initial: () => SliverToBoxAdapter(child: Container()),
|
initial: () => SliverToBoxAdapter(child: Container()),
|
||||||
loading: () => SliverToBoxAdapter(
|
loading: () => const SliverToBoxAdapter(
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Text("Saved views loading..."), //TODO: INTL
|
child: Text("Saved views loading..."), //TODO: INTL
|
||||||
),
|
),
|
||||||
@@ -55,7 +49,7 @@ class SavedViewList extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
error: () => Center(
|
error: () => const Center(
|
||||||
child: Text(
|
child: Text(
|
||||||
"An error occurred while trying to load the saved views.",
|
"An error occurred while trying to load the saved views.",
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
import 'package:hydrated_bloc/hydrated_bloc.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_app_state.dart';
|
||||||
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
import 'package:paperless_mobile/core/notifier/document_changed_notifier.dart';
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import 'package:paperless_mobile/features/documents/view/widgets/selection/confi
|
|||||||
import 'package:paperless_mobile/features/documents/view/widgets/selection/view_type_selection_widget.dart';
|
import 'package:paperless_mobile/features/documents/view/widgets/selection/view_type_selection_widget.dart';
|
||||||
import 'package:paperless_mobile/features/paged_document_view/view/document_paging_view_mixin.dart';
|
import 'package:paperless_mobile/features/paged_document_view/view/document_paging_view_mixin.dart';
|
||||||
import 'package:paperless_mobile/features/saved_view_details/cubit/saved_view_details_cubit.dart';
|
import 'package:paperless_mobile/features/saved_view_details/cubit/saved_view_details_cubit.dart';
|
||||||
import 'package:paperless_mobile/routes/document_details_route.dart';
|
|
||||||
|
|
||||||
class SavedViewDetailsPage extends StatefulWidget {
|
class SavedViewDetailsPage extends StatefulWidget {
|
||||||
final Future<void> Function(SavedView savedView) onDelete;
|
final Future<void> Function(SavedView savedView) onDelete;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:hive_flutter/adapters.dart';
|
import 'package:hive_flutter/adapters.dart';
|
||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
||||||
@@ -49,7 +48,6 @@ class ManageAccountsPage extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
_buildAccountTile(context, globalSettings.currentLoggedInUser!,
|
_buildAccountTile(context, globalSettings.currentLoggedInUser!,
|
||||||
box.get(globalSettings.currentLoggedInUser!)!, globalSettings),
|
box.get(globalSettings.currentLoggedInUser!)!, globalSettings),
|
||||||
// if (otherAccounts.isNotEmpty) Text("Other accounts"),
|
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
for (int index = 0; index < otherAccounts.length; index++)
|
for (int index = 0; index < otherAccounts.length; index++)
|
||||||
@@ -69,17 +67,11 @@ class ManageAccountsPage extends StatelessWidget {
|
|||||||
_onAddAccount(context, globalSettings.currentLoggedInUser!);
|
_onAddAccount(context, globalSettings.currentLoggedInUser!);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
Consumer<ApiVersion>(
|
if (context.watch<ApiVersion>().hasMultiUserSupport)
|
||||||
builder: (context, value, child) {
|
const ListTile(
|
||||||
if (value.version >= 3) {
|
|
||||||
return const ListTile(
|
|
||||||
leading: Icon(Icons.admin_panel_settings),
|
leading: Icon(Icons.admin_panel_settings),
|
||||||
title: Text("Manage permissions"), //TODO : INTL
|
title: Text("Manage permissions"), //TODO: INTL
|
||||||
);
|
),
|
||||||
}
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
},
|
|
||||||
)
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -106,9 +98,7 @@ class ManageAccountsPage extends StatelessWidget {
|
|||||||
if (account.paperlessUser.fullName != null) Text(account.paperlessUser.fullName!),
|
if (account.paperlessUser.fullName != null) Text(account.paperlessUser.fullName!),
|
||||||
Text(
|
Text(
|
||||||
account.serverUrl.replaceFirst(RegExp(r'https://?'), ''),
|
account.serverUrl.replaceFirst(RegExp(r'https://?'), ''),
|
||||||
style: TextStyle(
|
style: TextStyle(color: theme.colorScheme.primary),
|
||||||
color: Theme.of(context).colorScheme.primary,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -10,10 +10,10 @@ class SecuritySettingsPage extends StatelessWidget {
|
|||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text(S.of(context)!.security),
|
title: Text(S.of(context)!.security),
|
||||||
actions: [
|
actions: const [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.all(16.0),
|
padding: EdgeInsets.all(16.0),
|
||||||
child: const Icon(Icons.person_outline),
|
child: Icon(Icons.person_outline),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ class ClearCacheSetting extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text("Clear downloaded files"), //TODO: INTL
|
title: const Text("Clear downloaded files"), //TODO: INTL
|
||||||
subtitle:
|
subtitle:
|
||||||
Text("Deletes all files downloaded from this app."), //TODO: INTL
|
const Text("Deletes all files downloaded from this app."), //TODO: INTL
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final dir = await FileService.downloadsDirectory;
|
final dir = await FileService.downloadsDirectory;
|
||||||
final deletedSize = _dirSize(dir);
|
final deletedSize = _dirSize(dir);
|
||||||
@@ -36,8 +36,8 @@ class ClearDownloadsSetting extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ListTile(
|
return ListTile(
|
||||||
title: Text("Clear downloads"), //TODO: INTL
|
title: const Text("Clear downloads"), //TODO: INTL
|
||||||
subtitle: Text(
|
subtitle: const Text(
|
||||||
"Remove downloaded files, scans and clear the cache's content"), //TODO: INTL
|
"Remove downloaded files, scans and clear the cache's content"), //TODO: INTL
|
||||||
onTap: () {
|
onTap: () {
|
||||||
FileService.documentsDirectory;
|
FileService.documentsDirectory;
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:hive_flutter/adapters.dart';
|
|
||||||
import 'package:paperless_mobile/constants.dart';
|
import 'package:paperless_mobile/constants.dart';
|
||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
|
||||||
import 'package:paperless_mobile/core/translation/color_scheme_option_localization_mapper.dart';
|
import 'package:paperless_mobile/core/translation/color_scheme_option_localization_mapper.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/hint_card.dart';
|
import 'package:paperless_mobile/core/widgets/hint_card.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
|
||||||
import 'package:paperless_mobile/features/settings/model/color_scheme_option.dart';
|
import 'package:paperless_mobile/features/settings/model/color_scheme_option.dart';
|
||||||
import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart';
|
import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart';
|
||||||
import 'package:paperless_mobile/features/settings/view/widgets/radio_settings_dialog.dart';
|
import 'package:paperless_mobile/features/settings/view/widgets/radio_settings_dialog.dart';
|
||||||
@@ -69,7 +65,7 @@ class ColorSchemeOptionSetting extends StatelessWidget {
|
|||||||
|
|
||||||
bool _isBelowAndroid12() {
|
bool _isBelowAndroid12() {
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
final int version = int.tryParse(androidInfo!.version.release ?? '0') ?? 0;
|
final int version = int.tryParse(androidInfo!.version.release) ?? 0;
|
||||||
return version < 12;
|
return version < 12;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/src/widgets/framework.dart';
|
|
||||||
import 'package:flutter/src/widgets/placeholder.dart';
|
|
||||||
import 'package:hive_flutter/adapters.dart';
|
import 'package:hive_flutter/adapters.dart';
|
||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_cancel_button.dart';
|
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_cancel_button.dart';
|
||||||
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_confirm_button.dart';
|
import 'package:paperless_mobile/core/widgets/dialog_utils/dialog_confirm_button.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class RadioSettingsDialog<T> extends StatefulWidget {
|
class RadioSettingsDialog<T> extends StatefulWidget {
|
||||||
final List<RadioOption<T>> options;
|
final List<RadioOption<T>> options;
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart';
|
import 'package:paperless_mobile/features/settings/view/widgets/global_settings_builder.dart';
|
||||||
import 'package:paperless_mobile/features/settings/view/widgets/radio_settings_dialog.dart';
|
import 'package:paperless_mobile/features/settings/view/widgets/radio_settings_dialog.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/repository/user_repository.dart';
|
|
||||||
|
|
||||||
class UserAvatar extends StatelessWidget {
|
class UserAvatar extends StatelessWidget {
|
||||||
final String userId;
|
final String userId;
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ import 'package:hive_flutter/adapters.dart';
|
|||||||
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
import 'package:paperless_mobile/core/config/hive/hive_config.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
import 'package:paperless_mobile/core/database/tables/local_user_account.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
import 'package:paperless_mobile/core/database/tables/global_settings.dart';
|
||||||
import 'package:paperless_mobile/core/database/tables/local_user_settings.dart';
|
|
||||||
|
|
||||||
class UserAccountBuilder extends StatelessWidget {
|
class UserAccountBuilder extends StatelessWidget {
|
||||||
final Widget Function(
|
final Widget Function(
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import 'dart:collection';
|
import 'dart:collection';
|
||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
import 'package:receive_sharing_intent/receive_sharing_intent.dart';
|
||||||
|
|||||||
@@ -2,9 +2,7 @@ import 'dart:developer';
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_mobile/core/service/github_issue_service.dart';
|
|
||||||
import 'package:paperless_mobile/core/translation/error_code_localization_mapper.dart';
|
import 'package:paperless_mobile/core/translation/error_code_localization_mapper.dart';
|
||||||
import 'package:paperless_mobile/generated/l10n/app_localizations.dart';
|
|
||||||
|
|
||||||
class SnackBarActionConfig {
|
class SnackBarActionConfig {
|
||||||
final String label;
|
final String label;
|
||||||
@@ -67,13 +65,13 @@ void showGenericError(
|
|||||||
showSnackBar(
|
showSnackBar(
|
||||||
context,
|
context,
|
||||||
error.toString(),
|
error.toString(),
|
||||||
action: SnackBarActionConfig(
|
// action: SnackBarActionConfig(
|
||||||
label: S.of(context)!.report,
|
// label: S.of(context)!.report,
|
||||||
onPressed: () => GithubIssueService.createIssueFromError(
|
// onPressed: () => GithubIssueService.createIssueFromError(
|
||||||
context,
|
// context,
|
||||||
stackTrace: stackTrace,
|
// stackTrace: stackTrace,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
);
|
);
|
||||||
log(
|
log(
|
||||||
"An error has occurred.",
|
"An error has occurred.",
|
||||||
|
|||||||
+12
-12
@@ -1,3 +1,4 @@
|
|||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:connectivity_plus/connectivity_plus.dart';
|
import 'package:connectivity_plus/connectivity_plus.dart';
|
||||||
@@ -56,10 +57,8 @@ String get defaultPreferredLocaleSubtag {
|
|||||||
|
|
||||||
Future<void> _initHive() async {
|
Future<void> _initHive() async {
|
||||||
await Hive.initFlutter();
|
await Hive.initFlutter();
|
||||||
// //TODO: REMOVE!
|
|
||||||
// await getApplicationDocumentsDirectory().then((value) => value.delete(recursive: true));
|
|
||||||
|
|
||||||
registerHiveAdapters();
|
registerHiveAdapters();
|
||||||
|
// await getApplicationDocumentsDirectory().then((value) => value.deleteSync(recursive: true));
|
||||||
await Hive.openBox<LocalUserAccount>(HiveBoxes.localUserAccount);
|
await Hive.openBox<LocalUserAccount>(HiveBoxes.localUserAccount);
|
||||||
await Hive.openBox<LocalUserAppState>(HiveBoxes.localUserAppState);
|
await Hive.openBox<LocalUserAppState>(HiveBoxes.localUserAppState);
|
||||||
final globalSettingsBox = await Hive.openBox<GlobalSettings>(HiveBoxes.globalSettings);
|
final globalSettingsBox = await Hive.openBox<GlobalSettings>(HiveBoxes.globalSettings);
|
||||||
@@ -126,9 +125,7 @@ void main() async {
|
|||||||
providers: [
|
providers: [
|
||||||
ChangeNotifierProvider.value(value: sessionManager),
|
ChangeNotifierProvider.value(value: sessionManager),
|
||||||
Provider<LocalAuthenticationService>.value(value: localAuthService),
|
Provider<LocalAuthenticationService>.value(value: localAuthService),
|
||||||
Provider<ConnectivityStatusService>.value(
|
Provider<ConnectivityStatusService>.value(value: connectivityStatusService),
|
||||||
value: connectivityStatusService,
|
|
||||||
),
|
|
||||||
Provider<LocalNotificationService>.value(value: localNotificationService),
|
Provider<LocalNotificationService>.value(value: localNotificationService),
|
||||||
Provider.value(value: DocumentChangedNotifier()),
|
Provider.value(value: DocumentChangedNotifier()),
|
||||||
],
|
],
|
||||||
@@ -136,12 +133,7 @@ void main() async {
|
|||||||
providers: [
|
providers: [
|
||||||
BlocProvider<ConnectivityCubit>.value(value: connectivityCubit),
|
BlocProvider<ConnectivityCubit>.value(value: connectivityCubit),
|
||||||
BlocProvider(
|
BlocProvider(
|
||||||
create: (context) => AuthenticationCubit(
|
create: (context) => AuthenticationCubit(localAuthService, apiFactory, sessionManager),
|
||||||
localAuthService,
|
|
||||||
apiFactory,
|
|
||||||
sessionManager,
|
|
||||||
),
|
|
||||||
child: Container(),
|
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
child: PaperlessMobileEntrypoint(
|
child: PaperlessMobileEntrypoint(
|
||||||
@@ -215,6 +207,7 @@ class AuthenticationWrapper extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
|
class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
|
||||||
|
late final StreamSubscription _shareMediaSubscription;
|
||||||
@override
|
@override
|
||||||
void didChangeDependencies() {
|
void didChangeDependencies() {
|
||||||
super.didChangeDependencies();
|
super.didChangeDependencies();
|
||||||
@@ -223,6 +216,12 @@ class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_shareMediaSubscription.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
@@ -233,6 +232,7 @@ class _AuthenticationWrapperState extends State<AuthenticationWrapper> {
|
|||||||
}
|
}
|
||||||
initializeDateFormatting();
|
initializeDateFormatting();
|
||||||
// For sharing files coming from outside the app while the app is still opened
|
// For sharing files coming from outside the app while the app is still opened
|
||||||
|
_shareMediaSubscription =
|
||||||
ReceiveSharingIntent.getMediaStream().listen(ShareIntentQueue.instance.addAll);
|
ReceiveSharingIntent.getMediaStream().listen(ShareIntentQueue.instance.addAll);
|
||||||
// For sharing files coming from outside the app while the app is closed
|
// For sharing files coming from outside the app while the app is closed
|
||||||
ReceiveSharingIntent.getInitialMedia().then(ShareIntentQueue.instance.addAll);
|
ReceiveSharingIntent.getInitialMedia().then(ShareIntentQueue.instance.addAll);
|
||||||
|
|||||||
+1
-1
@@ -43,7 +43,7 @@ ThemeData buildTheme({
|
|||||||
inputDecorationTheme: _defaultInputDecorationTheme,
|
inputDecorationTheme: _defaultInputDecorationTheme,
|
||||||
listTileTheme: _defaultListTileTheme,
|
listTileTheme: _defaultListTileTheme,
|
||||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||||
appBarTheme: AppBarTheme(
|
appBarTheme: const AppBarTheme(
|
||||||
scrolledUnderElevation: 0,
|
scrolledUnderElevation: 0,
|
||||||
),
|
),
|
||||||
chipTheme: ChipThemeData(
|
chipTheme: ChipThemeData(
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_api/src/models/user_model.dart';
|
|
||||||
|
|
||||||
class PaperlessApiHiveTypeIds {
|
class PaperlessApiHiveTypeIds {
|
||||||
PaperlessApiHiveTypeIds._();
|
PaperlessApiHiveTypeIds._();
|
||||||
@@ -56,7 +55,6 @@ void registerPaperlessApiHiveTypeAdapters() {
|
|||||||
// Users and permissions
|
// Users and permissions
|
||||||
Hive.registerAdapter(UserModelV3Adapter());
|
Hive.registerAdapter(UserModelV3Adapter());
|
||||||
Hive.registerAdapter(UserModelV2Adapter());
|
Hive.registerAdapter(UserModelV2Adapter());
|
||||||
Hive.registerAdapter(UserPermissionsAdapter());
|
|
||||||
Hive.registerAdapter(InheritedPermissionsAdapter());
|
Hive.registerAdapter(InheritedPermissionsAdapter());
|
||||||
Hive.registerAdapter(GroupModelAdapter());
|
Hive.registerAdapter(GroupModelAdapter());
|
||||||
Hive.registerAdapter(PermissionsAdapter());
|
Hive.registerAdapter(PermissionsAdapter());
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:paperless_api/src/models/models.dart';
|
import 'package:paperless_api/src/models/models.dart';
|
||||||
import 'package:paperless_api/src/models/query_parameters/date_range_queries/absolute_date_range_query.dart';
|
|
||||||
import 'package:paperless_api/src/models/query_parameters/date_range_queries/relative_date_range_query.dart';
|
|
||||||
|
|
||||||
class DateRangeQueryJsonConverter
|
class DateRangeQueryJsonConverter
|
||||||
extends JsonConverter<DateRangeQuery, Map<String, dynamic>> {
|
extends JsonConverter<DateRangeQuery, Map<String, dynamic>> {
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
// ignore_for_file: unused_field
|
||||||
|
|
||||||
import 'package:equatable/equatable.dart';
|
import 'package:equatable/equatable.dart';
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:paperless_api/paperless_api.dart';
|
import 'package:paperless_api/paperless_api.dart';
|
||||||
import 'package:paperless_api/src/constants.dart';
|
import 'package:paperless_api/src/constants.dart';
|
||||||
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
import 'package:paperless_api/src/converters/local_date_time_json_converter.dart';
|
||||||
import 'package:paperless_api/src/models/query_parameters/tags_query/tags_query.dart';
|
|
||||||
|
|
||||||
part 'filter_rule_model.g.dart';
|
part 'filter_rule_model.g.dart';
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ class GroupModel with _$GroupModel {
|
|||||||
const factory GroupModel({
|
const factory GroupModel({
|
||||||
@HiveField(0) required int id,
|
@HiveField(0) required int id,
|
||||||
@HiveField(1) required String name,
|
@HiveField(1) required String name,
|
||||||
@HiveField(2) required List<UserPermissions> permissions,
|
@HiveField(2) required List<String> permissions,
|
||||||
}) = _GroupModel;
|
}) = _GroupModel;
|
||||||
|
|
||||||
factory GroupModel.fromJson(Map<String, dynamic> json) => _$GroupModelFromJson(json);
|
factory GroupModel.fromJson(Map<String, dynamic> json) => _$GroupModelFromJson(json);
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ mixin _$GroupModel {
|
|||||||
@HiveField(1)
|
@HiveField(1)
|
||||||
String get name => throw _privateConstructorUsedError;
|
String get name => throw _privateConstructorUsedError;
|
||||||
@HiveField(2)
|
@HiveField(2)
|
||||||
List<UserPermissions> get permissions => throw _privateConstructorUsedError;
|
List<String> get permissions => throw _privateConstructorUsedError;
|
||||||
|
|
||||||
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
Map<String, dynamic> toJson() => throw _privateConstructorUsedError;
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
@@ -42,7 +42,7 @@ abstract class $GroupModelCopyWith<$Res> {
|
|||||||
$Res call(
|
$Res call(
|
||||||
{@HiveField(0) int id,
|
{@HiveField(0) int id,
|
||||||
@HiveField(1) String name,
|
@HiveField(1) String name,
|
||||||
@HiveField(2) List<UserPermissions> permissions});
|
@HiveField(2) List<String> permissions});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -74,7 +74,7 @@ class _$GroupModelCopyWithImpl<$Res, $Val extends GroupModel>
|
|||||||
permissions: null == permissions
|
permissions: null == permissions
|
||||||
? _value.permissions
|
? _value.permissions
|
||||||
: permissions // ignore: cast_nullable_to_non_nullable
|
: permissions // ignore: cast_nullable_to_non_nullable
|
||||||
as List<UserPermissions>,
|
as List<String>,
|
||||||
) as $Val);
|
) as $Val);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -90,7 +90,7 @@ abstract class _$$_GroupModelCopyWith<$Res>
|
|||||||
$Res call(
|
$Res call(
|
||||||
{@HiveField(0) int id,
|
{@HiveField(0) int id,
|
||||||
@HiveField(1) String name,
|
@HiveField(1) String name,
|
||||||
@HiveField(2) List<UserPermissions> permissions});
|
@HiveField(2) List<String> permissions});
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @nodoc
|
/// @nodoc
|
||||||
@@ -120,7 +120,7 @@ class __$$_GroupModelCopyWithImpl<$Res>
|
|||||||
permissions: null == permissions
|
permissions: null == permissions
|
||||||
? _value._permissions
|
? _value._permissions
|
||||||
: permissions // ignore: cast_nullable_to_non_nullable
|
: permissions // ignore: cast_nullable_to_non_nullable
|
||||||
as List<UserPermissions>,
|
as List<String>,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -131,7 +131,7 @@ class _$_GroupModel implements _GroupModel {
|
|||||||
const _$_GroupModel(
|
const _$_GroupModel(
|
||||||
{@HiveField(0) required this.id,
|
{@HiveField(0) required this.id,
|
||||||
@HiveField(1) required this.name,
|
@HiveField(1) required this.name,
|
||||||
@HiveField(2) required final List<UserPermissions> permissions})
|
@HiveField(2) required final List<String> permissions})
|
||||||
: _permissions = permissions;
|
: _permissions = permissions;
|
||||||
|
|
||||||
factory _$_GroupModel.fromJson(Map<String, dynamic> json) =>
|
factory _$_GroupModel.fromJson(Map<String, dynamic> json) =>
|
||||||
@@ -143,10 +143,10 @@ class _$_GroupModel implements _GroupModel {
|
|||||||
@override
|
@override
|
||||||
@HiveField(1)
|
@HiveField(1)
|
||||||
final String name;
|
final String name;
|
||||||
final List<UserPermissions> _permissions;
|
final List<String> _permissions;
|
||||||
@override
|
@override
|
||||||
@HiveField(2)
|
@HiveField(2)
|
||||||
List<UserPermissions> get permissions {
|
List<String> get permissions {
|
||||||
if (_permissions is EqualUnmodifiableListView) return _permissions;
|
if (_permissions is EqualUnmodifiableListView) return _permissions;
|
||||||
// ignore: implicit_dynamic_type
|
// ignore: implicit_dynamic_type
|
||||||
return EqualUnmodifiableListView(_permissions);
|
return EqualUnmodifiableListView(_permissions);
|
||||||
@@ -191,8 +191,7 @@ abstract class _GroupModel implements GroupModel {
|
|||||||
const factory _GroupModel(
|
const factory _GroupModel(
|
||||||
{@HiveField(0) required final int id,
|
{@HiveField(0) required final int id,
|
||||||
@HiveField(1) required final String name,
|
@HiveField(1) required final String name,
|
||||||
@HiveField(2) required final List<UserPermissions> permissions}) =
|
@HiveField(2) required final List<String> permissions}) = _$_GroupModel;
|
||||||
_$_GroupModel;
|
|
||||||
|
|
||||||
factory _GroupModel.fromJson(Map<String, dynamic> json) =
|
factory _GroupModel.fromJson(Map<String, dynamic> json) =
|
||||||
_$_GroupModel.fromJson;
|
_$_GroupModel.fromJson;
|
||||||
@@ -205,7 +204,7 @@ abstract class _GroupModel implements GroupModel {
|
|||||||
String get name;
|
String get name;
|
||||||
@override
|
@override
|
||||||
@HiveField(2)
|
@HiveField(2)
|
||||||
List<UserPermissions> get permissions;
|
List<String> get permissions;
|
||||||
@override
|
@override
|
||||||
@JsonKey(ignore: true)
|
@JsonKey(ignore: true)
|
||||||
_$$_GroupModelCopyWith<_$_GroupModel> get copyWith =>
|
_$$_GroupModelCopyWith<_$_GroupModel> get copyWith =>
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import 'dart:developer';
|
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:flutter/foundation.dart';
|
|
||||||
import 'package:json_annotation/json_annotation.dart';
|
import 'package:json_annotation/json_annotation.dart';
|
||||||
import 'package:paperless_api/src/converters/hex_color_json_converter.dart';
|
import 'package:paperless_api/src/converters/hex_color_json_converter.dart';
|
||||||
import 'package:paperless_api/src/models/labels/label_model.dart';
|
import 'package:paperless_api/src/models/labels/label_model.dart';
|
||||||
@@ -24,7 +22,7 @@ class Tag extends Label {
|
|||||||
|
|
||||||
final bool isInboxTag;
|
final bool isInboxTag;
|
||||||
|
|
||||||
Tag({
|
const Tag({
|
||||||
super.id,
|
super.id,
|
||||||
required super.name,
|
required super.name,
|
||||||
super.documentCount,
|
super.documentCount,
|
||||||
|
|||||||
@@ -53,6 +53,5 @@ enum ErrorCode {
|
|||||||
requestTimedOut,
|
requestTimedOut,
|
||||||
unsupportedFileFormat,
|
unsupportedFileFormat,
|
||||||
missingClientCertificate,
|
missingClientCertificate,
|
||||||
acknowledgeTasksError,
|
acknowledgeTasksError;
|
||||||
notAuthorized;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,117 +1,30 @@
|
|||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
enum PermissionAction {
|
||||||
import 'package:hive/hive.dart';
|
add("add"),
|
||||||
import 'package:paperless_api/config/hive/hive_type_ids.dart';
|
change("change"),
|
||||||
part 'user_permissions.g.dart';
|
delete("delete"),
|
||||||
|
view("view");
|
||||||
@HiveType(typeId: PaperlessApiHiveTypeIds.userPermissions)
|
|
||||||
@JsonEnum(valueField: "value")
|
|
||||||
enum UserPermissions {
|
|
||||||
@HiveField(0)
|
|
||||||
addCorrespondent("add_correspondent"),
|
|
||||||
@HiveField(1)
|
|
||||||
addDocument("add_document"),
|
|
||||||
@HiveField(2)
|
|
||||||
addDocumenttype("add_documenttype"),
|
|
||||||
@HiveField(3)
|
|
||||||
addGroup("add_group"),
|
|
||||||
@HiveField(4)
|
|
||||||
addMailaccount("add_mailaccount"),
|
|
||||||
@HiveField(5)
|
|
||||||
addMailrule("add_mailrule"),
|
|
||||||
@HiveField(6)
|
|
||||||
addNote("add_note"),
|
|
||||||
@HiveField(7)
|
|
||||||
addPaperlesstask("add_paperlesstask"),
|
|
||||||
@HiveField(8)
|
|
||||||
addSavedview("add_savedview"),
|
|
||||||
@HiveField(9)
|
|
||||||
addStoragepath("add_storagepath"),
|
|
||||||
@HiveField(10)
|
|
||||||
addTag("add_tag"),
|
|
||||||
@HiveField(11)
|
|
||||||
addUisettings("add_uisettings"),
|
|
||||||
@HiveField(12)
|
|
||||||
addUser("add_user"),
|
|
||||||
@HiveField(13)
|
|
||||||
changeCorrespondent("change_correspondent"),
|
|
||||||
@HiveField(14)
|
|
||||||
changeDocument("change_document"),
|
|
||||||
@HiveField(15)
|
|
||||||
changeDocumenttype("change_documenttype"),
|
|
||||||
@HiveField(16)
|
|
||||||
changeGroup("change_group"),
|
|
||||||
@HiveField(17)
|
|
||||||
changeMailaccount("change_mailaccount"),
|
|
||||||
@HiveField(18)
|
|
||||||
changeMailrule("change_mailrule"),
|
|
||||||
@HiveField(19)
|
|
||||||
changeNote("change_note"),
|
|
||||||
@HiveField(20)
|
|
||||||
changePaperlesstask("change_paperlesstask"),
|
|
||||||
@HiveField(21)
|
|
||||||
changeSavedview("change_savedview"),
|
|
||||||
@HiveField(22)
|
|
||||||
changeStoragepath("change_storagepath"),
|
|
||||||
@HiveField(23)
|
|
||||||
changeTag("change_tag"),
|
|
||||||
@HiveField(24)
|
|
||||||
changeUisettings("change_uisettings"),
|
|
||||||
@HiveField(25)
|
|
||||||
changeUser("change_user"),
|
|
||||||
@HiveField(26)
|
|
||||||
deleteCorrespondent("delete_correspondent"),
|
|
||||||
@HiveField(27)
|
|
||||||
deleteDocument("delete_document"),
|
|
||||||
@HiveField(28)
|
|
||||||
deleteDocumenttype("delete_documenttype"),
|
|
||||||
@HiveField(29)
|
|
||||||
deleteGroup("delete_group"),
|
|
||||||
@HiveField(30)
|
|
||||||
deleteMailaccount("delete_mailaccount"),
|
|
||||||
@HiveField(31)
|
|
||||||
deleteMailrule("delete_mailrule"),
|
|
||||||
@HiveField(32)
|
|
||||||
deleteNote("delete_note"),
|
|
||||||
@HiveField(33)
|
|
||||||
deletePaperlesstask("delete_paperlesstask"),
|
|
||||||
@HiveField(34)
|
|
||||||
deleteSavedview("delete_savedview"),
|
|
||||||
@HiveField(35)
|
|
||||||
deleteStoragepath("delete_storagepath"),
|
|
||||||
@HiveField(36)
|
|
||||||
deleteTag("delete_tag"),
|
|
||||||
@HiveField(37)
|
|
||||||
deleteUisettings("delete_uisettings"),
|
|
||||||
@HiveField(38)
|
|
||||||
deleteUser("delete_user"),
|
|
||||||
@HiveField(39)
|
|
||||||
viewCorrespondent("view_correspondent"),
|
|
||||||
@HiveField(40)
|
|
||||||
viewDocument("view_document"),
|
|
||||||
@HiveField(41)
|
|
||||||
viewDocumenttype("view_documenttype"),
|
|
||||||
@HiveField(42)
|
|
||||||
viewGroup("view_group"),
|
|
||||||
@HiveField(43)
|
|
||||||
viewMailaccount("view_mailaccount"),
|
|
||||||
@HiveField(44)
|
|
||||||
viewMailrule("view_mailrule"),
|
|
||||||
@HiveField(45)
|
|
||||||
viewNote("view_note"),
|
|
||||||
@HiveField(46)
|
|
||||||
viewPaperlesstask("view_paperlesstask"),
|
|
||||||
@HiveField(47)
|
|
||||||
viewSavedview("view_savedview"),
|
|
||||||
@HiveField(48)
|
|
||||||
viewStoragepath("view_storagepath"),
|
|
||||||
@HiveField(49)
|
|
||||||
viewTag("view_tag"),
|
|
||||||
@HiveField(50)
|
|
||||||
viewUisettings("view_uisettings"),
|
|
||||||
@HiveField(51)
|
|
||||||
viewUser("view_user");
|
|
||||||
|
|
||||||
const UserPermissions(this.value);
|
|
||||||
|
|
||||||
final String value;
|
final String value;
|
||||||
|
const PermissionAction(this.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
enum PermissionTarget {
|
||||||
|
correspondent("correspondent"),
|
||||||
|
document("document"),
|
||||||
|
documentType("documenttype"),
|
||||||
|
group("group"),
|
||||||
|
mailAccount("mailaccount"),
|
||||||
|
mailrule("mailrule"),
|
||||||
|
note("note"),
|
||||||
|
paperlesstask("paperlesstask"),
|
||||||
|
savedView("savedview"),
|
||||||
|
storagePath("storagepath"),
|
||||||
|
tag("tag"),
|
||||||
|
uiSettings("uisettings"),
|
||||||
|
user("user"),
|
||||||
|
logentry("logentry"),
|
||||||
|
permission("permission");
|
||||||
|
|
||||||
|
final String value;
|
||||||
|
const PermissionTarget(this.value);
|
||||||
}
|
}
|
||||||
|
|||||||
-1
@@ -1,5 +1,4 @@
|
|||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:paperless_api/config/hive/hive_type_ids.dart';
|
|
||||||
import 'package:paperless_api/src/models/query_parameters/date_range_queries/date_range_query_field.dart';
|
import 'package:paperless_api/src/models/query_parameters/date_range_queries/date_range_query_field.dart';
|
||||||
|
|
||||||
import 'date_range_query.dart';
|
import 'date_range_query.dart';
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user