Skip to content

Added a export to a GPX#134

Merged
wel97459 merged 7 commits into
mainfrom
dev-gpx
Feb 9, 2026
Merged

Added a export to a GPX#134
wel97459 merged 7 commits into
mainfrom
dev-gpx

Conversation

@wel97459

@wel97459 wel97459 commented Feb 5, 2026

Copy link
Copy Markdown
Collaborator

Added a export to a GPX file, this allows you put your contacts on other maping apps or share a network in a one export.

This needs testing on iPhones, I was able to tested on Android and works well.

Copilot AI review requested due to automatic review settings February 5, 2026 21:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds GPX export functionality to the meshcore-open app, allowing users to export their contacts (repeaters, chat contacts, or all entities) with location data to a GPX file format for use with other mapping applications or for sharing the network.

Changes:

  • Added three new dependencies: gpx for GPX file generation, path_provider for file system access, and share_plus for native sharing functionality
  • Implemented a new GpxExport utility class that exports contacts with location data to GPX format with separate methods for repeaters, chat contacts, and all entities
  • Added UI integration in the settings screen with three export options presented as list tiles in a new export card

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 20 comments.

File Description
pubspec.yaml Added three dependencies (gpx, path_provider, share_plus) to support GPX export functionality
lib/utils/gpx_export.dart New utility class implementing GPX export logic with methods to filter and export different contact types
lib/screens/settings_screen.dart Added export card with three export options and handler for displaying export result messages
lib/l10n/app_en.arb Added localization strings for export UI labels, subtitles, and status messages

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread lib/utils/gpx_export.dart Outdated
Comment on lines +157 to +158
// Optional cleanup (uncomment if you don't want to keep the file)
// await file.delete();

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The exported GPX files are saved to the application documents directory but are never cleaned up (the cleanup code is commented out at line 158). Over time, this could accumulate many files and consume storage space. Consider implementing automatic cleanup of old export files, or at least uncomment the file deletion after successful sharing.

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart Outdated
Comment on lines +52 to +58
if (repeater.latitude == null || repeater.longitude == null) {
continue;
}
_addContact(
repeater.name,
repeater.latitude ?? 0.0,
repeater.longitude ?? 0.0,

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redundant null-coalescing operator. The code already checks if latitude/longitude are null on the previous lines (52-54), so when adding the contact on lines 57-58, the null-coalescing operator (?? 0.0) will never be used. Either remove the redundant check on lines 52-54 and rely on the null-coalescing, or remove the null-coalescing operators as they serve no purpose after the null check.

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart Outdated
Comment on lines +66 to +75
final repeaters = contacts.where((c) => c.type == advTypeChat).toList();
for (var repeater in repeaters) {
if (repeater.latitude == null || repeater.longitude == null) {
continue;
}
_addContact(
repeater.name,
repeater.latitude ?? 0.0,
repeater.longitude ?? 0.0,
"Type: ${repeater.typeLabel}\nPublic Key: ${repeater.publicKeyHex}",

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name 'repeaters' is misleading when filtering for 'advTypeChat' contacts. This method is supposed to add contacts (chat users), not repeaters. The variable should be named 'contacts' or 'chatContacts' to accurately reflect what it contains.

Suggested change
final repeaters = contacts.where((c) => c.type == advTypeChat).toList();
for (var repeater in repeaters) {
if (repeater.latitude == null || repeater.longitude == null) {
continue;
}
_addContact(
repeater.name,
repeater.latitude ?? 0.0,
repeater.longitude ?? 0.0,
"Type: ${repeater.typeLabel}\nPublic Key: ${repeater.publicKeyHex}",
final chatContacts = contacts.where((c) => c.type == advTypeChat).toList();
for (var chatContact in chatContacts) {
if (chatContact.latitude == null || chatContact.longitude == null) {
continue;
}
_addContact(
chatContact.name,
chatContact.latitude ?? 0.0,
chatContact.longitude ?? 0.0,
"Type: ${chatContact.typeLabel}\nPublic Key: ${chatContact.publicKeyHex}",

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart Outdated
Comment on lines +137 to +138
text: 'Repeater locations exported from meshcore-open app as GPX file.',
subject: 'Meshcore Repeaters GPX Export',

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The share text says 'Repeater locations' but this export can be used for repeaters, contacts, or all entities. The share text should be more generic to accurately describe what's being shared in all use cases.

Suggested change
text: 'Repeater locations exported from meshcore-open app as GPX file.',
subject: 'Meshcore Repeaters GPX Export',
text: 'Locations exported from meshcore-open app as a GPX file.',
subject: 'Meshcore GPX Export',

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart Outdated
// 1. Build GPX content (your existing logic – unchanged here)
final gpx = Gpx()
..version = '1.1'
..creator = 'meshcore-open Repeater Exporter'

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GPX creator is hardcoded as 'meshcore-open Repeater Exporter' but this export is used for more than just repeaters (also chat contacts and all entities). Consider using a more generic creator name like 'meshcore-open Contact Exporter' or 'meshcore-open'.

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart Outdated
Comment on lines +66 to +75
final repeaters = contacts.where((c) => c.type == advTypeChat).toList();
for (var repeater in repeaters) {
if (repeater.latitude == null || repeater.longitude == null) {
continue;
}
_addContact(
repeater.name,
repeater.latitude ?? 0.0,
repeater.longitude ?? 0.0,
"Type: ${repeater.typeLabel}\nPublic Key: ${repeater.publicKeyHex}",

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name 'repeater' is misleading when iterating over chat contacts (advTypeChat). Since this method filters for chat contacts, the iteration variable should be named 'contact' or 'chatContact' to match its actual type.

Suggested change
final repeaters = contacts.where((c) => c.type == advTypeChat).toList();
for (var repeater in repeaters) {
if (repeater.latitude == null || repeater.longitude == null) {
continue;
}
_addContact(
repeater.name,
repeater.latitude ?? 0.0,
repeater.longitude ?? 0.0,
"Type: ${repeater.typeLabel}\nPublic Key: ${repeater.publicKeyHex}",
final chatContacts = contacts.where((c) => c.type == advTypeChat).toList();
for (var chatContact in chatContacts) {
if (chatContact.latitude == null || chatContact.longitude == null) {
continue;
}
_addContact(
chatContact.name,
chatContact.latitude ?? 0.0,
chatContact.longitude ?? 0.0,
"Type: ${chatContact.typeLabel}\nPublic Key: ${chatContact.publicKeyHex}",

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart Outdated
Comment on lines +82 to +90
for (var repeater in contacts.toList()) {
if (repeater.latitude == null || repeater.longitude == null) {
continue;
}
_addContact(
repeater.name,
repeater.latitude ?? 0.0,
repeater.longitude ?? 0.0,
"Type: ${repeater.typeLabel}\nPublic Key: ${repeater.publicKeyHex}",

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name 'repeater' is misleading when iterating over all contacts. Since this method processes all contact types (including chat, repeater, room, and sensor types), the iteration variable should be named 'contact' to accurately reflect what it contains.

Suggested change
for (var repeater in contacts.toList()) {
if (repeater.latitude == null || repeater.longitude == null) {
continue;
}
_addContact(
repeater.name,
repeater.latitude ?? 0.0,
repeater.longitude ?? 0.0,
"Type: ${repeater.typeLabel}\nPublic Key: ${repeater.publicKeyHex}",
for (var contact in contacts.toList()) {
if (contact.latitude == null || contact.longitude == null) {
continue;
}
_addContact(
contact.name,
contact.latitude ?? 0.0,
contact.longitude ?? 0.0,
"Type: ${contact.typeLabel}\nPublic Key: ${contact.publicKeyHex}",

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart Outdated
..creator = 'meshcore-open Repeater Exporter'
..metadata = Metadata(
name: 'Meshcore Repeaters',
desc: 'Repeater & room locations exported from meshcore-open',

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The metadata description says 'Repeater & room locations' but this export can also include chat contacts (via addContacts) or all contact types (via addAll). The description should be more generic like 'Contact locations exported from meshcore-open' to accurately reflect all use cases.

Suggested change
desc: 'Repeater & room locations exported from meshcore-open',
desc: 'Contact locations exported from meshcore-open',

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart Outdated
Comment on lines +134 to +141
// 3. Modern share call (2025+ style)
final result = await SharePlus.instance.share(
ShareParams(
text: 'Repeater locations exported from meshcore-open app as GPX file.',
subject: 'Meshcore Repeaters GPX Export',
files: [XFile(path)],
// Optional: sharePositionOrigin: ... (if you want iPad popover positioning)
),

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The share_plus package API usage appears to be incorrect for version 12.0.1. The standard API in share_plus v12 is 'Share.shareXFiles([XFile(...)])' rather than 'SharePlus.instance.share(ShareParams(...))'. The ShareParams and SharePlus.instance pattern is not part of the standard share_plus API. Please verify the correct API usage for share_plus v12.0.1 and update accordingly.

Suggested change
// 3. Modern share call (2025+ style)
final result = await SharePlus.instance.share(
ShareParams(
text: 'Repeater locations exported from meshcore-open app as GPX file.',
subject: 'Meshcore Repeaters GPX Export',
files: [XFile(path)],
// Optional: sharePositionOrigin: ... (if you want iPad popover positioning)
),
// 3. Share GPX file using share_plus v12 API
final result = await Share.shareXFiles(
[XFile(path)],
text: 'Repeater locations exported from meshcore-open app as GPX file.',
subject: 'Meshcore Repeaters GPX Export',
// Optional: sharePositionOrigin: ... (if you want iPad popover positioning)

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This deprecated and is not valid.

Comment thread lib/utils/gpx_export.dart Outdated
.replaceAll('.', '-')
.split('T')
.join('_');
final path = '${dir.path}/meshcore_repeaters_$timestamp.gpx';

Copilot AI Feb 5, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filename contains 'meshcore_repeaters_' but this export function is also used for exporting chat contacts and all entities, not just repeaters. Consider making the filename more generic like 'meshcore_contacts_' or making it configurable based on what is being exported.

Copilot uses AI. Check for mistakes.
@446564

446564 commented Feb 7, 2026

Copy link
Copy Markdown
Collaborator

The robot seems very helpful as reviewer 😎 I don'thave iPhone but will give it a test on android as well.

When you address any changes, can you also run dart format?

Copilot AI review requested due to automatic review settings February 7, 2026 23:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 37 out of 37 changed files in this pull request and generated 6 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread pubspec.yaml
Comment on lines +60 to +62
gpx: ^2.3.0
path_provider: ^2.1.5
share_plus: ^12.0.1

Copilot AI Feb 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this repo commits pubspec.lock and CI caches/builds using it, adding new direct dependencies here should be accompanied by an updated pubspec.lock. Also, share_plus appears in the Windows/macOS registrants but not in Linux/iOS project files in the repo; ensure the platform plugin registrants are regenerated/committed consistently so desktop/mobile builds register the plugin everywhere.

Copilot uses AI. Check for mistakes.
Comment thread lib/l10n/app_en.arb Outdated
"settings_gpxExportNotAvailable": "Not supported on your device/OS",
"settings_gpxExportError": "There was an error when exporting.",
"settings_gpxExportRepeatersRoom": "Repeater & room server locations",
"settings_gpxExportRepeatersRoomFilename": "meshcore_reapters",

Copilot AI Feb 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo in the exported filename base: meshcore_reapters should be meshcore_repeaters (this affects the actual GPX filename generated for English locale).

Suggested change
"settings_gpxExportRepeatersRoomFilename": "meshcore_reapters",
"settings_gpxExportRepeatersRoomFilename": "meshcore_repeaters",

Copilot uses AI. Check for mistakes.
Comment thread lib/l10n/app_bg.arb Outdated
Comment on lines +1575 to +1579
"settings_gpxExportNoContacts": "Няма контакти за изlexport.",
"settings_gpxExportRepeatersSubtitle": "Изпраща повторители / roomserver с местоположение в GPX файл.",
"settings_gpxExportAllSubtitle": "Експортира всички контакти с местоположение в файл GPX.",
"settings_gpxExportRepeatersRoomFilename": "ядро на мрежата за повторни излъчвания",
"settings_gpxExportSuccess": "Успешно изlexport на файл GPX.",

Copilot AI Feb 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Bulgarian translations contain mixed Cyrillic/Latin text (изlexport), which appears to be an accidental placeholder/typo and is user-facing. Please replace with proper Bulgarian wording (pure Cyrillic).

Suggested change
"settings_gpxExportNoContacts": "Няма контакти за изlexport.",
"settings_gpxExportRepeatersSubtitle": "Изпраща повторители / roomserver с местоположение в GPX файл.",
"settings_gpxExportAllSubtitle": "Експортира всички контакти с местоположение в файл GPX.",
"settings_gpxExportRepeatersRoomFilename": "ядро на мрежата за повторни излъчвания",
"settings_gpxExportSuccess": "Успешно изlexport на файл GPX.",
"settings_gpxExportNoContacts": "Няма контакти за експортиране.",
"settings_gpxExportRepeatersSubtitle": "Изпраща повторители / roomserver с местоположение в GPX файл.",
"settings_gpxExportAllSubtitle": "Експортира всички контакти с местоположение в файл GPX.",
"settings_gpxExportRepeatersRoomFilename": "ядро на мрежата за повторни излъчвания",
"settings_gpxExportSuccess": "Успешно експортиране на файл GPX.",

Copilot uses AI. Check for mistakes.
Comment on lines +708 to +725
switch (result) {
case gpxExportSuccess:
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(l10n.settings_gpxExportSuccess)));
case gpxExportNoContacts:
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_gpxExportNoContacts)),
);
case gpxExportNotAvailable:
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_gpxExportNotAvailable)),
);
case gpxExportFailed:
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(l10n.settings_gpxExportError)));
}

Copilot AI Feb 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The switch over result is missing terminating statements (break/return/etc.) for each case. In Dart this is a compile-time error, and it also means you can’t add handling for gpxExportCancelled (which exportGPX can return). Add break/return for each case and include an explicit case for gpxExportCancelled (even if it’s a no-op).

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart
Comment on lines +1 to +6
import 'package:flutter/foundation.dart';
import 'package:gpx/gpx.dart';
import 'package:meshcore_open/connector/meshcore_connector.dart';
import 'package:meshcore_open/connector/meshcore_protocol.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';

Copilot AI Feb 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file imports dart:io and uses File, but the project’s CI builds flutter build web; importing dart:io will fail web compilation. Split the implementation via conditional imports (IO vs web), or move the IO-specific code behind a platform-specific file and provide a web-safe stub that returns gpxExportNotAvailable (or implements a browser download/share).

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if we explicitly support web at this time

Comment thread lib/utils/gpx_export.dart Outdated
Comment on lines +152 to +154
// ignore: unnecessary_string_escapes
final path = '${dir.path}/$filename\_$timestamp.gpx';

Copilot AI Feb 7, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'${dir.path}/$filename\_$timestamp.gpx' contains \_, which is an invalid escape sequence in Dart strings (it won’t compile). You don’t need to escape _ here—remove the backslash (and the ignore).

Copilot uses AI. Check for mistakes.

@wel97459 wel97459 Feb 8, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without it, it thinks it part of the var name.

'${dir.path}/$filename\_$timestamp.gpx' contains \_, which is an invalid escape sequence in Dart strings (it won’t compile). You don’t need to escape _ here—remove the backslash (and the ignore).

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Without it it think it part of the var name.

'${dir.path}/$filename\_$timestamp.gpx' contains \_, which is an invalid escape sequence in Dart strings (it won’t compile). You don’t need to escape _ here—remove the backslash (and the ignore).

@446564 446564 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good over all, some good points brought up by cp.

I also could not get the file to save, but only share to another app. Which worked well importing straight into Organic Maps.

Screenshot_20260207-164046 Screenshot_20260207-164924

Copilot AI review requested due to automatic review settings February 8, 2026 20:15

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 39 out of 40 changed files in this pull request and generated 15 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +744 to +747
_gpxExport(
exporter,
l10n.map_repeater,
l10n.settings_gpxExportRepeatersRoom,

Copilot AI Feb 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GPX metadata name passed to the exporter uses l10n.map_repeater, which will label the exported file as “Repeater” even though this action exports repeater+room locations. Consider using a GPX-specific label (e.g. settings_gpxExportRepeatersRoom or settings_gpxExportRepeaters) so the shared file metadata matches its contents.

Copilot uses AI. Check for mistakes.
Comment on lines +780 to +784
_gpxExport(
exporter,
l10n.map_repeater,
l10n.settings_gpxExportAllContacts,
"meshcore_all_",

Copilot AI Feb 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The GPX metadata name passed to the exporter uses l10n.map_repeater, which will label the exported file as “Repeater” even though this action exports all contacts. Use an “all contacts” label so the GPX metadata matches the export.

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart
Comment on lines +112 to +114
if (_contacts.isEmpty) {
debugPrint("No repeaters to export – nothing to share.");
return gpxExportNoContacts;

Copilot AI Feb 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The log message says "No repeaters to export" but this exporter is also used for contacts/all exports. Update the message to something generic like "No contacts to export" to avoid misleading logs.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same thing

Comment thread tools/translate.py Outdated
Comment on lines +1 to +20
#!/usr/bin/env python3
"""
translate_arb_with_translategemma.py
translate_arb_with_ollama.py

Translates ARB/JSON localization files using TranslateGemma via Ollama.
Preserves placeholders like {deviceName} and ICU plural/select formats.
Translates ARB/JSON localization values using a local Ollama model, while:
- preserving keys
- skipping "@@locale" and all "@key" metadata blocks
- preserving placeholders like {deviceName}, {count, plural, ...}
- writing a new file with updated @@locale
- printing progress as it runs

Usage:
# Translate all strings:
python translate.py --in lib/l10n/app_en.arb --out lib/l10n/app_es.arb --to-locale es

# Translate only missing strings:
python translate.py --in lib/l10n/app_en.arb --out lib/l10n/app_es.arb --to-locale es --missing-only
python translate_arb_with_ollama.py \
--in ../lib/l10n/app_en.arb \
--out ../lib/l10n/app_es.arb \
--to-locale es \
--model ministral-3:latest \
--temperature 0 \
--concurrency 4

Copilot AI Feb 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The usage header and examples refer to translate_arb_with_ollama.py, but the file in this repo is tools/translate.py and there is no translate_arb_with_ollama.py. Update the docstring/examples (or rename the file) so the documented command actually works.

Copilot uses AI. Check for mistakes.
Comment thread tools/translate.py Outdated
Comment on lines +1 to +10
#!/usr/bin/env python3
"""
translate_arb_with_translategemma.py
translate_arb_with_ollama.py

Translates ARB/JSON localization files using TranslateGemma via Ollama.
Preserves placeholders like {deviceName} and ICU plural/select formats.
Translates ARB/JSON localization values using a local Ollama model, while:
- preserving keys
- skipping "@@locale" and all "@key" metadata blocks
- preserving placeholders like {deviceName}, {count, plural, ...}
- writing a new file with updated @@locale
- printing progress as it runs

Copilot AI Feb 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is described as adding GPX export, but it also includes a large unrelated rewrite of tools/translate.py. Consider splitting the translation tooling changes into a separate PR to keep scope focused and reduce review/merge risk.

Copilot uses AI. Check for mistakes.
Comment thread lib/l10n/app_bg.arb
Comment on lines +1578 to +1579
"settings_gpxExportSuccess": "Успешно изlexport на файл GPX.",
"settings_gpxExportNoContacts": "Няма контакти за изlexport.",

Copilot AI Feb 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The Bulgarian translation contains the non-word “изlexport” (mixed Cyrillic/Latin), which looks like a generation artifact. Replace it with proper Bulgarian (e.g. use “експортиране” consistently).

Suggested change
"settings_gpxExportSuccess": "Успешно изlexport на файл GPX.",
"settings_gpxExportNoContacts": "Няма контакти за изlexport.",
"settings_gpxExportSuccess": "Успешно експортиране на файл GPX.",
"settings_gpxExportNoContacts": "Няма контакти за експортиране.",

Copilot uses AI. Check for mistakes.
Comment thread tools/translate.py Outdated
name = m.group(1)
# Check if this appears as a simple {name} placeholder (not inside ICU)
# by looking at what comes after it
full_match = m.group(0)

Copilot AI Feb 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable full_match is not used.

Copilot uses AI. Check for mistakes.
Comment thread tools/translate.py Outdated
"""Check if string contains ICU plural/select block."""
return bool(ICU_VAR_RE.search(s))
def build_prompt(text: str, target_lang: str, placeholder_names: List[str], has_icu: bool, ask_confidence: bool = False) -> str:
preserve_list = "\n".join(f"- {{{t}}}" for t in placeholder_names) if placeholder_names else "- (none)"

Copilot AI Feb 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable preserve_list is not used.

Copilot uses AI. Check for mistakes.
Comment thread tools/translate.py Outdated
if match:
confidence = int(match.group(1))
return translation, confidence
except ValueError:

Copilot AI Feb 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'except' clause does nothing but pass and there is no explanatory comment.

Copilot uses AI. Check for mistakes.
Comment thread tools/translate.py Outdated
return key, fallback_out, None, True
elif fallback_ok and not ok:
# Original failed validation but fallback passed
return key, fallback_out, None, True

Copilot AI Feb 8, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This statement is unreachable.

Copilot uses AI. Check for mistakes.

@446564 446564 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the remaining changes are not super important

Comment thread lib/utils/gpx_export.dart
Comment on lines +1 to +6
import 'package:flutter/foundation.dart';
import 'package:gpx/gpx.dart';
import 'package:meshcore_open/connector/meshcore_connector.dart';
import 'package:meshcore_open/connector/meshcore_protocol.dart';
import 'package:path_provider/path_provider.dart';
import 'dart:io';

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know if we explicitly support web at this time

Comment thread lib/utils/gpx_export.dart

Future<int> exportGPX() async {
if (_contacts.isEmpty) {
debugPrint("No repeaters to export – nothing to share.");

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, however it's just a debug print

Comment thread lib/utils/gpx_export.dart
Comment on lines +112 to +114
if (_contacts.isEmpty) {
debugPrint("No repeaters to export – nothing to share.");
return gpxExportNoContacts;

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same thing

Copilot AI review requested due to automatic review settings February 9, 2026 01:13
@wel97459 wel97459 merged commit 24de98d into main Feb 9, 2026
10 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 37 out of 38 changed files in this pull request and generated 3 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +708 to +716
switch (result) {
case gpxExportSuccess:
ScaffoldMessenger.of(
context,
).showSnackBar(SnackBar(content: Text(l10n.settings_gpxExportSuccess)));
case gpxExportNoContacts:
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(l10n.settings_gpxExportNoContacts)),
);

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this switch, the gpxExportSuccess case doesn’t end with break/return, which makes the switch invalid in Dart (cases can’t fall through). Add a break (or return) after showing the success SnackBar; also ensure the other cases are still reached correctly.

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart
Comment on lines +152 to +162
final path = '${dir.path}/$filename$timestamp.gpx';

final file = File(path);
await file.writeAsString(xml);

final result = await SharePlus.instance.share(
ShareParams(text: shareText, subject: subject, files: [XFile(path)]),
);

await file.delete();

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If writeAsString or share(...) throws, the GPX file is never deleted because file.delete() is only reached on the success path. Consider moving cleanup into a finally block (and optionally swallowing delete errors) so temporary exports don’t accumulate and a successful share isn’t reported as failed due to a cleanup exception.

Copilot uses AI. Check for mistakes.
Comment thread lib/utils/gpx_export.dart
Comment on lines +112 to +114
if (_contacts.isEmpty) {
debugPrint("No repeaters to export – nothing to share.");
return gpxExportNoContacts;

Copilot AI Feb 9, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This debug log is shown when _contacts is empty, but it hard-codes “No repeaters to export” even when exporting chat contacts or “all”. Update the message to be generic (e.g., “No contacts to export”) so diagnostics match the selected export type.

Copilot uses AI. Check for mistakes.
@wel97459 wel97459 deleted the dev-gpx branch March 7, 2026 09:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants