Added translations, fixed chips theming

This commit is contained in:
Anton Stubenbord
2023-01-20 12:46:46 +01:00
parent f9dfddf704
commit fa3059218d
24 changed files with 399 additions and 270 deletions

View File

@@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
import 'package:paperless_api/paperless_api.dart'; import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/generated/l10n.dart';
String translateMatchingAlgorithm( String translateMatchingAlgorithmDescription(
BuildContext context, MatchingAlgorithm algorithm) { BuildContext context,
MatchingAlgorithm algorithm,
) {
switch (algorithm) { switch (algorithm) {
case MatchingAlgorithm.anyWord: case MatchingAlgorithm.anyWord:
return S.of(context).matchingAlgorithmAnyDescription; return S.of(context).matchingAlgorithmAnyDescription;
@@ -19,3 +21,23 @@ String translateMatchingAlgorithm(
return S.of(context).matchingAlgorithmAutoDescription; return S.of(context).matchingAlgorithmAutoDescription;
} }
} }
String translateMatchingAlgorithmName(
BuildContext context,
MatchingAlgorithm algorithm,
) {
switch (algorithm) {
case MatchingAlgorithm.anyWord:
return S.of(context).matchingAlgorithmAnyName;
case MatchingAlgorithm.allWords:
return S.of(context).matchingAlgorithmAllName;
case MatchingAlgorithm.exactMatch:
return S.of(context).matchingAlgorithmExactName;
case MatchingAlgorithm.regex:
return S.of(context).matchingAlgorithmRegexName;
case MatchingAlgorithm.fuzzy:
return S.of(context).matchingAlgorithmFuzzyName;
case MatchingAlgorithm.auto:
return S.of(context).matchingAlgorithmAutoName;
}
}

View File

@@ -1,5 +1,6 @@
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/workarounds/colored_chip.dart';
import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/generated/l10n.dart';
class RelativeDateRangePickerHelper extends StatefulWidget { class RelativeDateRangePickerHelper extends StatefulWidget {
@@ -28,7 +29,8 @@ class _RelativeDateRangePickerHelperState
separatorBuilder: (context, index) => const SizedBox(width: 8.0), separatorBuilder: (context, index) => const SizedBox(width: 8.0),
itemBuilder: (context, index) { itemBuilder: (context, index) {
final option = _options[index]; final option = _options[index];
return FilterChip( return ColoredChipWrapper(
child: FilterChip(
label: Text(option.title), label: Text(option.title),
onSelected: (isSelected) { onSelected: (isSelected) {
final value = final value =
@@ -37,6 +39,7 @@ class _RelativeDateRangePickerHelperState
widget.onChanged?.call(value); widget.onChanged?.call(value);
}, },
selected: widget.field.value == option.value, selected: widget.field.value == option.value,
),
); );
}, },
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,

View File

@@ -0,0 +1,23 @@
import 'package:flutter/material.dart';
class ColoredChipWrapper extends StatelessWidget {
final Color? backgroundColor;
final Widget child;
const ColoredChipWrapper({
super.key,
this.backgroundColor,
required this.child,
});
@override
Widget build(BuildContext context) {
Color color = backgroundColor ?? Colors.lightGreen[50]!;
return Theme(
data: Theme.of(context).copyWith(
canvasColor: color,
),
child: child,
);
}
}

View File

@@ -438,7 +438,6 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
child: TagsWidget( child: TagsWidget(
isClickable: widget.isLabelClickable, isClickable: widget.isLabelClickable,
tagIds: document.tags, tagIds: document.tags,
isSelectedPredicate: (_) => false,
onTagSelected: (int tagId) {}, onTagSelected: (int tagId) {},
), ),
), ),

View File

@@ -95,7 +95,7 @@ class DocumentsCubit extends HydratedCubit<DocumentsState>
} }
void unselectView() { void unselectView() {
emit(state.copyWith(selectedSavedViewId: null)); emit(state.copyWith(selectedSavedViewId: () => null));
} }
@override @override

View File

@@ -25,7 +25,7 @@ class DocumentsState extends DocumentsPagedState {
List<PagedSearchResult<DocumentModel>>? value, List<PagedSearchResult<DocumentModel>>? value,
DocumentFilter? filter, DocumentFilter? filter,
List<DocumentModel>? selection, List<DocumentModel>? selection,
int? selectedSavedViewId, int? Function()? selectedSavedViewId,
}) { }) {
return DocumentsState( return DocumentsState(
hasLoaded: hasLoaded ?? this.hasLoaded, hasLoaded: hasLoaded ?? this.hasLoaded,
@@ -33,7 +33,9 @@ class DocumentsState extends DocumentsPagedState {
value: value ?? this.value, value: value ?? this.value,
filter: filter ?? this.filter, filter: filter ?? this.filter,
selection: selection ?? this.selection, selection: selection ?? this.selection,
selectedSavedViewId: selectedSavedViewId ?? this.selectedSavedViewId, selectedSavedViewId: selectedSavedViewId != null
? selectedSavedViewId.call()
: this.selectedSavedViewId,
); );
} }

View File

