Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions lib/localizations/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,9 @@
"keyHint": "Schlüssel",
"valueHint": "Wert",
"atLeastOneTagRequired": "Mindestens ein Tag ist erforderlich",
"profileSaved": "Profil \"{}\" gespeichert"
"profileSaved": "Profil \"{}\" gespeichert",
"removeTagTitle": "Tag entfernen?",
"removeTagMessage": "\"{}\" von diesem Profil entfernen?"
},
"operatorProfileEditor": {
"newOperatorProfile": "Neues Betreiber-Profil",
Expand Down Expand Up @@ -392,7 +394,9 @@
"existingTagsTitle": "Vorhandene Tags",
"existingTagsDescription": "Bearbeiten Sie die vorhandenen Tags auf diesem Gerät. Hinzufügen, entfernen oder ändern Sie beliebige Tags:",
"existingOperator": "<Vorhandener Betreiber>",
"existingOperatorTags": "vorhandene Betreiber-Tags"
"existingOperatorTags": "vorhandene Betreiber-Tags",
"removeTagTitle": "Tag entfernen?",
"removeTagMessage": "\"{}\" von diesem Knoten entfernen?"
},
"layerSelector": {
"cannotChangeTileTypes": "Kachel-Typen können während des Herunterladens von Offline-Bereichen nicht geändert werden",
Expand Down
8 changes: 6 additions & 2 deletions lib/localizations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,9 @@
"keyHint": "key",
"valueHint": "value",
"atLeastOneTagRequired": "At least one tag is required",
"profileSaved": "Profile \"{}\" saved"
"profileSaved": "Profile \"{}\" saved",
"removeTagTitle": "Remove tag?",
"removeTagMessage": "Remove \"{}\" from this profile?"
},
"operatorProfileEditor": {
"newOperatorProfile": "New Operator Profile",
Expand Down Expand Up @@ -429,7 +431,9 @@
"existingTagsTitle": "Existing Tags",
"existingTagsDescription": "Edit the existing tags on this device. Add, remove, or modify any tag:",
"existingOperator": "<Existing operator>",
"existingOperatorTags": "existing operator tags"
"existingOperatorTags": "existing operator tags",
"removeTagTitle": "Remove tag?",
"removeTagMessage": "Remove \"{}\" from this node?"
},
"layerSelector": {
"cannotChangeTileTypes": "Cannot change tile types while downloading offline areas",
Expand Down
8 changes: 6 additions & 2 deletions lib/localizations/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,9 @@
"keyHint": "clave",
"valueHint": "valor",
"atLeastOneTagRequired": "Se requiere al menos una etiqueta",
"profileSaved": "Perfil \"{}\" guardado"
"profileSaved": "Perfil \"{}\" guardado",
"removeTagTitle": "¿Eliminar etiqueta?",
"removeTagMessage": "¿Eliminar \"{}\" de este perfil?"
},
"operatorProfileEditor": {
"newOperatorProfile": "Nuevo Perfil de Operador",
Expand Down Expand Up @@ -429,7 +431,9 @@
"existingTagsTitle": "Etiquetas Existentes",
"existingTagsDescription": "Edite las etiquetas existentes en este dispositivo. Agregue, elimine o modifique cualquier etiqueta:",
"existingOperator": "<Operador existente>",
"existingOperatorTags": "etiquetas de operador existentes"
"existingOperatorTags": "etiquetas de operador existentes",
"removeTagTitle": "¿Eliminar etiqueta?",
"removeTagMessage": "¿Eliminar \"{}\" de este nodo?"
},
"layerSelector": {
"cannotChangeTileTypes": "No se pueden cambiar los tipos de teselas mientras se descargan áreas sin conexión",
Expand Down
8 changes: 6 additions & 2 deletions lib/localizations/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,9 @@
"keyHint": "clé",
"valueHint": "valeur",
"atLeastOneTagRequired": "Au moins une balise est requise",
"profileSaved": "Profil \"{}\" sauvegardé"
"profileSaved": "Profil \"{}\" sauvegardé",
"removeTagTitle": "Supprimer la balise ?",
"removeTagMessage": "Supprimer \"{}\" de ce profil ?"
},
"operatorProfileEditor": {
"newOperatorProfile": "Nouveau Profil d'Opérateur",
Expand Down Expand Up @@ -429,7 +431,9 @@
"existingTagsTitle": "Balises Existantes",
"existingTagsDescription": "Modifiez les balises existantes sur cet appareil. Ajoutez, supprimez ou modifiez n'importe quelle balise :",
"existingOperator": "<Opérateur existant>",
"existingOperatorTags": "balises d'opérateur existantes"
"existingOperatorTags": "balises d'opérateur existantes",
"removeTagTitle": "Supprimer la balise ?",
"removeTagMessage": "Supprimer \"{}\" de ce nœud ?"
},
"layerSelector": {
"cannotChangeTileTypes": "Impossible de changer les types de tuiles pendant le téléchargement des zones hors ligne",
Expand Down
8 changes: 6 additions & 2 deletions lib/localizations/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,9 @@
"keyHint": "chiave",
"valueHint": "valore",
"atLeastOneTagRequired": "È richiesto almeno un tag",
"profileSaved": "Profilo \"{}\" salvato"
"profileSaved": "Profilo \"{}\" salvato",
"removeTagTitle": "Rimuovere tag?",
"removeTagMessage": "Rimuovere \"{}\" da questo profilo?"
},
"operatorProfileEditor": {
"newOperatorProfile": "Nuovo Profilo Operatore",
Expand Down Expand Up @@ -429,7 +431,9 @@
"existingTagsTitle": "Tag Esistenti",
"existingTagsDescription": "Modifica i tag esistenti su questo dispositivo. Aggiungi, rimuovi o modifica qualsiasi tag:",
"existingOperator": "<Operatore esistente>",
"existingOperatorTags": "tag operatore esistenti"
"existingOperatorTags": "tag operatore esistenti",
"removeTagTitle": "Rimuovere tag?",
"removeTagMessage": "Rimuovere \"{}\" da questo nodo?"
},
"layerSelector": {
"cannotChangeTileTypes": "Impossibile cambiare tipi di tile durante il download di aree offline",
Expand Down
8 changes: 6 additions & 2 deletions lib/localizations/pt.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,9 @@
"keyHint": "chave",
"valueHint": "valor",
"atLeastOneTagRequired": "Pelo menos uma tag é obrigatória",
"profileSaved": "Perfil \"{}\" salvo"
"profileSaved": "Perfil \"{}\" salvo",
"removeTagTitle": "Remover tag?",
"removeTagMessage": "Remover \"{}\" deste perfil?"
},
"operatorProfileEditor": {
"newOperatorProfile": "Novo Perfil de Operador",
Expand Down Expand Up @@ -429,7 +431,9 @@
"existingTagsTitle": "Tags Existentes",
"existingTagsDescription": "Edite as tags existentes neste dispositivo. Adicione, remova ou modifique qualquer tag:",
"existingOperator": "<Operador existente>",
"existingOperatorTags": "tags de operador existentes"
"existingOperatorTags": "tags de operador existentes",
"removeTagTitle": "Remover tag?",
"removeTagMessage": "Remover \"{}\" deste nó?"
},
"layerSelector": {
"cannotChangeTileTypes": "Não é possível alterar tipos de tiles durante o download de áreas offline",
Expand Down
8 changes: 6 additions & 2 deletions lib/localizations/zh.json
Original file line number Diff line number Diff line change
Expand Up @@ -358,7 +358,9 @@
"keyHint": "键",
"valueHint": "值",
"atLeastOneTagRequired": "至少需要一个标签",
"profileSaved": "配置文件 \"{}\" 已保存"
"profileSaved": "配置文件 \"{}\" 已保存",
"removeTagTitle": "删除标签?",
"removeTagMessage": "从此配置文件中删除 \"{}\"?"
},
"operatorProfileEditor": {
"newOperatorProfile": "新建运营商配置文件",
Expand Down Expand Up @@ -429,7 +431,9 @@
"existingTagsTitle": "现有标签",
"existingTagsDescription": "编辑此设备上的现有标签。添加、删除或修改任何标签:",
"existingOperator": "<现有运营商>",
"existingOperatorTags": "现有运营商标签"
"existingOperatorTags": "现有运营商标签",
"removeTagTitle": "删除标签?",
"removeTagMessage": "从此节点中删除 \"{}\"?"
},
"layerSelector": {
"cannotChangeTileTypes": "在下载离线区域时无法更改瓦片类型",
Expand Down
26 changes: 26 additions & 0 deletions lib/screens/operator_profile_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ class _OperatorProfileEditorState extends State<OperatorProfileEditor> {
initialValue: _tags[i].value,
hintText: locService.t('profileEditor.valueHint'),
onChanged: (v) => setState(() => _tags[i] = MapEntry(_tags[i].key, v)),
onCleared: () => _confirmRemoveTag(i),
),
),
IconButton(
Expand All @@ -143,6 +144,31 @@ class _OperatorProfileEditorState extends State<OperatorProfileEditor> {
});
}

