mirror of
https://github.com/Xevion/paperless-mobile.git
synced 2025-12-06 21:15:50 -06:00
Added translations, fixed chips theming
This commit is contained in:
@@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/generated/l10n.dart';
|
||||
|
||||
String translateMatchingAlgorithm(
|
||||
BuildContext context, MatchingAlgorithm algorithm) {
|
||||
String translateMatchingAlgorithmDescription(
|
||||
BuildContext context,
|
||||
MatchingAlgorithm algorithm,
|
||||
) {
|
||||
switch (algorithm) {
|
||||
case MatchingAlgorithm.anyWord:
|
||||
return S.of(context).matchingAlgorithmAnyDescription;
|
||||
@@ -19,3 +21,23 @@ String translateMatchingAlgorithm(
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/workarounds/colored_chip.dart';
|
||||
import 'package:paperless_mobile/generated/l10n.dart';
|
||||
|
||||
class RelativeDateRangePickerHelper extends StatefulWidget {
|
||||
@@ -28,15 +29,17 @@ class _RelativeDateRangePickerHelperState
|
||||
separatorBuilder: (context, index) => const SizedBox(width: 8.0),
|
||||
itemBuilder: (context, index) {
|
||||
final option = _options[index];
|
||||
return FilterChip(
|
||||
label: Text(option.title),
|
||||
onSelected: (isSelected) {
|
||||
final value =
|
||||
isSelected ? option.value : const RelativeDateRangeQuery();
|
||||
widget.field.didChange(value);
|
||||
widget.onChanged?.call(value);
|
||||
},
|
||||
selected: widget.field.value == option.value,
|
||||
return ColoredChipWrapper(
|
||||
child: FilterChip(
|
||||
label: Text(option.title),
|
||||
onSelected: (isSelected) {
|
||||
final value =
|
||||
isSelected ? option.value : const RelativeDateRangeQuery();
|
||||
widget.field.didChange(value);
|
||||
widget.onChanged?.call(value);
|
||||
},
|
||||
selected: widget.field.value == option.value,
|
||||
),
|
||||
);
|
||||
},
|
||||
scrollDirection: Axis.horizontal,
|
||||
|
||||
23
lib/core/workarounds/colored_chip.dart
Normal file
23
lib/core/workarounds/colored_chip.dart
Normal 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -438,7 +438,6 @@ class _DocumentDetailsPageState extends State<DocumentDetailsPage> {
|
||||
child: TagsWidget(
|
||||
isClickable: widget.isLabelClickable,
|
||||
tagIds: document.tags,
|
||||
isSelectedPredicate: (_) => false,
|
||||
onTagSelected: (int tagId) {},
|
||||
),
|
||||
),
|
||||
|
||||
@@ -95,7 +95,7 @@ class DocumentsCubit extends HydratedCubit<DocumentsState>
|
||||
}
|
||||
|
||||
void unselectView() {
|
||||
emit(state.copyWith(selectedSavedViewId: null));
|
||||
emit(state.copyWith(selectedSavedViewId: () => null));
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -25,7 +25,7 @@ class DocumentsState extends DocumentsPagedState {
|
||||
List<PagedSearchResult<DocumentModel>>? value,
|
||||
DocumentFilter? filter,
|
||||
List<DocumentModel>? selection,
|
||||
int? selectedSavedViewId,
|
||||
int? Function()? selectedSavedViewId,
|
||||
}) {
|
||||
return DocumentsState(
|
||||
hasLoaded: hasLoaded ?? this.hasLoaded,
|
||||
@@ -33,7 +33,9 @@ class DocumentsState extends DocumentsPagedState {
|
||||
value: value ?? this.value,
|
||||
filter: filter ?? this.filter,
|
||||
selection: selection ?? this.selection,
|
||||
selectedSavedViewId: selectedSavedViewId ?? this.selectedSavedViewId,
|
||||
selectedSavedViewId: selectedSavedViewId != null
|
||||
? selectedSavedViewId.call()
|
||||
: this.selectedSavedViewId,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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/document_type_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/features/edit_document/cubit/edit_document_cubit.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>({
|
||||
required Iterable<T> suggestions,
|
||||
required ItemBuilder<T> itemBuilder,
|
||||
@@ -321,8 +325,9 @@ class _DocumentEditPageState extends State<DocumentEditPage> {
|
||||
child: ListView.separated(
|
||||
scrollDirection: Axis.horizontal,
|
||||
itemCount: suggestions.length,
|
||||
itemBuilder: (context, index) =>
|
||||
itemBuilder(context, suggestions.elementAt(index)),
|
||||
itemBuilder: (context, index) => ColoredChipWrapper(
|
||||
child: itemBuilder(context, suggestions.elementAt(index)),
|
||||
),
|
||||
separatorBuilder: (BuildContext context, int index) =>
|
||||
const SizedBox(width: 4.0),
|
||||
),
|
||||
|
||||
@@ -72,7 +72,6 @@ class DocumentGridItem extends StatelessWidget {
|
||||
TagsWidget(
|
||||
tagIds: document.tags,
|
||||
isMultiLine: false,
|
||||
isSelectedPredicate: isTagSelectedPredicate,
|
||||
onTagSelected: onTagSelected,
|
||||
),
|
||||
const Spacer(),
|
||||
|
||||
@@ -73,7 +73,6 @@ class DocumentListItem extends StatelessWidget {
|
||||
isClickable: isLabelClickable,
|
||||
tagIds: document.tags,
|
||||
isMultiLine: false,
|
||||
isSelectedPredicate: isTagSelectedPredicate,
|
||||
onTagSelected: (id) => onTagSelected?.call(id),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -46,8 +46,17 @@ class LabelForm<T extends Label> extends StatefulWidget {
|
||||
class _LabelFormState<T extends Label> extends State<LabelForm<T>> {
|
||||
final _formKey = GlobalKey<FormBuilderState>();
|
||||
|
||||
late bool _enableMatchFormField;
|
||||
|
||||
PaperlessValidationErrors _errors = {};
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_enableMatchFormField =
|
||||
widget.initialValue?.matchingAlgorithm != MatchingAlgorithm.auto;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
@@ -71,15 +80,6 @@ class _LabelFormState<T extends Label> extends State<LabelForm<T>> {
|
||||
initialValue: widget.initialValue?.name,
|
||||
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?>(
|
||||
name: Label.matchingAlgorithmKey,
|
||||
initialValue: widget.initialValue?.matchingAlgorithm.value ??
|
||||
@@ -88,16 +88,32 @@ class _LabelFormState<T extends Label> extends State<LabelForm<T>> {
|
||||
labelText: S.of(context).labelMatchingAlgorithmPropertyLabel,
|
||||
errorText: _errors[Label.matchingAlgorithmKey],
|
||||
),
|
||||
onChanged: (val) => setState(() => _errors = {}),
|
||||
onChanged: (val) {
|
||||
setState(() {
|
||||
_errors = {};
|
||||
_enableMatchFormField = val != MatchingAlgorithm.auto.value;
|
||||
});
|
||||
},
|
||||
items: MatchingAlgorithm.values
|
||||
.map(
|
||||
(algo) => DropdownMenuItem<int?>(
|
||||
child: Text(translateMatchingAlgorithm(context, algo)),
|
||||
child: Text(
|
||||
translateMatchingAlgorithmDescription(context, algo)),
|
||||
value: algo.value,
|
||||
),
|
||||
)
|
||||
.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(
|
||||
name: Label.isInsensitiveKey,
|
||||
initialValue: widget.initialValue?.isInsensitive ?? true,
|
||||
@@ -117,6 +133,11 @@ class _LabelFormState<T extends Label> extends State<LabelForm<T>> {
|
||||
...widget.initialValue?.toJson() ?? {},
|
||||
..._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
|
||||
.onSubmit(widget.fromJsonT(mergedJson));
|
||||
Navigator.pop(context, createdLabel);
|
||||
|
||||
@@ -219,7 +219,7 @@ class _InfoDrawerState extends State<InfoDrawer> {
|
||||
],
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primaryContainer,
|
||||
color: Theme.of(context).colorScheme.surfaceVariant,
|
||||
),
|
||||
),
|
||||
...[
|
||||
|
||||
@@ -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/state/impl/correspondent_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/features/document_details/bloc/document_details_cubit.dart';
|
||||
import 'package:paperless_mobile/features/document_details/view/pages/document_details_page.dart';
|
||||
@@ -111,21 +112,23 @@ class _InboxItemState extends State<InboxItem> {
|
||||
final actions = [
|
||||
_buildAssignAsnAction(chipShape, context),
|
||||
const SizedBox(width: 4.0),
|
||||
ActionChip(
|
||||
avatar: const Icon(Icons.delete_outline),
|
||||
shape: chipShape,
|
||||
label: const Text("Delete document"),
|
||||
onPressed: () async {
|
||||
final shouldDelete = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) =>
|
||||
DeleteDocumentConfirmationDialog(document: widget.document),
|
||||
) ??
|
||||
false;
|
||||
if (shouldDelete) {
|
||||
context.read<InboxCubit>().delete(widget.document);
|
||||
}
|
||||
},
|
||||
ColoredChipWrapper(
|
||||
child: ActionChip(
|
||||
avatar: const Icon(Icons.delete_outline),
|
||||
shape: chipShape,
|
||||
label: const Text("Delete document"),
|
||||
onPressed: () async {
|
||||
final shouldDelete = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => DeleteDocumentConfirmationDialog(
|
||||
document: widget.document),
|
||||
) ??
|
||||
false;
|
||||
if (shouldDelete) {
|
||||
context.read<InboxCubit>().delete(widget.document);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
];
|
||||
// return FutureBuilder<FieldSuggestions>(
|
||||
@@ -191,31 +194,33 @@ class _InboxItemState extends State<InboxItem> {
|
||||
BuildContext context,
|
||||
) {
|
||||
final hasAsn = widget.document.archiveSerialNumber != null;
|
||||
return ActionChip(
|
||||
avatar: _isAsnAssignLoading
|
||||
? const CircularProgressIndicator()
|
||||
: hasAsn
|
||||
? null
|
||||
: const Icon(Icons.archive_outlined),
|
||||
shape: chipShape,
|
||||
label: hasAsn
|
||||
? Text(
|
||||
'${S.of(context).documentArchiveSerialNumberPropertyShortLabel} #${widget.document.archiveSerialNumber}',
|
||||
)
|
||||
: const Text("Assign ASN"),
|
||||
onPressed: !hasAsn
|
||||
? () {
|
||||
setState(() {
|
||||
_isAsnAssignLoading = true;
|
||||
});
|
||||
context
|
||||
.read<InboxCubit>()
|
||||
.assignAsn(widget.document)
|
||||
.whenComplete(
|
||||
() => setState(() => _isAsnAssignLoading = false),
|
||||
);
|
||||
}
|
||||
: null,
|
||||
return ColoredChipWrapper(
|
||||
child: ActionChip(
|
||||
avatar: _isAsnAssignLoading
|
||||
? const CircularProgressIndicator()
|
||||
: hasAsn
|
||||
? null
|
||||
: const Icon(Icons.archive_outlined),
|
||||
shape: chipShape,
|
||||
label: hasAsn
|
||||
? Text(
|
||||
'${S.of(context).documentArchiveSerialNumberPropertyShortLabel} #${widget.document.archiveSerialNumber}',
|
||||
)
|
||||
: const Text("Assign ASN"),
|
||||
onPressed: !hasAsn
|
||||
? () {
|
||||
setState(() {
|
||||
_isAsnAssignLoading = true;
|
||||
});
|
||||
context
|
||||
.read<InboxCubit>()
|
||||
.assignAsn(widget.document)
|
||||
.whenComplete(
|
||||
() => setState(() => _isAsnAssignLoading = false),
|
||||
);
|
||||
}
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -224,7 +229,6 @@ class _InboxItemState extends State<InboxItem> {
|
||||
tagIds: widget.document.tags,
|
||||
isMultiLine: false,
|
||||
isClickable: false,
|
||||
isSelectedPredicate: (_) => false,
|
||||
showShortNames: true,
|
||||
dense: true,
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_form_builder/flutter_form_builder.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';
|
||||
|
||||
class StoragePathAutofillFormBuilderField extends StatefulWidget {
|
||||
@@ -61,71 +62,78 @@ class _StoragePathAutofillFormBuilderFieldState
|
||||
"Select to autofill path variable",
|
||||
style: Theme.of(context).textTheme.bodySmall,
|
||||
),
|
||||
Wrap(
|
||||
alignment: WrapAlignment.start,
|
||||
spacing: 4.0,
|
||||
runSpacing: 4.0,
|
||||
children: [
|
||||
InputChip(
|
||||
label: Text(
|
||||
S.of(context).documentArchiveSerialNumberPropertyLongLabel),
|
||||
onPressed: () => _addParameterToInput("{asn}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCorrespondentPropertyLabel),
|
||||
onPressed: () => _addParameterToInput("{correspondent}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentDocumentTypePropertyLabel),
|
||||
onPressed: () => _addParameterToInput("{document_type}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentTagsPropertyLabel),
|
||||
onPressed: () => _addParameterToInput("{tag_list}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentTitlePropertyLabel),
|
||||
onPressed: () => _addParameterToInput("{title}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel),
|
||||
onPressed: () => _addParameterToInput("{created}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterYearLabel})"),
|
||||
onPressed: () => _addParameterToInput("{created_year}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterMonthLabel})"),
|
||||
onPressed: () => _addParameterToInput("{created_month}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterDayLabel})"),
|
||||
onPressed: () => _addParameterToInput("{created_day}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel),
|
||||
onPressed: () => _addParameterToInput("{added}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterYearLabel})"),
|
||||
onPressed: () => _addParameterToInput("{added_year}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterMonthLabel})"),
|
||||
onPressed: () => _addParameterToInput("{added_month}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterDayLabel})"),
|
||||
onPressed: () => _addParameterToInput("{added_day}", field),
|
||||
),
|
||||
],
|
||||
ColoredChipWrapper(
|
||||
child: Wrap(
|
||||
alignment: WrapAlignment.start,
|
||||
spacing: 4.0,
|
||||
runSpacing: 4.0,
|
||||
children: [
|
||||
InputChip(
|
||||
label: Text(S
|
||||
.of(context)
|
||||
.documentArchiveSerialNumberPropertyLongLabel),
|
||||
onPressed: () => _addParameterToInput("{asn}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCorrespondentPropertyLabel),
|
||||
onPressed: () =>
|
||||
_addParameterToInput("{correspondent}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentDocumentTypePropertyLabel),
|
||||
onPressed: () =>
|
||||
_addParameterToInput("{document_type}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentTagsPropertyLabel),
|
||||
onPressed: () => _addParameterToInput("{tag_list}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentTitlePropertyLabel),
|
||||
onPressed: () => _addParameterToInput("{title}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel),
|
||||
onPressed: () => _addParameterToInput("{created}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterYearLabel})"),
|
||||
onPressed: () =>
|
||||
_addParameterToInput("{created_year}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterMonthLabel})"),
|
||||
onPressed: () =>
|
||||
_addParameterToInput("{created_month}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterDayLabel})"),
|
||||
onPressed: () => _addParameterToInput("{created_day}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel),
|
||||
onPressed: () => _addParameterToInput("{added}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterYearLabel})"),
|
||||
onPressed: () => _addParameterToInput("{added_year}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterMonthLabel})"),
|
||||
onPressed: () => _addParameterToInput("{added_month}", field),
|
||||
),
|
||||
InputChip(
|
||||
label: Text(S.of(context).documentCreatedPropertyLabel +
|
||||
" (${S.of(context).storagePathParameterDayLabel})"),
|
||||
onPressed: () => _addParameterToInput("{added_day}", field),
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:paperless_api/paperless_api.dart';
|
||||
import 'package:paperless_mobile/core/workarounds/colored_chip.dart';
|
||||
|
||||
class TagWidget extends StatelessWidget {
|
||||
final Tag tag;
|
||||
final VoidCallback? afterTagTapped;
|
||||
final VoidCallback onSelected;
|
||||
final bool isSelected;
|
||||
final bool isClickable;
|
||||
final bool showShortName;
|
||||
final bool dense;
|
||||
@@ -13,10 +12,8 @@ class TagWidget extends StatelessWidget {
|
||||
const TagWidget({
|
||||
super.key,
|
||||
required this.tag,
|
||||
required this.afterTagTapped,
|
||||
this.isClickable = true,
|
||||
required this.onSelected,
|
||||
required this.isSelected,
|
||||
this.showShortName = false,
|
||||
this.dense = false,
|
||||
});
|
||||
@@ -27,24 +24,25 @@ class TagWidget extends StatelessWidget {
|
||||
padding: const EdgeInsets.only(right: 4.0),
|
||||
child: AbsorbPointer(
|
||||
absorbing: !isClickable,
|
||||
child: FilterChip(
|
||||
labelPadding:
|
||||
dense ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
padding: dense ? const EdgeInsets.all(4) : null,
|
||||
selected: isSelected,
|
||||
selectedColor: tag.color,
|
||||
onSelected: (_) => onSelected(),
|
||||
visualDensity: const VisualDensity(vertical: -2),
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
label: Text(
|
||||
showShortName && tag.name.length > 6
|
||||
? '${tag.name.substring(0, 6)}...'
|
||||
: tag.name,
|
||||
style: TextStyle(color: tag.textColor),
|
||||
child: ColoredChipWrapper(
|
||||
child: FilterChip(
|
||||
labelPadding:
|
||||
dense ? const EdgeInsets.symmetric(horizontal: 2) : null,
|
||||
padding: dense ? const EdgeInsets.all(4) : null,
|
||||
selectedColor: tag.color,
|
||||
onSelected: (_) => onSelected(),
|
||||
visualDensity: const VisualDensity(vertical: -2),
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
label: Text(
|
||||
showShortName && tag.name.length > 6
|
||||
? '${tag.name.substring(0, 6)}...'
|
||||
: tag.name,
|
||||
style: TextStyle(color: tag.textColor),
|
||||
),
|
||||
checkmarkColor: tag.textColor,
|
||||
backgroundColor: tag.color,
|
||||
side: BorderSide.none,
|
||||
),
|
||||
checkmarkColor: tag.textColor,
|
||||
backgroundColor: tag.color,
|
||||
side: BorderSide.none,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -7,6 +7,7 @@ import 'package:flutter_typeahead/flutter_typeahead.dart';
|
||||
import 'package:paperless_api/paperless_api.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/workarounds/colored_chip.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/generated/l10n.dart';
|
||||
@@ -263,13 +264,15 @@ class _TagFormFieldState extends State<TagFormField> {
|
||||
}
|
||||
|
||||
Widget _buildNotAssignedTag(FormFieldState<TagsQuery> field) {
|
||||
return InputChip(
|
||||
label: Text(
|
||||
S.of(context).labelNotAssignedText,
|
||||
return ColoredChipWrapper(
|
||||
child: InputChip(
|
||||
label: Text(
|
||||
S.of(context).labelNotAssignedText,
|
||||
),
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.onSurface.withOpacity(0.12),
|
||||
onDeleted: () => field.didChange(const IdsTagsQuery()),
|
||||
),
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.onSurface.withOpacity(0.12),
|
||||
onDeleted: () => field.didChange(const IdsTagsQuery()),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -283,33 +286,37 @@ class _TagFormFieldState extends State<TagFormField> {
|
||||
if (tag == null) {
|
||||
return Container();
|
||||
}
|
||||
return InputChip(
|
||||
label: Text(
|
||||
tag.name,
|
||||
style: TextStyle(
|
||||
color: tag.textColor,
|
||||
decorationColor: tag.textColor,
|
||||
decoration: !isIncludedTag ? TextDecoration.lineThrough : null,
|
||||
decorationThickness: 2.0,
|
||||
return ColoredChipWrapper(
|
||||
child: InputChip(
|
||||
label: Text(
|
||||
tag.name,
|
||||
style: TextStyle(
|
||||
color: tag.textColor,
|
||||
decorationColor: tag.textColor,
|
||||
decoration: !isIncludedTag ? TextDecoration.lineThrough : null,
|
||||
decorationThickness: 2.0,
|
||||
),
|
||||
),
|
||||
onPressed: widget.excludeAllowed
|
||||
? () => field.didChange(currentQuery.withIdQueryToggled(tag.id!))
|
||||
: null,
|
||||
backgroundColor: tag.color,
|
||||
deleteIconColor: tag.textColor,
|
||||
onDeleted: () => field.didChange(
|
||||
(field.value as IdsTagsQuery).withIdsRemoved([tag.id!]),
|
||||
),
|
||||
),
|
||||
onPressed: widget.excludeAllowed
|
||||
? () => field.didChange(currentQuery.withIdQueryToggled(tag.id!))
|
||||
: null,
|
||||
backgroundColor: tag.color,
|
||||
deleteIconColor: tag.textColor,
|
||||
onDeleted: () => field.didChange(
|
||||
(field.value as IdsTagsQuery).withIdsRemoved([tag.id!]),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAnyAssignedTag(FormFieldState<TagsQuery> field) {
|
||||
return InputChip(
|
||||
label: Text(S.of(context).labelAnyAssignedText),
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.12),
|
||||
onDeleted: () => field.didChange(const IdsTagsQuery()),
|
||||
return ColoredChipWrapper(
|
||||
child: InputChip(
|
||||
label: Text(S.of(context).labelAnyAssignedText),
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.12),
|
||||
onDeleted: () => field.didChange(const IdsTagsQuery()),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,20 +9,16 @@ import 'package:paperless_mobile/features/labels/tags/view/widgets/tag_widget.da
|
||||
class TagsWidget extends StatelessWidget {
|
||||
final Iterable<int> tagIds;
|
||||
final bool isMultiLine;
|
||||
final VoidCallback? afterTagTapped;
|
||||
final void Function(int tagId)? onTagSelected;
|
||||
final bool isClickable;
|
||||
final bool Function(int id) isSelectedPredicate;
|
||||
final bool showShortNames;
|
||||
final bool dense;
|
||||
|
||||
const TagsWidget({
|
||||
Key? key,
|
||||
required this.tagIds,
|
||||
this.afterTagTapped,
|
||||
this.isMultiLine = true,
|
||||
this.isClickable = true,
|
||||
required this.isSelectedPredicate,
|
||||
this.onTagSelected,
|
||||
this.showShortNames = false,
|
||||
this.dense = true,
|
||||
@@ -38,9 +34,7 @@ class TagsWidget extends StatelessWidget {
|
||||
.map(
|
||||
(id) => TagWidget(
|
||||
tag: state.getLabel(id)!,
|
||||
afterTagTapped: afterTagTapped,
|
||||
isClickable: isClickable,
|
||||
isSelected: isSelectedPredicate(id),
|
||||
onSelected: () => onTagSelected?.call(id),
|
||||
showShortName: showShortNames,
|
||||
dense: dense,
|
||||
|
||||
@@ -174,7 +174,6 @@ class _LabelsPageState extends State<LabelsPage>
|
||||
)
|
||||
: null,
|
||||
),
|
||||
contentBuilder: (t) => Text(t.match ?? ''),
|
||||
emptyStateActionButtonLabel:
|
||||
S.of(context).labelsPageTagsEmptyStateAddNewLabel,
|
||||
emptyStateDescription:
|
||||
|
||||
@@ -68,21 +68,22 @@ class LabelTabView<T extends Label> extends StatelessWidget {
|
||||
connectivityState.isConnected,
|
||||
child: ListView(
|
||||
children: labels
|
||||
.map(
|
||||
(l) => LabelItem<T>(
|
||||
name: l.name,
|
||||
content: contentBuilder?.call(l) ??
|
||||
Text(
|
||||
"${translateMatchingAlgorithm(context, l.matchingAlgorithm)}\n"
|
||||
"${l.match}",
|
||||
maxLines: 2,
|
||||
),
|
||||
onOpenEditPage: onEdit,
|
||||
filterBuilder: filterBuilder,
|
||||
leading: leadingBuilder?.call(l),
|
||||
label: l,
|
||||
),
|
||||
)
|
||||
.map((l) => LabelItem<T>(
|
||||
name: l.name,
|
||||
content: contentBuilder?.call(l) ??
|
||||
Text(
|
||||
translateMatchingAlgorithmName(
|
||||
context, l.matchingAlgorithm) +
|
||||
((l.match?.isNotEmpty ?? false)
|
||||
? ": ${l.match}"
|
||||
: ""),
|
||||
maxLines: 2,
|
||||
),
|
||||
onOpenEditPage: onEdit,
|
||||
filterBuilder: filterBuilder,
|
||||
leading: leadingBuilder?.call(l),
|
||||
label: l,
|
||||
))
|
||||
.toList(),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -182,15 +182,15 @@ class SavedViewSelectionWidget extends StatelessWidget {
|
||||
}
|
||||
|
||||
void _onSelected(
|
||||
bool isSelected,
|
||||
bool selectionIntent,
|
||||
BuildContext context,
|
||||
SavedView view,
|
||||
) async {
|
||||
if (isSelected) {
|
||||
if (selectionIntent) {
|
||||
context.read<DocumentsCubit>().selectView(view.id!);
|
||||
} else {
|
||||
context.read<DocumentsCubit>().resetFilter();
|
||||
context.read<DocumentsCubit>().unselectView();
|
||||
context.read<DocumentsCubit>().resetFilter();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"@@locale": "cs",
|
||||
"aboutDialogDevelopedByText": "Vyvíjí",
|
||||
"aboutDialogDevelopedByText": "Vyvíjí {name}",
|
||||
"@aboutDialogDevelopedByText": {
|
||||
"placeholders": {
|
||||
"name": {}
|
||||
@@ -490,16 +490,28 @@
|
||||
"@loginPageUsernameValidatorMessageText": {},
|
||||
"matchingAlgorithmAllDescription": "",
|
||||
"@matchingAlgorithmAllDescription": {},
|
||||
"matchingAlgorithmAllName": "",
|
||||
"@matchingAlgorithmAllName": {},
|
||||
"matchingAlgorithmAnyDescription": "",
|
||||
"@matchingAlgorithmAnyDescription": {},
|
||||
"matchingAlgorithmAnyName": "",
|
||||
"@matchingAlgorithmAnyName": {},
|
||||
"matchingAlgorithmAutoDescription": "",
|
||||
"@matchingAlgorithmAutoDescription": {},
|
||||
"matchingAlgorithmAutoName": "",
|
||||
"@matchingAlgorithmAutoName": {},
|
||||
"matchingAlgorithmExactDescription": "",
|
||||
"@matchingAlgorithmExactDescription": {},
|
||||
"matchingAlgorithmExactName": "",
|
||||
"@matchingAlgorithmExactName": {},
|
||||
"matchingAlgorithmFuzzyDescription": "",
|
||||
"@matchingAlgorithmFuzzyDescription": {},
|
||||
"matchingAlgorithmFuzzyName": "",
|
||||
"@matchingAlgorithmFuzzyName": {},
|
||||
"matchingAlgorithmRegexDescription": "",
|
||||
"@matchingAlgorithmRegexDescription": {},
|
||||
"matchingAlgorithmRegexName": "",
|
||||
"@matchingAlgorithmRegexName": {},
|
||||
"offlineWidgetText": "Nezdařilo se vytvořit připojení k internetu.",
|
||||
"@offlineWidgetText": {},
|
||||
"onboardingDoneButtonLabel": "Hotovo",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"@@locale": "de",
|
||||
"aboutDialogDevelopedByText": "Entwickelt von",
|
||||
"aboutDialogDevelopedByText": "Entwickelt von {name}",
|
||||
"@aboutDialogDevelopedByText": {
|
||||
"placeholders": {
|
||||
"name": {}
|
||||
@@ -488,18 +488,30 @@
|
||||
"@loginPageUsernameLabel": {},
|
||||
"loginPageUsernameValidatorMessageText": "Nutzername darf nicht leer sein.",
|
||||
"@loginPageUsernameValidatorMessageText": {},
|
||||
"matchingAlgorithmAllDescription": "Alle: Dokument enthält alle folgenden Wörter",
|
||||
"matchingAlgorithmAllDescription": "Dokument enthält alle folgenden Wörter",
|
||||
"@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": {},
|
||||
"matchingAlgorithmAutoDescription": "Auto: Zuweisung automatisch erlernen",
|
||||
"matchingAlgorithmAnyName": "Irgendein Wort",
|
||||
"@matchingAlgorithmAnyName": {},
|
||||
"matchingAlgorithmAutoDescription": "Zuweisung automatisch erlernen",
|
||||
"@matchingAlgorithmAutoDescription": {},
|
||||
"matchingAlgorithmExactDescription": "Exakt: Dokument enthält die folgende Zeichenkette",
|
||||
"matchingAlgorithmAutoName": "Auto",
|
||||
"@matchingAlgorithmAutoName": {},
|
||||
"matchingAlgorithmExactDescription": "Dokument enthält die folgende Zeichenkette",
|
||||
"@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": {},
|
||||
"matchingAlgorithmRegexDescription": "Regulärer Ausdruck: Dokument passt zum folgenden Ausdruck",
|
||||
"matchingAlgorithmFuzzyName": "Ungenau",
|
||||
"@matchingAlgorithmFuzzyName": {},
|
||||
"matchingAlgorithmRegexDescription": "Dokument passt zum folgenden Ausdruck",
|
||||
"@matchingAlgorithmRegexDescription": {},
|
||||
"matchingAlgorithmRegexName": "Regulärer Ausdruck",
|
||||
"@matchingAlgorithmRegexName": {},
|
||||
"offlineWidgetText": "Es konte keine Verbindung zum Internet hergestellt werden.",
|
||||
"@offlineWidgetText": {},
|
||||
"onboardingDoneButtonLabel": "Fertig",
|
||||
|
||||
@@ -488,18 +488,30 @@
|
||||
"@loginPageUsernameLabel": {},
|
||||
"loginPageUsernameValidatorMessageText": "Username must not be empty.",
|
||||
"@loginPageUsernameValidatorMessageText": {},
|
||||
"matchingAlgorithmAllDescription": "All: Document contains all of these words",
|
||||
"matchingAlgorithmAllDescription": "Document contains all of these words",
|
||||
"@matchingAlgorithmAllDescription": {},
|
||||
"matchingAlgorithmAnyDescription": "Any: Document contains any of these words",
|
||||
"matchingAlgorithmAllName": "All",
|
||||
"@matchingAlgorithmAllName": {},
|
||||
"matchingAlgorithmAnyDescription": "Document contains any of these words",
|
||||
"@matchingAlgorithmAnyDescription": {},
|
||||
"matchingAlgorithmAutoDescription": "Auto: Learn matching automatically",
|
||||
"matchingAlgorithmAnyName": "Any",
|
||||
"@matchingAlgorithmAnyName": {},
|
||||
"matchingAlgorithmAutoDescription": "Learn matching automatically",
|
||||
"@matchingAlgorithmAutoDescription": {},
|
||||
"matchingAlgorithmExactDescription": "Exact: Document contains this string",
|
||||
"matchingAlgorithmAutoName": "Auto",
|
||||
"@matchingAlgorithmAutoName": {},
|
||||
"matchingAlgorithmExactDescription": "Document contains this string",
|
||||
"@matchingAlgorithmExactDescription": {},
|
||||
"matchingAlgorithmFuzzyDescription": "Fuzzy: Document contains a word similar to this word",
|
||||
"matchingAlgorithmExactName": "Exact",
|
||||
"@matchingAlgorithmExactName": {},
|
||||
"matchingAlgorithmFuzzyDescription": "Document contains a word similar to this word",
|
||||
"@matchingAlgorithmFuzzyDescription": {},
|
||||
"matchingAlgorithmRegexDescription": "Regular Expression: Document matches this regular expression",
|
||||
"matchingAlgorithmFuzzyName": "Fuzzy",
|
||||
"@matchingAlgorithmFuzzyName": {},
|
||||
"matchingAlgorithmRegexDescription": "Document matches this regular expression",
|
||||
"@matchingAlgorithmRegexDescription": {},
|
||||
"matchingAlgorithmRegexName": "Regular Expression",
|
||||
"@matchingAlgorithmRegexName": {},
|
||||
"offlineWidgetText": "An internet connection could not be established.",
|
||||
"@offlineWidgetText": {},
|
||||
"onboardingDoneButtonLabel": "Done",
|
||||
|
||||
@@ -490,16 +490,28 @@
|
||||
"@loginPageUsernameValidatorMessageText": {},
|
||||
"matchingAlgorithmAllDescription": "",
|
||||
"@matchingAlgorithmAllDescription": {},
|
||||
"matchingAlgorithmAllName": "",
|
||||
"@matchingAlgorithmAllName": {},
|
||||
"matchingAlgorithmAnyDescription": "",
|
||||
"@matchingAlgorithmAnyDescription": {},
|
||||
"matchingAlgorithmAnyName": "",
|
||||
"@matchingAlgorithmAnyName": {},
|
||||
"matchingAlgorithmAutoDescription": "",
|
||||
"@matchingAlgorithmAutoDescription": {},
|
||||
"matchingAlgorithmAutoName": "",
|
||||
"@matchingAlgorithmAutoName": {},
|
||||
"matchingAlgorithmExactDescription": "",
|
||||
"@matchingAlgorithmExactDescription": {},
|
||||
"matchingAlgorithmExactName": "",
|
||||
"@matchingAlgorithmExactName": {},
|
||||
"matchingAlgorithmFuzzyDescription": "",
|
||||
"@matchingAlgorithmFuzzyDescription": {},
|
||||
"matchingAlgorithmFuzzyName": "",
|
||||
"@matchingAlgorithmFuzzyName": {},
|
||||
"matchingAlgorithmRegexDescription": "",
|
||||
"@matchingAlgorithmRegexDescription": {},
|
||||
"matchingAlgorithmRegexName": "",
|
||||
"@matchingAlgorithmRegexName": {},
|
||||
"offlineWidgetText": "İnternet bağlantısı kurulamadı.",
|
||||
"@offlineWidgetText": {},
|
||||
"onboardingDoneButtonLabel": "Bitti",
|
||||
|
||||
@@ -204,54 +204,20 @@ class PaperlessMobileEntrypoint extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _PaperlessMobileEntrypointState extends State<PaperlessMobileEntrypoint> {
|
||||
final _lightTheme = ThemeData(
|
||||
brightness: Brightness.light,
|
||||
final _lightTheme = ThemeData.from(
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: Colors.lightGreen,
|
||||
brightness: Brightness.light,
|
||||
),
|
||||
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(
|
||||
brightness: Brightness.dark,
|
||||
final _darkTheme = ThemeData.from(
|
||||
colorScheme: ColorScheme.fromSeed(
|
||||
seedColor: Colors.lightGreen,
|
||||
brightness: Brightness.dark,
|
||||
),
|
||||
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
|
||||
@@ -269,8 +235,39 @@ class _PaperlessMobileEntrypointState extends State<PaperlessMobileEntrypoint> {
|
||||
return MaterialApp(
|
||||
debugShowCheckedModeBanner: true,
|
||||
title: "Paperless Mobile",
|
||||
theme: _lightTheme,
|
||||
darkTheme: _darkTheme,
|
||||
theme: _lightTheme.copyWith(
|
||||
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,
|
||||
supportedLocales: S.delegate.supportedLocales,
|
||||
locale: Locale.fromSubtags(
|
||||
|
||||
Reference in New Issue
Block a user