@@ -11,6 +11,7 @@ import 'package:paperless_mobile/core/repository/label_repository.dart';
import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart'; import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart';
import 'package:paperless_mobile/core/repository/state/impl/document_type_repository_state.dart'; import 'package:paperless_mobile/core/repository/state/impl/document_type_repository_state.dart';
import 'package:paperless_mobile/core/repository/state/impl/storage_path_repository_state.dart'; import 'package:paperless_mobile/core/repository/state/impl/storage_path_repository_state.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';
import 'package:paperless_mobile/features/edit_document/cubit/edit_document_cubit.dart'; import 'package:paperless_mobile/features/edit_document/cubit/edit_document_cubit.dart';
import 'package:paperless_mobile/features/edit_label/view/impl/add_correspondent_page.dart'; import 'package:paperless_mobile/features/edit_label/view/impl/add_correspondent_page.dart';
@@ -305,6 +306,9 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
); );
} }
///
/// Item builder is typically some sort of [Chip].
///
Widget _buildSuggestionsSkeleton<T>({ Widget _buildSuggestionsSkeleton<T>({
required Iterable<T> suggestions, required Iterable<T> suggestions,
required ItemBuilder<T> itemBuilder, required ItemBuilder<T> itemBuilder,
@@ -321,8 +325,9 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
child: ListView.separated( child: ListView.separated(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
itemCount: suggestions.length, itemCount: suggestions.length,
itemBuilder: (context, index) => itemBuilder: (context, index) => ColoredChipWrapper(
itemBuilder(context, suggestions.elementAt(index)), child: itemBuilder(context, suggestions.elementAt(index)),
),
separatorBuilder: (BuildContext context, int index) => separatorBuilder: (BuildContext context, int index) =>
const SizedBox(width: 4.0), const SizedBox(width: 4.0),
), ),

View File

@@ -72,7 +72,6 @@ class DocumentGridItem extends StatelessWidget {
TagsWidget( TagsWidget(
tagIds: document.tags, tagIds: document.tags,
isMultiLine: false, isMultiLine: false,
isSelectedPredicate: isTagSelectedPredicate,
onTagSelected: onTagSelected, onTagSelected: onTagSelected,
), ),
const Spacer(), const Spacer(),

View File

@@ -73,7 +73,6 @@ class DocumentListItem extends StatelessWidget {
isClickable: isLabelClickable, isClickable: isLabelClickable,
tagIds: document.tags, tagIds: document.tags,
isMultiLine: false, isMultiLine: false,
isSelectedPredicate: isTagSelectedPredicate,
onTagSelected: (id) => onTagSelected?.call(id), onTagSelected: (id) => onTagSelected?.call(id),
), ),
), ),

View File

@@ -46,8 +46,17 @@ class LabelForm<T extends Label> extends StatefulWidget {
class _LabelFormState<T extends Label> extends State<LabelForm<T>> { class _LabelFormState<T extends Label> extends State<LabelForm<T>> {
final _formKey = GlobalKey<FormBuilderState>(); final _formKey = GlobalKey<FormBuilderState>();
late bool _enableMatchFormField;
PaperlessValidationErrors _errors = {}; PaperlessValidationErrors _errors = {};
@override
void initState() {
super.initState();
_enableMatchFormField =
widget.initialValue?.matchingAlgorithm != MatchingAlgorithm.auto;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Scaffold( return Scaffold(
@@ -71,15 +80,6 @@ class _LabelFormState<T extends Label> extends State<LabelForm<T>> {
initialValue: widget.initialValue?.name, initialValue: widget.initialValue?.name,
onChanged: (val) => setState(() => _errors = {}), onChanged: (val) => setState(() => _errors = {}),
), ),
FormBuilderTextField(
name: Label.matchKey,
decoration: InputDecoration(
labelText: S.of(context).labelMatchPropertyLabel,
errorText: _errors[Label.matchKey],
),
initialValue: widget.initialValue?.match,
onChanged: (val) => setState(() => _errors = {}),
),
FormBuilderDropdown<int?>( FormBuilderDropdown<int?>(
name: Label.matchingAlgorithmKey, name: Label.matchingAlgorithmKey,
initialValue: widget.initialValue?.matchingAlgorithm.value ?? initialValue: widget.initialValue?.matchingAlgorithm.value ??
@@ -88,16 +88,32 @@ class _LabelFormState<T extends Label> extends State<LabelForm<T>> {
labelText: S.of(context).labelMatchingAlgorithmPropertyLabel, labelText: S.of(context).labelMatchingAlgorithmPropertyLabel,
errorText: _errors[Label.matchingAlgorithmKey], errorText: _errors[Label.matchingAlgorithmKey],
), ),
onChanged: (val) => setState(() => _errors = {}), onChanged: (val) {
setState(() {
_errors = {};
_enableMatchFormField = val != MatchingAlgorithm.auto.value;
});
},
items: MatchingAlgorithm.values items: MatchingAlgorithm.values
.map( .map(
(algo) => DropdownMenuItem<int?>( (algo) => DropdownMenuItem<int?>(
child: Text(translateMatchingAlgorithm(context, algo)), child: Text(
translateMatchingAlgorithmDescription(context, algo)),
value: algo.value, value: algo.value,
), ),
) )
.toList(), .toList(),
), ),
if (_enableMatchFormField)
FormBuilderTextField(
name: Label.matchKey,
decoration: InputDecoration(
labelText: S.of(context).labelMatchPropertyLabel,
errorText: _errors[Label.matchKey],
),
initialValue: widget.initialValue?.match,
onChanged: (val) => setState(() => _errors = {}),
),
FormBuilderCheckbox( FormBuilderCheckbox(
name: Label.isInsensitiveKey, name: Label.isInsensitiveKey,
initialValue: widget.initialValue?.isInsensitive ?? true, initialValue: widget.initialValue?.isInsensitive ?? true,
@@ -117,6 +133,11 @@ class _LabelFormState<T extends Label> extends State<LabelForm<T>> {
...widget.initialValue?.toJson() ?? {}, ...widget.initialValue?.toJson() ?? {},
..._formKey.currentState!.value ..._formKey.currentState!.value
}; };
if (mergedJson[Label.matchingAlgorithmKey] ==
MatchingAlgorithm.auto.value) {
// If auto is selected, the match will be removed.
mergedJson[Label.matchKey] = '';
}
final createdLabel = await widget.submitButtonConfig final createdLabel = await widget.submitButtonConfig
.onSubmit(widget.fromJsonT(mergedJson)); .onSubmit(widget.fromJsonT(mergedJson));
Navigator.pop(context, createdLabel); Navigator.pop(context, createdLabel);

View File

@@ -219,7 +219,7 @@ class _InfoDrawerState extends State<InfoDrawer> {
], ],
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Theme.of(context).colorScheme.primaryContainer, color: Theme.of(context).colorScheme.surfaceVariant,
), ),
), ),
...[ ...[

View File

@@ -4,6 +4,7 @@ import 'package:paperless_api/paperless_api.dart';
import 'package:paperless_mobile/core/repository/provider/label_repositories_provider.dart'; import 'package:paperless_mobile/core/repository/provider/label_repositories_provider.dart';
import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart'; import 'package:paperless_mobile/core/repository/state/impl/correspondent_repository_state.dart';
import 'package:paperless_mobile/core/repository/state/impl/document_type_repository_state.dart'; import 'package:paperless_mobile/core/repository/state/impl/document_type_repository_state.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';
import 'package:paperless_mobile/features/document_details/bloc/document_details_cubit.dart'; import 'package:paperless_mobile/features/document_details/bloc/document_details_cubit.dart';
import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart'; import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart';
@@ -111,15 +112,16 @@ class _InboxItemState extends State<InboxItem> {
final actions = [ final actions = [
_buildAssignAsnAction(chipShape, context), _buildAssignAsnAction(chipShape, context),
const SizedBox(width: 4.0), const SizedBox(width: 4.0),
ActionChip( ColoredChipWrapper(
child: ActionChip(
avatar: const Icon(Icons.delete_outline), avatar: const Icon(Icons.delete_outline),
shape: chipShape, shape: chipShape,
label: const Text("Delete document"), label: const Text("Delete document"),
onPressed: () async { onPressed: () async {
final shouldDelete = await showDialog<bool>( final shouldDelete = await showDialog<bool>(
context: context, context: context,
builder: (context) => builder: (context) => DeleteDocumentConfirmationDialog(
DeleteDocumentConfirmationDialog(document: widget.document), document: widget.document),
) ?? ) ??
false; false;
if (shouldDelete) { if (shouldDelete) {
@@ -127,6 +129,7 @@ class _InboxItemState extends State<InboxItem> {
} }
}, },
), ),
),
]; ];
// return FutureBuilder<FieldSuggestions>( // return FutureBuilder<FieldSuggestions>(
// future: _fieldSuggestions, // future: _fieldSuggestions,
@@ -191,7 +194,8 @@ class _InboxItemState extends State<InboxItem> {
BuildContext context, BuildContext context,
) { ) {
final hasAsn = widget.document.archiveSerialNumber != null; final hasAsn = widget.document.archiveSerialNumber != null;
return ActionChip( return ColoredChipWrapper(
child: ActionChip(
avatar: _isAsnAssignLoading avatar: _isAsnAssignLoading
? const CircularProgressIndicator() ? const CircularProgressIndicator()
: hasAsn : hasAsn
@@ -216,6 +220,7 @@ class _InboxItemState extends State<InboxItem> {
); );
} }
: null, : null,
),
); );
} }
@@ -224,7 +229,6 @@ class _InboxItemState extends State<InboxItem> {
tagIds: widget.document.tags, tagIds: widget.document.tags,
isMultiLine: false, isMultiLine: false,
isClickable: false, isClickable: false,
isSelectedPredicate: (_) => false,
showShortNames: true, showShortNames: true,
dense: true, dense: true,
); );

View File

@@ -1,6 +1,7 @@
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:form_builder_validators/form_builder_validators.dart'; import 'package:form_builder_validators/form_builder_validators.dart';
import 'package:paperless_mobile/core/workarounds/colored_chip.dart';
import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/generated/l10n.dart';
class StoragePathAutofillFormBuilderField extends StatefulWidget { class StoragePathAutofillFormBuilderField extends StatefulWidget {
@@ -61,23 +62,27 @@ class _StoragePathAutofillFormBuilderFieldState
"Select to autofill path variable", "Select to autofill path variable",
style: Theme.of(context).textTheme.bodySmall, style: Theme.of(context).textTheme.bodySmall,
), ),
Wrap( ColoredChipWrapper(
child: Wrap(
alignment: WrapAlignment.start, alignment: WrapAlignment.start,
spacing: 4.0, spacing: 4.0,
runSpacing: 4.0, runSpacing: 4.0,
children: [ children: [
InputChip( InputChip(
label: Text( label: Text(S
S.of(context).documentArchiveSerialNumberPropertyLongLabel), .of(context)
.documentArchiveSerialNumberPropertyLongLabel),
onPressed: () => _addParameterToInput("{asn}", field), onPressed: () => _addParameterToInput("{asn}", field),
), ),
InputChip( InputChip(
label: Text(S.of(context).documentCorrespondentPropertyLabel), label: Text(S.of(context).documentCorrespondentPropertyLabel),
onPressed: () => _addParameterToInput("{correspondent}", field), onPressed: () =>
_addParameterToInput("{correspondent}", field),
), ),
InputChip( InputChip(
label: Text(S.of(context).documentDocumentTypePropertyLabel), label: Text(S.of(context).documentDocumentTypePropertyLabel),
onPressed: () => _addParameterToInput("{document_type}", field), onPressed: () =>
_addParameterToInput("{document_type}", field),
), ),
InputChip( InputChip(
label: Text(S.of(context).documentTagsPropertyLabel), label: Text(S.of(context).documentTagsPropertyLabel),
@@ -94,12 +99,14 @@ class _StoragePathAutofillFormBuilderFieldState
InputChip( InputChip(
label: Text(S.of(context).documentCreatedPropertyLabel + label: Text(S.of(context).documentCreatedPropertyLabel +
" (${S.of(context).storagePathParameterYearLabel})"), " (${S.of(context).storagePathParameterYearLabel})"),
onPressed: () => _addParameterToInput("{created_year}", field), onPressed: () =>
_addParameterToInput("{created_year}", field),
), ),
InputChip( InputChip(
label: Text(S.of(context).documentCreatedPropertyLabel + label: Text(S.of(context).documentCreatedPropertyLabel +
" (${S.of(context).storagePathParameterMonthLabel})"), " (${S.of(context).storagePathParameterMonthLabel})"),
onPressed: () => _addParameterToInput("{created_month}", field), onPressed: () =>
_addParameterToInput("{created_month}", field),
), ),
InputChip( InputChip(
label: Text(S.of(context).documentCreatedPropertyLabel + label: Text(S.of(context).documentCreatedPropertyLabel +
@@ -126,6 +133,7 @@ class _StoragePathAutofillFormBuilderFieldState
onPressed: () => _addParameterToInput("{added_day}", field), onPressed: () => _addParameterToInput("{added_day}", field),
), ),
], ],
),
) )
], ],
), ),

View File

@@ -1,11 +1,10 @@
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/workarounds/colored_chip.dart';
class TagWidget extends StatelessWidget { class TagWidget extends StatelessWidget {
final Tag tag; final Tag tag;
final VoidCallback? afterTagTapped;
final VoidCallback onSelected; final VoidCallback onSelected;
final bool isSelected;
final bool isClickable; final bool isClickable;
final bool showShortName; final bool showShortName;
final bool dense; final bool dense;
@@ -13,10 +12,8 @@ class TagWidget extends StatelessWidget {
const TagWidget({ const TagWidget({
super.key, super.key,
required this.tag, required this.tag,
required this.afterTagTapped,
this.isClickable = true, this.isClickable = true,
required this.onSelected, required this.onSelected,
required this.isSelected,
this.showShortName = false, this.showShortName = false,
this.dense = false, this.dense = false,
}); });
@@ -27,11 +24,11 @@ class TagWidget extends StatelessWidget {
padding: const EdgeInsets.only(right: 4.0), padding: const EdgeInsets.only(right: 4.0),
child: AbsorbPointer( child: AbsorbPointer(
absorbing: !isClickable, absorbing: !isClickable,
child: ColoredChipWrapper(
child: FilterChip( child: FilterChip(
labelPadding: labelPadding:
dense ? const EdgeInsets.symmetric(horizontal: 2) : null, dense ? const EdgeInsets.symmetric(horizontal: 2) : null,
padding: dense ? const EdgeInsets.all(4) : null, padding: dense ? const EdgeInsets.all(4) : null,
selected: isSelected,
selectedColor: tag.color, selectedColor: tag.color,
onSelected: (_) => onSelected(), onSelected: (_) => onSelected(),
visualDensity: const VisualDensity(vertical: -2), visualDensity: const VisualDensity(vertical: -2),
@@ -47,6 +44,7 @@ class TagWidget extends StatelessWidget {
side: BorderSide.none, side: BorderSide.none,
), ),
), ),
),
); );
} }
} }