void _confirmRemoveTag(int index) async {
final tagKey = _tags[index].key;
final locService = LocalizationService.instance;
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text(locService.t('profileEditor.removeTagTitle')),
content: Text(locService.t('profileEditor.removeTagMessage', params: [tagKey])),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: Text(locService.cancel),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text(locService.t('actions.delete')),
),
],
),
);
if (confirmed == true && mounted) {
setState(() => _tags.removeAt(index));
}
}

void _save() {
final locService = LocalizationService.instance;
final name = _nameCtrl.text.trim();
Expand Down
28 changes: 27 additions & 1 deletion lib/screens/profile_editor.dart
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,10 @@ class _ProfileEditorState extends State<ProfileEditor> {
initialValue: _tags[i].value,
hintText: locService.t('profileEditor.valueHint'),
readOnly: !widget.profile.editable,
onChanged: !widget.profile.editable
onChanged: !widget.profile.editable
? (v) {} // No-op when read-only
: (v) => setState(() => _tags[i] = MapEntry(_tags[i].key, v)),
onCleared: !widget.profile.editable ? null : () => _confirmRemoveTag(i),
),
),
if (widget.profile.editable)
Expand All @@ -198,6 +199,31 @@ class _ProfileEditorState extends State<ProfileEditor> {
});
}

