diff --git a/lib/core/widgets/form_fields/fullscreen_selection_form.dart b/lib/core/widgets/form_fields/fullscreen_selection_form.dart new file mode 100644 index 0000000..7ff9f15 --- /dev/null +++ b/lib/core/widgets/form_fields/fullscreen_selection_form.dart @@ -0,0 +1,145 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; + +class FullscreenSelectionForm extends StatefulWidget { + final FocusNode? focusNode; + final TextEditingController? controller; + + final String hintText; + final Widget leadingIcon; + final bool autofocus; + + final VoidCallback? onTextFieldCleared; + final List trailingActions; + final Widget Function(BuildContext context, int index) selectionBuilder; + final int selectionCount; + final void Function(String value)? onKeyboardSubmit; + final Widget? floatingActionButton; + + const FullscreenSelectionForm({ + super.key, + this.focusNode, + this.controller, + required this.hintText, + required this.leadingIcon, + this.autofocus = true, + this.onTextFieldCleared, + this.trailingActions = const [], + required this.selectionBuilder, + required this.selectionCount, + this.onKeyboardSubmit, + this.floatingActionButton, + }); + + @override + State createState() => + _FullscreenSelectionFormState(); +} + +class _FullscreenSelectionFormState extends State { + late final FocusNode _focusNode; + late final TextEditingController _controller; + + bool _showClearIcon = false; + + @override + void initState() { + super.initState(); + _focusNode = widget.focusNode ?? FocusNode(); + _controller = (widget.controller ?? TextEditingController()) + ..addListener(() { + setState(() { + _showClearIcon = _controller.text.isNotEmpty; + }); + }); + if (widget.autofocus) { + WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + //Delay keyboard popup to ensure open animation is finished before. + Future.delayed( + const Duration(milliseconds: 200), + () => _focusNode.requestFocus(), + ); + }); + } + } + + @override + Widget build(BuildContext context) { + final theme = Theme.of(context); + + return Scaffold( + floatingActionButton: widget.floatingActionButton, + appBar: AppBar( + backgroundColor: theme.colorScheme.surface, + toolbarHeight: 72, + leading: BackButton( + color: theme.colorScheme.onSurface, + ), + title: TextFormField( + focusNode: _focusNode, + controller: _controller, + onFieldSubmitted: (value) { + FocusScope.of(context).unfocus(); + widget.onKeyboardSubmit?.call(value); + }, + autofocus: true, + style: theme.textTheme.bodyLarge?.apply( + color: theme.colorScheme.onSurface, + ), + decoration: InputDecoration( + contentPadding: EdgeInsets.zero, + hintStyle: theme.textTheme.bodyLarge?.apply( + color: theme.colorScheme.onSurfaceVariant, + ), + icon: widget.leadingIcon, + hintText: widget.hintText, + border: InputBorder.none, + ), + textInputAction: TextInputAction.done, + ), + actions: [ + if (_showClearIcon) + IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + _controller.clear(); + widget.onTextFieldCleared?.call(); + }, + ), + ...widget.trailingActions, + ], + bottom: PreferredSize( + preferredSize: const Size.fromHeight(1), + child: Divider( + color: theme.colorScheme.outline, + ), + ), + ), + body: Column( + children: [ + Expanded( + child: ListView.builder( + padding: EdgeInsets.zero, + shrinkWrap: true, + itemCount: widget.selectionCount, + itemBuilder: (BuildContext context, int index) { + final highlight = + AutocompleteHighlightedOption.of(context) == index; + if (highlight) { + SchedulerBinding.instance + .addPostFrameCallback((Duration timeStamp) { + Scrollable.ensureVisible( + context, + alignment: 0, + ); + }); + } + return widget.selectionBuilder(context, index); + }, + ), + ), + ], + ), + ); + } +} diff --git a/lib/features/document_bulk_action/view/widgets/fullscreen_bulk_edit_label_form_field.dart b/lib/features/document_bulk_action/view/widgets/fullscreen_bulk_edit_label_form_field.dart new file mode 100644 index 0000000..5c4c494 --- /dev/null +++ b/lib/features/document_bulk_action/view/widgets/fullscreen_bulk_edit_label_form_field.dart @@ -0,0 +1,150 @@ +import 'package:collection/collection.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/widgets/dialog_utils/dialog_cancel_button.dart'; +import 'package:paperless_mobile/core/widgets/form_fields/fullscreen_selection_form.dart'; +import 'package:paperless_mobile/features/document_bulk_action/cubit/document_bulk_action_cubit.dart'; +import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; + +class FullscreenBulkEditLabelFormField extends StatefulWidget { + final String hintText; + final Map options; + final List selection; + final int? Function(DocumentModel document) labelMapper; + final Widget leadingIcon; + final void Function(int? id) onSubmit; + + FullscreenBulkEditLabelFormField({ + super.key, + required this.options, + required this.selection, + required this.labelMapper, + required this.leadingIcon, + required this.hintText, + required this.onSubmit, + }) : assert(selection.isNotEmpty); + + @override + State createState() => + _FullscreenBulkEditLabelFormFieldState(); +} + +class _FullscreenBulkEditLabelFormFieldState + extends State { + LabelSelection? _selection; + + @override + void initState() { + super.initState(); + if (_initialValues.length == 1 && _initialValues.first != null) { + _selection = LabelSelection(_initialValues.first); + } + } + + List get _initialValues => + widget.selection.map(widget.labelMapper).toSet().toList(); + + Iterable _generateOrderedLabels() sync* { + for (var label in _initialValues) { + if (label != null) { + yield label; + } + } + for (final id + in widget.options.keys.whereNot((e) => _initialValues.contains(e))) { + yield id; + } + } + + @override + Widget build(BuildContext context) { + final _labels = _generateOrderedLabels(); + final hideFab = _selection == null || + (_initialValues.length == 1 && + _selection?.label == _initialValues.first); + return FullscreenSelectionForm( + hintText: widget.hintText, + leadingIcon: widget.leadingIcon, + selectionBuilder: (context, index) => + _buildItem(widget.options[_labels.elementAt(index)]!), + selectionCount: _labels.length, + floatingActionButton: !hideFab + ? FloatingActionButton.extended( + onPressed: () async { + if (_selection == null) { + Navigator.pop(context); + } else { + final shouldPerformAction = await showDialog( + context: context, + builder: (context) => _buildConfirmDialog(context), + // if _selection.labelId is null: show dialog asking to remove label from widget.selection.length documents + // else show dialog asking to assign label to widget.selection.length documents + ) ?? + false; + if (shouldPerformAction) { + widget.onSubmit(_selection!.label); + Navigator.pop(context); + } + } + }, + label: Text(S.of(context)!.apply), + icon: Icon(Icons.done), + ) + : null, + ); + } + + AlertDialog _buildConfirmDialog(BuildContext context) { + return AlertDialog( + title: Text(S.of(context)!.confirmAction), + content: Text( + S.of(context)!.areYouSureYouWantToContinue, + ), + actions: [ + const DialogCancelButton(), + TextButton( + onPressed: () => Navigator.of(context).pop(true), + child: Text( + S.of(context)!.confirm, + style: TextStyle( + color: Theme.of(context).colorScheme.error, + ), + ), + ), + ], + ); + } + + Widget _buildItem(Label label) { + Widget? trailingIcon; + if (_initialValues.length > 1 && + _selection == null && + _initialValues.contains(label.id)) { + trailingIcon = const Icon(Icons.remove); + } else if (_selection?.label == label.id) { + trailingIcon = const Icon(Icons.done); + } + return ListTile( + title: Text(label.name), + trailing: trailingIcon, + onTap: () { + if (_selection?.label == label.id) { + setState(() { + _selection = LabelSelection(null); + }); + } else { + setState(() { + _selection = LabelSelection(label.id); + }); + } + }, + ); + } +} + +class LabelSelection { + final int? label; + + LabelSelection(this.label); +} diff --git a/lib/features/documents/view/widgets/selection/document_selection_sliver_app_bar.dart b/lib/features/documents/view/widgets/selection/document_selection_sliver_app_bar.dart index 3a9d0e1..01cd603 100644 --- a/lib/features/documents/view/widgets/selection/document_selection_sliver_app_bar.dart +++ b/lib/features/documents/view/widgets/selection/document_selection_sliver_app_bar.dart @@ -7,6 +7,7 @@ import 'package:paperless_mobile/extensions/flutter_extensions.dart'; import 'package:paperless_mobile/features/document_bulk_action/cubit/document_bulk_action_cubit.dart'; import 'package:paperless_mobile/features/document_bulk_action/view/widgets/bulk_edit_label_bottom_sheet.dart'; import 'package:paperless_mobile/features/document_bulk_action/view/widgets/bulk_edit_tags_bottom_sheet.dart'; +import 'package:paperless_mobile/features/document_bulk_action/view/widgets/fullscreen_bulk_edit_label_form_field.dart'; import 'package:paperless_mobile/features/documents/cubit/documents_cubit.dart'; import 'package:paperless_mobile/features/documents/view/widgets/selection/bulk_delete_confirmation_dialog.dart'; import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; @@ -65,12 +66,106 @@ class DocumentSelectionSliverAppBar extends StatelessWidget { child: ListView( scrollDirection: Axis.horizontal, children: [ - _buildBulkEditCorrespondentChip(context) - .paddedOnly(left: 8, right: 4), - _buildBulkEditDocumentTypeChip(context) - .paddedOnly(left: 4, right: 4), - _buildBulkEditStoragePathChip(context) - .paddedOnly(left: 4, right: 4), + ActionChip( + label: Text(S.of(context)!.correspondent), + avatar: const Icon(Icons.edit), + onPressed: () async { + await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => BlocProvider( + create: (context) => DocumentBulkActionCubit( + context.read(), + context.read(), + context.read(), + selection: state.selection, + ), + child: BlocBuilder( + builder: (context, state) { + return FullscreenBulkEditLabelFormField( + options: state.correspondents, + selection: state.selection, + labelMapper: (document) => document.correspondent, + leadingIcon: const Icon(Icons.person_outline), + hintText: S.of(context)!.startTyping, + onSubmit: context + .read() + .bulkModifyCorrespondent, + ); + }, + ), + ), + ), + ); + }, + ).paddedOnly(left: 8, right: 4), + ActionChip( + label: Text(S.of(context)!.documentType), + avatar: const Icon(Icons.edit), + onPressed: () async { + await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => BlocProvider( + create: (context) => DocumentBulkActionCubit( + context.read(), + context.read(), + context.read(), + selection: state.selection, + ), + child: BlocBuilder( + builder: (context, state) { + return FullscreenBulkEditLabelFormField( + options: state.documentTypes, + selection: state.selection, + labelMapper: (document) => document.documentType, + leadingIcon: + const Icon(Icons.description_outlined), + hintText: S.of(context)!.startTyping, + onSubmit: context + .read() + .bulkModifyDocumentType, + ); + }, + ), + ), + ), + ); + }, + ).paddedOnly(left: 8, right: 4), + ActionChip( + label: Text(S.of(context)!.storagePath), + avatar: const Icon(Icons.edit), + onPressed: () async { + await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => BlocProvider( + create: (context) => DocumentBulkActionCubit( + context.read(), + context.read(), + context.read(), + selection: state.selection, + ), + child: BlocBuilder( + builder: (context, state) { + return FullscreenBulkEditLabelFormField( + options: state.storagePaths, + selection: state.selection, + labelMapper: (document) => document.storagePath, + leadingIcon: const Icon(Icons.folder_outlined), + hintText: S.of(context)!.startTyping, + onSubmit: context + .read() + .bulkModifyStoragePath, + ); + }, + ), + ), + ), + ); + }, + ).paddedOnly(left: 8, right: 4), _buildBulkEditTagsChip(context).paddedOnly(left: 4, right: 4), ], ), @@ -79,150 +174,6 @@ class DocumentSelectionSliverAppBar extends StatelessWidget { ); } - Widget _buildBulkEditCorrespondentChip(BuildContext context) { - return ActionChip( - label: Text(S.of(context)!.correspondent), - avatar: const Icon(Icons.edit), - onPressed: () { - final initialValue = state.selection.every((element) => - element.correspondent == state.selection.first.correspondent) - ? state.selection.first.correspondent - : null; - showModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), - ), - ), - isScrollControlled: false, - context: context, - builder: (_) { - return BlocProvider( - create: (context) => DocumentBulkActionCubit( - context.read(), - context.read(), - context.read(), - selection: state.selection, - ), - child: Builder(builder: (context) { - return BulkEditLabelBottomSheet( - initialValue: initialValue, - title: "Bulk edit correspondent", - availableOptionsSelector: (state) => state.correspondents, - formFieldLabel: S.of(context)!.correspondent, - formFieldPrefixIcon: const Icon(Icons.person_outline), - onSubmit: (selectedId) async { - await context - .read() - .bulkModifyCorrespondent(selectedId); - Navigator.pop(context); - }, - ); - }), - ); - }, - ); - }, - ); - } - - Widget _buildBulkEditDocumentTypeChip(BuildContext context) { - return ActionChip( - label: Text(S.of(context)!.documentType), - avatar: const Icon(Icons.edit), - onPressed: () { - final initialValue = state.selection.every((element) => - element.documentType == state.selection.first.documentType) - ? state.selection.first.documentType - : null; - showModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), - ), - ), - isScrollControlled: false, - context: context, - builder: (_) { - return BlocProvider( - create: (context) => DocumentBulkActionCubit( - context.read(), - context.read(), - context.read(), - selection: state.selection, - ), - child: Builder(builder: (context) { - return BulkEditLabelBottomSheet( - initialValue: initialValue, - title: "Bulk edit document type", - availableOptionsSelector: (state) => state.documentTypes, - formFieldLabel: S.of(context)!.documentType, - formFieldPrefixIcon: const Icon(Icons.person_outline), - onSubmit: (selectedId) async { - await context - .read() - .bulkModifyDocumentType(selectedId); - Navigator.pop(context); - }, - ); - }), - ); - }, - ); - }, - ); - } - - Widget _buildBulkEditStoragePathChip(BuildContext context) { - return ActionChip( - label: Text(S.of(context)!.storagePath), - avatar: const Icon(Icons.edit), - onPressed: () { - final initialValue = state.selection.every((element) => - element.storagePath == state.selection.first.storagePath) - ? state.selection.first.storagePath - : null; - showModalBottomSheet( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.only( - topLeft: Radius.circular(16), - topRight: Radius.circular(16), - ), - ), - isScrollControlled: false, - context: context, - builder: (_) { - return BlocProvider( - create: (context) => DocumentBulkActionCubit( - context.read(), - context.read(), - context.read(), - selection: state.selection, - ), - child: Builder(builder: (context) { - return BulkEditLabelBottomSheet( - initialValue: initialValue, - title: "Bulk edit storage path", - availableOptionsSelector: (state) => state.storagePaths, - formFieldLabel: S.of(context)!.storagePath, - formFieldPrefixIcon: const Icon(Icons.folder_open_outlined), - onSubmit: (selectedId) async { - await context - .read() - .bulkModifyStoragePath(selectedId); - Navigator.pop(context); - }, - ); - }), - ); - }, - ); - }, - ); - } - Widget _buildBulkEditTagsChip(BuildContext context) { return ActionChip( label: Text(S.of(context)!.tags), diff --git a/lib/features/labels/tags/view/widgets/tag_form_field.dart b/lib/features/labels/tags/view/widgets/tag_form_field.dart deleted file mode 100644 index a35dc1d..0000000 --- a/lib/features/labels/tags/view/widgets/tag_form_field.dart +++ /dev/null @@ -1,149 +0,0 @@ -// import 'dart:developer'; - -// import 'package:animations/animations.dart'; -// import 'package:collection/collection.dart'; -// import 'package:flutter/material.dart'; -// import 'package:flutter_form_builder/flutter_form_builder.dart'; -// import 'package:paperless_api/paperless_api.dart'; -// import 'package:paperless_mobile/core/widgets/material/chips_input.dart'; -// import 'package:paperless_mobile/core/workarounds/colored_chip.dart'; -// import 'package:paperless_mobile/extensions/flutter_extensions.dart'; -// import 'package:paperless_mobile/features/labels/view/widgets/fullscreen_label_form.dart'; -// import 'package:paperless_mobile/generated/l10n/app_localizations.dart'; - -// /// -// /// Form field allowing to select labels (i.e. correspondent, documentType) -// /// [T] is the label type (e.g. [DocumentType], [Correspondent], ...) -// /// -// class TagsFormField extends StatelessWidget { -// final Widget prefixIcon; -// final Map options; -// final IdQueryParameter? initialValue; -// final String name; -// final String labelText; -// final FormFieldValidator? validator; -// final Widget Function(String? initialName)? addLabelPageBuilder; -// final void Function(IdQueryParameter?)? onChanged; -// final bool showNotAssignedOption; -// final bool showAnyAssignedOption; -// final List suggestions; -// final String? addLabelText; - -// const TagsFormField({ -// Key? key, -// required this.name, -// required this.options, -// required this.labelText, -// required this.prefixIcon, -// this.initialValue, -// this.validator, -// this.addLabelPageBuilder, -// this.onChanged, -// this.showNotAssignedOption = true, -// this.showAnyAssignedOption = true, -// this.suggestions = const [], -// this.addLabelText, -// }) : super(key: key); - -// String _buildText(BuildContext context, IdQueryParameter? value) { -// if (value?.isSet ?? false) { -// return options[value!.id]?.name ?? 'undefined'; -// } else if (value?.onlyNotAssigned ?? false) { -// return S.of(context)!.notAssigned; -// } else if (value?.onlyAssigned ?? false) { -// return S.of(context)!.anyAssigned; -// } -// return ''; -// } - -// @override -// Widget build(BuildContext context) { -// final isEnabled = options.values.any((e) => (e.documentCount ?? 0) > 0) || -// addLabelPageBuilder != null; -// return FormBuilderField( -// name: name, -// initialValue: initialValue, -// onChanged: onChanged, -// enabled: isEnabled, -// builder: (field) { -// final controller = TextEditingController( -// text: _buildText(context, field.value), -// ); -// final displayedSuggestions = -// suggestions.whereNot((e) => e.id == field.value?.id).toList(); - -// return Column( -// children: [ -// OpenContainer( -// middleColor: Theme.of(context).colorScheme.background, -// closedColor: Theme.of(context).colorScheme.background, -// openColor: Theme.of(context).colorScheme.background, -// closedShape: InputBorder.none, -// openElevation: 0, -// closedElevation: 0, -// closedBuilder: (context, openForm) => Container( -// margin: const EdgeInsets.only(top: 4), -// child: -// ), -// openBuilder: (context, closeForm) => FullscreenLabelForm( -// addNewLabelText: addLabelText, -// leadingIcon: prefixIcon, -// onCreateNewLabel: addLabelPageBuilder != null -// ? (initialName) { -// return Navigator.of(context).push( -// MaterialPageRoute( -// builder: (context) => -// addLabelPageBuilder!(initialName), -// ), -// ); -// } -// : null, -// options: options, -// onSubmit: closeForm, -// initialValue: field.value, -// showAnyAssignedOption: showAnyAssignedOption, -// showNotAssignedOption: showNotAssignedOption, -// ), -// onClosed: (data) { -// if (data != null) { -// field.didChange(data); -// } -// }, -// ), -// if (displayedSuggestions.isNotEmpty) -// Column( -// crossAxisAlignment: CrossAxisAlignment.start, -// children: [ -// Text( -// S.of(context)!.suggestions, -// style: Theme.of(context).textTheme.bodySmall, -// ), -// SizedBox( -// height: 48, -// child: ListView.separated( -// scrollDirection: Axis.horizontal, -// itemCount: displayedSuggestions.length, -// itemBuilder: (context, index) { -// final suggestion = -// displayedSuggestions.elementAt(index); -// return ColoredChipWrapper( -// child: ActionChip( -// label: Text(suggestion.name), -// onPressed: () => field.didChange( -// IdQueryParameter.fromId(suggestion.id), -// ), -// ), -// ); -// }, -// separatorBuilder: (BuildContext context, int index) => -// const SizedBox(width: 4.0), -// ), -// ), -// ], -// ).padded(), -// ], -// ); -// }, -// ); -// } -// } diff --git a/lib/features/labels/view/widgets/fullscreen_label_form.dart b/lib/features/labels/view/widgets/fullscreen_label_form.dart index 9a176ac..d40fa00 100644 --- a/lib/features/labels/view/widgets/fullscreen_label_form.dart +++ b/lib/features/labels/view/widgets/fullscreen_label_form.dart @@ -39,7 +39,7 @@ class FullscreenLabelForm extends StatefulWidget { class _FullscreenLabelFormState extends State> { - late bool _showClearIcon = false; + bool _showClearIcon = false; final _textEditingController = TextEditingController(); final _focusNode = FocusNode(); diff --git a/lib/l10n/intl_cs.arb b/lib/l10n/intl_cs.arb index da83258..57b6289 100644 --- a/lib/l10n/intl_cs.arb +++ b/lib/l10n/intl_cs.arb @@ -697,5 +697,11 @@ "thisFieldIsRequired": "This field is required!", "@thisFieldIsRequired": { "description": "Message shown below the form field when a required field has not been filled out." - } + }, + "confirm": "Confirm", + "confirmAction": "Confirm action", + "@confirmAction": { + "description": "Typically used as a title to confirm a previously selected action" + }, + "areYouSureYouWantToContinue": "Are you sure you want to continue?" } \ No newline at end of file diff --git a/lib/l10n/intl_de.arb b/lib/l10n/intl_de.arb index c5129be..877b114 100644 --- a/lib/l10n/intl_de.arb +++ b/lib/l10n/intl_de.arb @@ -694,8 +694,14 @@ "@donateCoffee": { "description": "Label displayed in the app drawer" }, - "thisFieldIsRequired": "This field is required!", + "thisFieldIsRequired": "Dieses Feld ist erforderlich!", "@thisFieldIsRequired": { "description": "Message shown below the form field when a required field has not been filled out." - } + }, + "confirm": "Bestätigen", + "confirmAction": "Aktion bestätigen", + "@confirmAction": { + "description": "Typically used as a title to confirm a previously selected action" + }, + "areYouSureYouWantToContinue": "Bist Du sicher, dass Du fortfahren möchtest?" } \ No newline at end of file diff --git a/lib/l10n/intl_en.arb b/lib/l10n/intl_en.arb index 45df4f1..874b175 100644 --- a/lib/l10n/intl_en.arb +++ b/lib/l10n/intl_en.arb @@ -697,5 +697,11 @@ "thisFieldIsRequired": "This field is required!", "@thisFieldIsRequired": { "description": "Message shown below the form field when a required field has not been filled out." - } + }, + "confirm": "Confirm", + "confirmAction": "Confirm action", + "@confirmAction": { + "description": "Typically used as a title to confirm a previously selected action" + }, + "areYouSureYouWantToContinue": "Are you sure you want to continue?" } \ No newline at end of file diff --git a/lib/l10n/intl_fr.arb b/lib/l10n/intl_fr.arb index 1dc4aa5..718cbc0 100644 --- a/lib/l10n/intl_fr.arb +++ b/lib/l10n/intl_fr.arb @@ -697,5 +697,11 @@ "thisFieldIsRequired": "This field is required!", "@thisFieldIsRequired": { "description": "Message shown below the form field when a required field has not been filled out." - } + }, + "confirm": "Confirm", + "confirmAction": "Confirm action", + "@confirmAction": { + "description": "Typically used as a title to confirm a previously selected action" + }, + "areYouSureYouWantToContinue": "Are you sure you want to continue?" } \ No newline at end of file diff --git a/lib/l10n/intl_pl.arb b/lib/l10n/intl_pl.arb index 14a072c..14629b4 100644 --- a/lib/l10n/intl_pl.arb +++ b/lib/l10n/intl_pl.arb @@ -697,5 +697,11 @@ "thisFieldIsRequired": "This field is required!", "@thisFieldIsRequired": { "description": "Message shown below the form field when a required field has not been filled out." - } + }, + "confirm": "Confirm", + "confirmAction": "Confirm action", + "@confirmAction": { + "description": "Typically used as a title to confirm a previously selected action" + }, + "areYouSureYouWantToContinue": "Are you sure you want to continue?" } \ No newline at end of file diff --git a/lib/l10n/intl_ru.arb b/lib/l10n/intl_ru.arb index 253d4b0..34be213 100644 --- a/lib/l10n/intl_ru.arb +++ b/lib/l10n/intl_ru.arb @@ -697,5 +697,11 @@ "thisFieldIsRequired": "This field is required!", "@thisFieldIsRequired": { "description": "Message shown below the form field when a required field has not been filled out." - } + }, + "confirm": "Confirm", + "confirmAction": "Confirm action", + "@confirmAction": { + "description": "Typically used as a title to confirm a previously selected action" + }, + "areYouSureYouWantToContinue": "Are you sure you want to continue?" } \ No newline at end of file diff --git a/lib/l10n/intl_tr.arb b/lib/l10n/intl_tr.arb index 6a5c7cc..883a5cf 100644 --- a/lib/l10n/intl_tr.arb +++ b/lib/l10n/intl_tr.arb @@ -697,5 +697,11 @@ "thisFieldIsRequired": "This field is required!", "@thisFieldIsRequired": { "description": "Message shown below the form field when a required field has not been filled out." - } + }, + "confirm": "Confirm", + "confirmAction": "Confirm action", + "@confirmAction": { + "description": "Typically used as a title to confirm a previously selected action" + }, + "areYouSureYouWantToContinue": "Are you sure you want to continue?" } \ No newline at end of file