View File

@@ -7,6 +7,7 @@ import 'package:flutter_typeahead/flutter_typeahead.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';
import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.dart'; import 'package:paperless_mobile/core/repository/state/impl/tag_repository_state.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';
import 'package:paperless_mobile/features/edit_label/view/impl/add_tag_page.dart'; import 'package:paperless_mobile/features/edit_label/view/impl/add_tag_page.dart';
import 'package:paperless_mobile/generated/l10n.dart'; import 'package:paperless_mobile/generated/l10n.dart';
@@ -263,13 +264,15 @@ class _TagFormFieldState extends State<TagFormField> {
} }
Widget _buildNotAssignedTag(FormFieldState<TagsQuery> field) { Widget _buildNotAssignedTag(FormFieldState<TagsQuery> field) {
return InputChip( return ColoredChipWrapper(
child: InputChip(
label: Text( label: Text(
S.of(context).labelNotAssignedText, S.of(context).labelNotAssignedText,
), ),
backgroundColor: backgroundColor:
Theme.of(context).colorScheme.onSurface.withOpacity(0.12), Theme.of(context).colorScheme.onSurface.withOpacity(0.12),
onDeleted: () => field.didChange(const IdsTagsQuery()), onDeleted: () => field.didChange(const IdsTagsQuery()),
),
); );
} }
@@ -283,7 +286,8 @@ class _TagFormFieldState extends State<TagFormField> {
if (tag == null) { if (tag == null) {
return Container(); return Container();
} }
return InputChip( return ColoredChipWrapper(
child: InputChip(
label: Text( label: Text(
tag.name, tag.name,
style: TextStyle( style: TextStyle(
@@ -301,15 +305,18 @@ class _TagFormFieldState extends State<TagFormField> {
onDeleted: () => field.didChange( onDeleted: () => field.didChange(
(field.value as IdsTagsQuery).withIdsRemoved([tag.id!]), (field.value as IdsTagsQuery).withIdsRemoved([tag.id!]),
), ),
),
); );
} }
Widget _buildAnyAssignedTag(FormFieldState<TagsQuery> field) { Widget _buildAnyAssignedTag(FormFieldState<TagsQuery> field) {
return InputChip( return ColoredChipWrapper(
child: InputChip(
label: Text(S.of(context).labelAnyAssignedText), label: Text(S.of(context).labelAnyAssignedText),
backgroundColor: backgroundColor:
Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.12), Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.12),
onDeleted: () => field.didChange(const IdsTagsQuery()), onDeleted: () => field.didChange(const IdsTagsQuery()),
),
); );
} }
} }