void _confirmRemoveTag(int index) async {
final tagKey = _tags[index].key;
final locService = LocalizationService.instance;
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text(locService.t('profileEditor.removeTagTitle')),
content: Text(locService.t('profileEditor.removeTagMessage', params: [tagKey])),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: Text(locService.cancel),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text(locService.t('actions.delete')),
),
],
),
);
if (confirmed == true && mounted) {
setState(() => _tags.removeAt(index));
}
}

String? _validateFov() {
final text = _fovCtrl.text.trim();
if (text.isEmpty) return null; // Optional field
Expand Down
9 changes: 5 additions & 4 deletions lib/widgets/nsi_tag_value_field.dart
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,15 @@ class NSITagValueField extends StatefulWidget {
required this.onChanged,
this.readOnly = false,
this.hintText,
this.onCleared,
});

final String tagKey;
final String initialValue;
final ValueChanged<String> onChanged;
final bool readOnly;
final String? hintText;
final VoidCallback? onCleared;

@override
State<NSITagValueField> createState() => _NSITagValueFieldState();
Expand Down Expand Up @@ -133,11 +135,10 @@ class _NSITagValueFieldState extends State<NSITagValueField> {
widget.onChanged(value);
},
onSubmitted: (_) {
// Only auto-complete when there's text to match against.
// Otherwise, pressing Done on an empty field would auto-select
// the first suggestion, preventing users from clearing values.
if (controller.text.isNotEmpty) {
if (controller.text.trim().isNotEmpty) {
onFieldSubmitted();
} else {
widget.onCleared?.call();
}
Comment thread
dougborg marked this conversation as resolved.
},
);
Expand Down
26 changes: 26 additions & 0 deletions lib/widgets/refine_tags_sheet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,7 @@ class _RefineTagsSheetState extends State<RefineTagsSheet> {
_additionalExistingTags[index] = MapEntry(_additionalExistingTags[index].key, newValue);
});
},
onCleared: () => _confirmRemoveAdditionalTag(index),
),
),
const SizedBox(width: 8),
Expand Down Expand Up @@ -544,4 +545,29 @@ class _RefineTagsSheetState extends State<RefineTagsSheet> {
_additionalExistingTags.removeAt(index);
});
}

void _confirmRemoveAdditionalTag(int index) async {
final tagKey = _additionalExistingTags[index].key;
final locService = LocalizationService.instance;
final confirmed = await showDialog<bool>(
context: context,
builder: (context) => AlertDialog(
title: Text(locService.t('refineTagsSheet.removeTagTitle')),
content: Text(locService.t('refineTagsSheet.removeTagMessage', params: [tagKey])),
actions: [
TextButton(
onPressed: () => Navigator.pop(context, false),
child: Text(locService.cancel),
),
TextButton(
onPressed: () => Navigator.pop(context, true),
child: Text(locService.t('actions.delete')),
),
],
),
);
if (confirmed == true && mounted) {
_removeAdditionalTag(index);
}
}
}
Loading