View File

@@ -9,20 +9,16 @@ import 'package:paperless_mobile/features/labels/tags/view/widgets/tag_widget.da
class TagsWidget extends StatelessWidget { class TagsWidget extends StatelessWidget {
final Iterable<int> tagIds; final Iterable<int> tagIds;
final bool isMultiLine; final bool isMultiLine;
final VoidCallback? afterTagTapped;
final void Function(int tagId)? onTagSelected; final void Function(int tagId)? onTagSelected;
final bool isClickable; final bool isClickable;
final bool Function(int id) isSelectedPredicate;
final bool showShortNames; final bool showShortNames;
final bool dense; final bool dense;
const TagsWidget({ const TagsWidget({
Key? key, Key? key,
required this.tagIds, required this.tagIds,
this.afterTagTapped,
this.isMultiLine = true, this.isMultiLine = true,
this.isClickable = true, this.isClickable = true,
required this.isSelectedPredicate,
this.onTagSelected, this.onTagSelected,
this.showShortNames = false, this.showShortNames = false,
this.dense = true, this.dense = true,
@@ -38,9 +34,7 @@ class TagsWidget extends StatelessWidget {
.map( .map(
(id) => TagWidget( (id) => TagWidget(
tag: state.getLabel(id)!, tag: state.getLabel(id)!,
afterTagTapped: afterTagTapped,
isClickable: isClickable, isClickable: isClickable,
isSelected: isSelectedPredicate(id),
onSelected: () => onTagSelected?.call(id), onSelected: () => onTagSelected?.call(id),
showShortName: showShortNames, showShortName: showShortNames,
dense: dense, dense: dense,

View File

@@ -174,7 +174,6 @@ class _LabelsPageState extends State<LabelsPage>
) )
: null, : null,
), ),
contentBuilder: (t) => Text(t.match ?? ''),
emptyStateActionButtonLabel: emptyStateActionButtonLabel:
S.of(context).labelsPageTagsEmptyStateAddNewLabel, S.of(context).labelsPageTagsEmptyStateAddNewLabel,
emptyStateDescription: emptyStateDescription:

View File

@@ -68,21 +68,22 @@ class LabelTabView<T extends Label> extends StatelessWidget {
connectivityState.isConnected, connectivityState.isConnected,
child: ListView( child: ListView(
children: labels children: labels
.map( .map((l) => LabelItem<T>(
(l) => LabelItem<T>(
name: l.name, name: l.name,
content: contentBuilder?.call(l) ?? content: contentBuilder?.call(l) ??
Text( Text(
"${translateMatchingAlgorithm(context, l.matchingAlgorithm)}\n" translateMatchingAlgorithmName(
"${l.match}", context, l.matchingAlgorithm) +
((l.match?.isNotEmpty ?? false)
? ": ${l.match}"
: ""),
maxLines: 2, maxLines: 2,
), ),
onOpenEditPage: onEdit, onOpenEditPage: onEdit,
filterBuilder: filterBuilder, filterBuilder: filterBuilder,
leading: leadingBuilder?.call(l), leading: leadingBuilder?.call(l),
label: l, label: l,
), ))
)
.toList(), .toList(),
), ),
); );

View File

@@ -182,15 +182,15 @@ class SavedViewSelectionWidget extends StatelessWidget {
} }
void _onSelected( void _onSelected(
bool isSelected, bool selectionIntent,
BuildContext context, BuildContext context,
SavedView view, SavedView view,
) async { ) async {
if (isSelected) { if (selectionIntent) {
context.read<DocumentsCubit>().selectView(view.id!); context.read<DocumentsCubit>().selectView(view.id!);
} else { } else {
context.read<DocumentsCubit>().resetFilter();
context.read<DocumentsCubit>().unselectView(); context.read<DocumentsCubit>().unselectView();
context.read<DocumentsCubit>().resetFilter();
} }
} }

View File

@@ -1,6 +1,6 @@
{ {
"@@locale": "cs", "@@locale": "cs",
"aboutDialogDevelopedByText": "Vyvíjí", "aboutDialogDevelopedByText": "Vyvíjí {name}",
"@aboutDialogDevelopedByText": { "@aboutDialogDevelopedByText": {
"placeholders": { "placeholders": {
"name": {} "name": {}
@@ -490,16 +490,28 @@
"@loginPageUsernameValidatorMessageText": {}, "@loginPageUsernameValidatorMessageText": {},
"matchingAlgorithmAllDescription": "", "matchingAlgorithmAllDescription": "",
"@matchingAlgorithmAllDescription": {}, "@matchingAlgorithmAllDescription": {},
"matchingAlgorithmAllName": "",
"@matchingAlgorithmAllName": {},
"matchingAlgorithmAnyDescription": "", "matchingAlgorithmAnyDescription": "",
"@matchingAlgorithmAnyDescription": {}, "@matchingAlgorithmAnyDescription": {},
"matchingAlgorithmAnyName": "",
"@matchingAlgorithmAnyName": {},
"matchingAlgorithmAutoDescription": "", "matchingAlgorithmAutoDescription": "",
"@matchingAlgorithmAutoDescription": {}, "@matchingAlgorithmAutoDescription": {},
"matchingAlgorithmAutoName": "",
"@matchingAlgorithmAutoName": {},
"matchingAlgorithmExactDescription": "", "matchingAlgorithmExactDescription": "",
"@matchingAlgorithmExactDescription": {}, "@matchingAlgorithmExactDescription": {},
"matchingAlgorithmExactName": "",
"@matchingAlgorithmExactName": {},
"matchingAlgorithmFuzzyDescription": "", "matchingAlgorithmFuzzyDescription": "",
"@matchingAlgorithmFuzzyDescription": {}, "@matchingAlgorithmFuzzyDescription": {},
"matchingAlgorithmFuzzyName": "",
"@matchingAlgorithmFuzzyName": {},
"matchingAlgorithmRegexDescription": "", "matchingAlgorithmRegexDescription": "",
"@matchingAlgorithmRegexDescription": {}, "@matchingAlgorithmRegexDescription": {},
"matchingAlgorithmRegexName": "",
"@matchingAlgorithmRegexName": {},
"offlineWidgetText": "Nezdařilo se vytvořit připojení k internetu.", "offlineWidgetText": "Nezdařilo se vytvořit připojení k internetu.",
"@offlineWidgetText": {}, "@offlineWidgetText": {},
"onboardingDoneButtonLabel": "Hotovo", "onboardingDoneButtonLabel": "Hotovo",

View File

@@ -1,6 +1,6 @@
{ {
"@@locale": "de", "@@locale": "de",
"aboutDialogDevelopedByText": "Entwickelt von", "aboutDialogDevelopedByText": "Entwickelt von {name}",
"@aboutDialogDevelopedByText": { "@aboutDialogDevelopedByText": {
"placeholders": { "placeholders": {
"name": {} "name": {}
@@ -488,18 +488,30 @@
"@loginPageUsernameLabel": {}, "@loginPageUsernameLabel": {},
"loginPageUsernameValidatorMessageText": "Nutzername darf nicht leer sein.", "loginPageUsernameValidatorMessageText": "Nutzername darf nicht leer sein.",
"@loginPageUsernameValidatorMessageText": {}, "@loginPageUsernameValidatorMessageText": {},
"matchingAlgorithmAllDescription": "Alle: Dokument enthält alle folgenden Wörter", "matchingAlgorithmAllDescription": "Dokument enthält alle folgenden Wörter",
"@matchingAlgorithmAllDescription": {}, "@matchingAlgorithmAllDescription": {},
"matchingAlgorithmAnyDescription": "Irgendein Wort: Dokument enthält eins der folgenden Wörter", "matchingAlgorithmAllName": "Alle",
"@matchingAlgorithmAllName": {},
"matchingAlgorithmAnyDescription": "Dokument enthält eins der folgenden Wörter",
"@matchingAlgorithmAnyDescription": {}, "@matchingAlgorithmAnyDescription": {},
"matchingAlgorithmAutoDescription": "Auto: Zuweisung automatisch erlernen", "matchingAlgorithmAnyName": "Irgendein Wort",
"@matchingAlgorithmAnyName": {},
"matchingAlgorithmAutoDescription": "Zuweisung automatisch erlernen",
"@matchingAlgorithmAutoDescription": {}, "@matchingAlgorithmAutoDescription": {},
"matchingAlgorithmExactDescription": "Exakt: Dokument enthält die folgende Zeichenkette", "matchingAlgorithmAutoName": "Auto",
"@matchingAlgorithmAutoName": {},
"matchingAlgorithmExactDescription": "Dokument enthält die folgende Zeichenkette",
"@matchingAlgorithmExactDescription": {}, "@matchingAlgorithmExactDescription": {},
"matchingAlgorithmFuzzyDescription": "Ungenau: Dokument enthält ein zum folgenden Wort ähnliches Wort", "matchingAlgorithmExactName": "Exakt",
"@matchingAlgorithmExactName": {},
"matchingAlgorithmFuzzyDescription": "Dokument enthält ein zum folgenden Wort ähnliches Wort",
"@matchingAlgorithmFuzzyDescription": {}, "@matchingAlgorithmFuzzyDescription": {},
"matchingAlgorithmRegexDescription": "Regulärer Ausdruck: Dokument passt zum folgenden Ausdruck", "matchingAlgorithmFuzzyName": "Ungenau",
"@matchingAlgorithmFuzzyName": {},
"matchingAlgorithmRegexDescription": "Dokument passt zum folgenden Ausdruck",
"@matchingAlgorithmRegexDescription": {}, "@matchingAlgorithmRegexDescription": {},
"matchingAlgorithmRegexName": "Regulärer Ausdruck",
"@matchingAlgorithmRegexName": {},
"offlineWidgetText": "Es konte keine Verbindung zum Internet hergestellt werden.", "offlineWidgetText": "Es konte keine Verbindung zum Internet hergestellt werden.",
"@offlineWidgetText": {}, "@offlineWidgetText": {},
"onboardingDoneButtonLabel": "Fertig", "onboardingDoneButtonLabel": "Fertig",

View File

@@ -488,18 +488,30 @@
"@loginPageUsernameLabel": {}, "@loginPageUsernameLabel": {},
"loginPageUsernameValidatorMessageText": "Username must not be empty.", "loginPageUsernameValidatorMessageText": "Username must not be empty.",
"@loginPageUsernameValidatorMessageText": {}, "@loginPageUsernameValidatorMessageText": {},
"matchingAlgorithmAllDescription": "All: Document contains all of these words", "matchingAlgorithmAllDescription": "Document contains all of these words",
"@matchingAlgorithmAllDescription": {}, "@matchingAlgorithmAllDescription": {},
"matchingAlgorithmAnyDescription": "Any: Document contains any of these words", "matchingAlgorithmAllName": "All",
"@matchingAlgorithmAllName": {},
"matchingAlgorithmAnyDescription": "Document contains any of these words",
"@matchingAlgorithmAnyDescription": {}, "@matchingAlgorithmAnyDescription": {},
"matchingAlgorithmAutoDescription": "Auto: Learn matching automatically", "matchingAlgorithmAnyName": "Any",
"@matchingAlgorithmAnyName": {},
"matchingAlgorithmAutoDescription": "Learn matching automatically",
"@matchingAlgorithmAutoDescription": {}, "@matchingAlgorithmAutoDescription": {},
"matchingAlgorithmExactDescription": "Exact: Document contains this string", "matchingAlgorithmAutoName": "Auto",
"@matchingAlgorithmAutoName": {},
"matchingAlgorithmExactDescription": "Document contains this string",
"@matchingAlgorithmExactDescription": {}, "@matchingAlgorithmExactDescription": {},
"matchingAlgorithmFuzzyDescription": "Fuzzy: Document contains a word similar to this word", "matchingAlgorithmExactName": "Exact",
"@matchingAlgorithmExactName": {},
"matchingAlgorithmFuzzyDescription": "Document contains a word similar to this word",
"@matchingAlgorithmFuzzyDescription": {}, "@matchingAlgorithmFuzzyDescription": {},
"matchingAlgorithmRegexDescription": "Regular Expression: Document matches this regular expression", "matchingAlgorithmFuzzyName": "Fuzzy",
"@matchingAlgorithmFuzzyName": {},
"matchingAlgorithmRegexDescription": "Document matches this regular expression",
"@matchingAlgorithmRegexDescription": {}, "@matchingAlgorithmRegexDescription": {},
"matchingAlgorithmRegexName": "Regular Expression",
"@matchingAlgorithmRegexName": {},
"offlineWidgetText": "An internet connection could not be established.", "offlineWidgetText": "An internet connection could not be established.",
"@offlineWidgetText": {}, "@offlineWidgetText": {},
"onboardingDoneButtonLabel": "Done", "onboardingDoneButtonLabel": "Done",

View File

@@ -490,16 +490,28 @@
"@loginPageUsernameValidatorMessageText": {}, "@loginPageUsernameValidatorMessageText": {},
"matchingAlgorithmAllDescription": "", "matchingAlgorithmAllDescription": "",
"@matchingAlgorithmAllDescription": {}, "@matchingAlgorithmAllDescription": {},
"matchingAlgorithmAllName": "",
"@matchingAlgorithmAllName": {},
"matchingAlgorithmAnyDescription": "", "matchingAlgorithmAnyDescription": "",
"@matchingAlgorithmAnyDescription": {}, "@matchingAlgorithmAnyDescription": {},
"matchingAlgorithmAnyName": "",
"@matchingAlgorithmAnyName": {},
"matchingAlgorithmAutoDescription": "", "matchingAlgorithmAutoDescription": "",
"@matchingAlgorithmAutoDescription": {}, "@matchingAlgorithmAutoDescription": {},
"matchingAlgorithmAutoName": "",
"@matchingAlgorithmAutoName": {},
"matchingAlgorithmExactDescription": "", "matchingAlgorithmExactDescription": "",
"@matchingAlgorithmExactDescription": {}, "@matchingAlgorithmExactDescription": {},
"matchingAlgorithmExactName": "",
"@matchingAlgorithmExactName": {},
"matchingAlgorithmFuzzyDescription": "", "matchingAlgorithmFuzzyDescription": "",
"@matchingAlgorithmFuzzyDescription": {}, "@matchingAlgorithmFuzzyDescription": {},
"matchingAlgorithmFuzzyName": "",
"@matchingAlgorithmFuzzyName": {},
"matchingAlgorithmRegexDescription": "", "matchingAlgorithmRegexDescription": "",
"@matchingAlgorithmRegexDescription": {}, "@matchingAlgorithmRegexDescription": {},
"matchingAlgorithmRegexName": "",
"@matchingAlgorithmRegexName": {},
"offlineWidgetText": "İnternet bağlantısı kurulamadı.", "offlineWidgetText": "İnternet bağlantısı kurulamadı.",
"@offlineWidgetText": {}, "@offlineWidgetText": {},
"onboardingDoneButtonLabel": "Bitti", "onboardingDoneButtonLabel": "Bitti",

View File

@@ -204,54 +204,20 @@ class PaperlessMobileEntrypoint extends StatefulWidget {
} }
class _PaperlessMobileEntrypointState extends State<PaperlessMobileEntrypoint> { class _PaperlessMobileEntrypointState extends State<PaperlessMobileEntrypoint> {
final _lightTheme = ThemeData( final _lightTheme = ThemeData.from(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.lightGreen,
brightness: Brightness.light, brightness: Brightness.light,
),
useMaterial3: true, useMaterial3: true,
colorSchemeSeed: Colors.lightGreen,
appBarTheme: const AppBarTheme(
scrolledUnderElevation: 0.0,
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 16.0,
),
),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
chipTheme: ChipThemeData(
backgroundColor: Colors.lightGreen[50],
),
listTileTheme: const ListTileThemeData(
tileColor: Colors.transparent,
),
); );
final _darkTheme = ThemeData( final _darkTheme = ThemeData.from(
colorScheme: ColorScheme.fromSeed(
seedColor: Colors.lightGreen,
brightness: Brightness.dark, brightness: Brightness.dark,
),
useMaterial3: true, useMaterial3: true,
colorSchemeSeed: Colors.lightGreen,
appBarTheme: const AppBarTheme(
scrolledUnderElevation: 0.0,
),
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 16.0,
),
),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
chipTheme: ChipThemeData(
backgroundColor: Colors.green[900],
),
listTileTheme: const ListTileThemeData(
tileColor: Colors.transparent,
),
); );
@override @override
@@ -269,8 +235,39 @@ class _PaperlessMobileEntrypointState extends State<PaperlessMobileEntrypoint> {
return MaterialApp( return MaterialApp(
debugShowCheckedModeBanner: true, debugShowCheckedModeBanner: true,
title: "Paperless Mobile", title: "Paperless Mobile",
theme: _lightTheme, theme: _lightTheme.copyWith(
darkTheme: _darkTheme, inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 16.0,
),
),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
listTileTheme: const ListTileThemeData(
tileColor: Colors.transparent,
),
),
darkTheme: _darkTheme.copyWith(
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(16),
),
contentPadding: const EdgeInsets.symmetric(
horizontal: 16.0,
vertical: 16.0,
),
),
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
chipTheme: ChipThemeData(
backgroundColor: Colors.lightGreen[50],
),
listTileTheme: const ListTileThemeData(
tileColor: Colors.transparent,
),
),
themeMode: settings.preferredThemeMode, themeMode: settings.preferredThemeMode,
supportedLocales: S.delegate.supportedLocales, supportedLocales: S.delegate.supportedLocales,
locale: Locale.fromSubtags( locale: Locale.fromSubtags(