Merge pull request #217 from MeshEnvy/chrome/main

enh: Chrome compatibility
This commit is contained in:
zjs81
2026-03-01 20:02:29 -07:00
committed by GitHub
48 changed files with 399 additions and 31 deletions
+38
View File
@@ -0,0 +1,38 @@
name: Deploy to Cloudflare Workers
on:
push:
tags:
- '*'
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Flutter
uses: subosito/flutter-action@v2
with:
channel: 'stable'
# Match local development version which provides Dart 3.11.0
flutter-version: '3.41.2'
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Get dependencies
run: flutter pub get
- name: Build Web
run: bun run build
- name: Deploy to Cloudflare
uses: cloudflare/wrangler-action@v3
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
command: deploy
+3
View File
@@ -83,3 +83,6 @@ keystore.properties
# IDE # IDE
.vscode/launch.json .vscode/launch.json
.vscode/settings.json .vscode/settings.json
# Cloudflare Wrangler
.wrangler
+3 -7
View File
@@ -717,17 +717,13 @@ class MeshCoreConnector extends ChangeNotifier {
_scanSubscription = FlutterBluePlus.scanResults.listen((results) { _scanSubscription = FlutterBluePlus.scanResults.listen((results) {
_scanResults.clear(); _scanResults.clear();
for (var result in results) { _scanResults.addAll(results);
if (result.device.platformName.startsWith("MeshCore-") ||
result.advertisementData.advName.startsWith("MeshCore-") ||
result.advertisementData.advName.startsWith("Whisper-")) {
_scanResults.add(result);
}
}
notifyListeners(); notifyListeners();
}); });
await FlutterBluePlus.startScan( await FlutterBluePlus.startScan(
withKeywords: ["MeshCore-", "Whisper-"],
webOptionalServices: [Guid(MeshCoreUuids.service)],
timeout: timeout, timeout: timeout,
androidScanMode: AndroidScanMode.lowLatency, androidScanMode: AndroidScanMode.lowLatency,
); );
+2
View File
@@ -1606,6 +1606,8 @@
"scanner_bluetoothOff": "Bluetooth е изключен.", "scanner_bluetoothOff": "Bluetooth е изключен.",
"scanner_enableBluetooth": "Активирайте Bluetooth", "scanner_enableBluetooth": "Активирайте Bluetooth",
"scanner_bluetoothOffMessage": "Моля, активирайте Bluetooth, за да сканирате за устройства.", "scanner_bluetoothOffMessage": "Моля, активирайте Bluetooth, за да сканирате за устройства.",
"scanner_chromeRequired": "Изисква се браузър Chrome",
"scanner_chromeRequiredMessage": "Това уеб приложение изисква Google Chrome или браузър, базиран на Chromium, за поддръжка на Bluetooth.",
"snrIndicator_lastSeen": "Последно видян", "snrIndicator_lastSeen": "Последно видян",
"snrIndicator_nearByRepeaters": "Близки повтарящи се устройства", "snrIndicator_nearByRepeaters": "Близки повтарящи се устройства",
"chat_ShowAllPaths": "Покажи всички пътища", "chat_ShowAllPaths": "Покажи всички пътища",
+2
View File
@@ -1635,6 +1635,8 @@
"pathTrace_clearTooltip": "Pfad löschen", "pathTrace_clearTooltip": "Pfad löschen",
"map_pathTraceCancelled": "Pfadverfolgung abgebrochen.", "map_pathTraceCancelled": "Pfadverfolgung abgebrochen.",
"scanner_bluetoothOffMessage": "Bitte aktivieren Sie Bluetooth, um nach Geräten zu suchen.", "scanner_bluetoothOffMessage": "Bitte aktivieren Sie Bluetooth, um nach Geräten zu suchen.",
"scanner_chromeRequired": "Chrome Browser erforderlich",
"scanner_chromeRequiredMessage": "Diese Webanwendung erfordert Google Chrome oder einen Chromium-basierten Browser für die Bluetooth-Unterstützung.",
"scanner_bluetoothOff": "Bluetooth ist deaktiviert.", "scanner_bluetoothOff": "Bluetooth ist deaktiviert.",
"scanner_enableBluetooth": "Bluetooth aktivieren", "scanner_enableBluetooth": "Bluetooth aktivieren",
"snrIndicator_lastSeen": "Zuletzt gesehen", "snrIndicator_lastSeen": "Zuletzt gesehen",
+2
View File
@@ -72,6 +72,8 @@
"scanner_scan": "Scan", "scanner_scan": "Scan",
"scanner_bluetoothOff": "Bluetooth is off", "scanner_bluetoothOff": "Bluetooth is off",
"scanner_bluetoothOffMessage": "Please turn on Bluetooth to scan for devices", "scanner_bluetoothOffMessage": "Please turn on Bluetooth to scan for devices",
"scanner_chromeRequired": "Chrome Browser Required",
"scanner_chromeRequiredMessage": "This web application requires Google Chrome or a Chromium-based browser for Bluetooth support.",
"scanner_enableBluetooth": "Enable Bluetooth", "scanner_enableBluetooth": "Enable Bluetooth",
"device_quickSwitch": "Quick switch", "device_quickSwitch": "Quick switch",
"device_meshcore": "MeshCore", "device_meshcore": "MeshCore",
+2
View File
@@ -1632,6 +1632,8 @@
"map_removeLast": "Eliminar último", "map_removeLast": "Eliminar último",
"map_pathTraceCancelled": "Rastreo de ruta cancelado.", "map_pathTraceCancelled": "Rastreo de ruta cancelado.",
"scanner_bluetoothOffMessage": "Por favor, active el Bluetooth para escanear dispositivos.", "scanner_bluetoothOffMessage": "Por favor, active el Bluetooth para escanear dispositivos.",
"scanner_chromeRequired": "Navegador Chrome requerido",
"scanner_chromeRequiredMessage": "Esta aplicación web requiere Google Chrome o un navegador basado en Chromium para el soporte de Bluetooth.",
"scanner_bluetoothOff": "Bluetooth está desactivado.", "scanner_bluetoothOff": "Bluetooth está desactivado.",
"scanner_enableBluetooth": "Habilitar Bluetooth", "scanner_enableBluetooth": "Habilitar Bluetooth",
"snrIndicator_nearByRepeaters": "Repetidores cercanos", "snrIndicator_nearByRepeaters": "Repetidores cercanos",
+2
View File
@@ -1604,6 +1604,8 @@
"map_removeLast": "Supprimer le dernier", "map_removeLast": "Supprimer le dernier",
"map_runTrace": "Exécuter la traçage de chemin", "map_runTrace": "Exécuter la traçage de chemin",
"scanner_bluetoothOffMessage": "Veuillez activer le Bluetooth pour rechercher des appareils.", "scanner_bluetoothOffMessage": "Veuillez activer le Bluetooth pour rechercher des appareils.",
"scanner_chromeRequired": "Navigateur Chrome requis",
"scanner_chromeRequiredMessage": "Cette application web nécessite Google Chrome ou un navigateur basé sur Chromium pour le support Bluetooth.",
"scanner_bluetoothOff": "Le Bluetooth est désactivé.", "scanner_bluetoothOff": "Le Bluetooth est désactivé.",
"scanner_enableBluetooth": "Activer le Bluetooth", "scanner_enableBluetooth": "Activer le Bluetooth",
"snrIndicator_lastSeen": "Dernière fois vu", "snrIndicator_lastSeen": "Dernière fois vu",
+2
View File
@@ -1605,6 +1605,8 @@
"map_tapToAdd": "Tocca i nodi per aggiungerli al percorso.", "map_tapToAdd": "Tocca i nodi per aggiungerli al percorso.",
"scanner_bluetoothOff": "Il Bluetooth è disattivato.", "scanner_bluetoothOff": "Il Bluetooth è disattivato.",
"scanner_bluetoothOffMessage": "Si prega di attivare il Bluetooth per effettuare la scansione dei dispositivi.", "scanner_bluetoothOffMessage": "Si prega di attivare il Bluetooth per effettuare la scansione dei dispositivi.",
"scanner_chromeRequired": "Browser Chrome richiesto",
"scanner_chromeRequiredMessage": "Questa applicazione web richiede Google Chrome o un browser basato su Chromium per il supporto Bluetooth.",
"scanner_enableBluetooth": "Abilita il Bluetooth", "scanner_enableBluetooth": "Abilita il Bluetooth",
"snrIndicator_nearByRepeaters": "Ripetitori vicini", "snrIndicator_nearByRepeaters": "Ripetitori vicini",
"snrIndicator_lastSeen": "Ultimo accesso", "snrIndicator_lastSeen": "Ultimo accesso",
+12
View File
@@ -388,6 +388,18 @@ abstract class AppLocalizations {
/// **'Please turn on Bluetooth to scan for devices'** /// **'Please turn on Bluetooth to scan for devices'**
String get scanner_bluetoothOffMessage; String get scanner_bluetoothOffMessage;
/// No description provided for @scanner_chromeRequired.
///
/// In en, this message translates to:
/// **'Chrome Browser Required'**
String get scanner_chromeRequired;
/// No description provided for @scanner_chromeRequiredMessage.
///
/// In en, this message translates to:
/// **'This web application requires Google Chrome or a Chromium-based browser for Bluetooth support.'**
String get scanner_chromeRequiredMessage;
/// No description provided for @scanner_enableBluetooth. /// No description provided for @scanner_enableBluetooth.
/// ///
/// In en, this message translates to: /// In en, this message translates to:
+7
View File
@@ -150,6 +150,13 @@ class AppLocalizationsBg extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Моля, активирайте Bluetooth, за да сканирате за устройства.'; 'Моля, активирайте Bluetooth, за да сканирате за устройства.';
@override
String get scanner_chromeRequired => 'Изисква се браузър Chrome';
@override
String get scanner_chromeRequiredMessage =>
'Това уеб приложение изисква Google Chrome или браузър, базиран на Chromium, за поддръжка на Bluetooth.';
@override @override
String get scanner_enableBluetooth => 'Активирайте Bluetooth'; String get scanner_enableBluetooth => 'Активирайте Bluetooth';
+7
View File
@@ -150,6 +150,13 @@ class AppLocalizationsDe extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Bitte aktivieren Sie Bluetooth, um nach Geräten zu suchen.'; 'Bitte aktivieren Sie Bluetooth, um nach Geräten zu suchen.';
@override
String get scanner_chromeRequired => 'Chrome Browser erforderlich';
@override
String get scanner_chromeRequiredMessage =>
'Diese Webanwendung erfordert Google Chrome oder einen Chromium-basierten Browser für die Bluetooth-Unterstützung.';
@override @override
String get scanner_enableBluetooth => 'Bluetooth aktivieren'; String get scanner_enableBluetooth => 'Bluetooth aktivieren';
+7
View File
@@ -149,6 +149,13 @@ class AppLocalizationsEn extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Please turn on Bluetooth to scan for devices'; 'Please turn on Bluetooth to scan for devices';
@override
String get scanner_chromeRequired => 'Chrome Browser Required';
@override
String get scanner_chromeRequiredMessage =>
'This web application requires Google Chrome or a Chromium-based browser for Bluetooth support.';
@override @override
String get scanner_enableBluetooth => 'Enable Bluetooth'; String get scanner_enableBluetooth => 'Enable Bluetooth';
+7
View File
@@ -150,6 +150,13 @@ class AppLocalizationsEs extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Por favor, active el Bluetooth para escanear dispositivos.'; 'Por favor, active el Bluetooth para escanear dispositivos.';
@override
String get scanner_chromeRequired => 'Navegador Chrome requerido';
@override
String get scanner_chromeRequiredMessage =>
'Esta aplicación web requiere Google Chrome o un navegador basado en Chromium para el soporte de Bluetooth.';
@override @override
String get scanner_enableBluetooth => 'Habilitar Bluetooth'; String get scanner_enableBluetooth => 'Habilitar Bluetooth';
+7
View File
@@ -150,6 +150,13 @@ class AppLocalizationsFr extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Veuillez activer le Bluetooth pour rechercher des appareils.'; 'Veuillez activer le Bluetooth pour rechercher des appareils.';
@override
String get scanner_chromeRequired => 'Navigateur Chrome requis';
@override
String get scanner_chromeRequiredMessage =>
'Cette application web nécessite Google Chrome ou un navigateur basé sur Chromium pour le support Bluetooth.';
@override @override
String get scanner_enableBluetooth => 'Activer le Bluetooth'; String get scanner_enableBluetooth => 'Activer le Bluetooth';
+7
View File
@@ -150,6 +150,13 @@ class AppLocalizationsIt extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Si prega di attivare il Bluetooth per effettuare la scansione dei dispositivi.'; 'Si prega di attivare il Bluetooth per effettuare la scansione dei dispositivi.';
@override
String get scanner_chromeRequired => 'Browser Chrome richiesto';
@override
String get scanner_chromeRequiredMessage =>
'Questa applicazione web richiede Google Chrome o un browser basato su Chromium per il supporto Bluetooth.';
@override @override
String get scanner_enableBluetooth => 'Abilita il Bluetooth'; String get scanner_enableBluetooth => 'Abilita il Bluetooth';
+7
View File
@@ -149,6 +149,13 @@ class AppLocalizationsNl extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Zorg ervoor dat Bluetooth is ingeschakeld om naar apparaten te zoeken.'; 'Zorg ervoor dat Bluetooth is ingeschakeld om naar apparaten te zoeken.';
@override
String get scanner_chromeRequired => 'Chrome-browser vereist';
@override
String get scanner_chromeRequiredMessage =>
'Deze webapplicatie vereist Google Chrome of een op Chromium gebaseerde browser voor Bluetooth-ondersteuning.';
@override @override
String get scanner_enableBluetooth => 'Activeer Bluetooth'; String get scanner_enableBluetooth => 'Activeer Bluetooth';
+7
View File
@@ -150,6 +150,13 @@ class AppLocalizationsPl extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Prosimy włączyć Bluetooth, aby przeskanować urządzenia.'; 'Prosimy włączyć Bluetooth, aby przeskanować urządzenia.';
@override
String get scanner_chromeRequired => 'Wymagana przeglądarka Chrome';
@override
String get scanner_chromeRequiredMessage =>
'Ta aplikacja internetowa wymaga przeglądarki Google Chrome lub opartej na Chromium do obsługi Bluetooth.';
@override @override
String get scanner_enableBluetooth => 'Włącz Bluetooth'; String get scanner_enableBluetooth => 'Włącz Bluetooth';
+7
View File
@@ -150,6 +150,13 @@ class AppLocalizationsPt extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Por favor, ative o Bluetooth para escanear por dispositivos.'; 'Por favor, ative o Bluetooth para escanear por dispositivos.';
@override
String get scanner_chromeRequired => 'Navegador Chrome necessário';
@override
String get scanner_chromeRequiredMessage =>
'Esta aplicação web requer o Google Chrome ou um navegador baseado no Chromium para suporte de Bluetooth.';
@override @override
String get scanner_enableBluetooth => 'Ative o Bluetooth'; String get scanner_enableBluetooth => 'Ative o Bluetooth';
+7
View File
@@ -149,6 +149,13 @@ class AppLocalizationsRu extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Пожалуйста, включите Bluetooth, чтобы найти устройства.'; 'Пожалуйста, включите Bluetooth, чтобы найти устройства.';
@override
String get scanner_chromeRequired => 'Требуется браузер Chrome';
@override
String get scanner_chromeRequiredMessage =>
'Для поддержки Bluetooth в этом веб-приложении требуется Google Chrome или браузер на базе Chromium.';
@override @override
String get scanner_enableBluetooth => 'Включите Bluetooth'; String get scanner_enableBluetooth => 'Включите Bluetooth';
+7
View File
@@ -150,6 +150,13 @@ class AppLocalizationsSk extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Prosím, zapnite Bluetooth, aby ste mohli skenovať pre zariadenia.'; 'Prosím, zapnite Bluetooth, aby ste mohli skenovať pre zariadenia.';
@override
String get scanner_chromeRequired => 'Vyžaduje sa prehliadač Chrome';
@override
String get scanner_chromeRequiredMessage =>
'Táto webová aplikácia vyžaduje Google Chrome alebo prehliadač založený na Chromium pre podporu Bluetooth.';
@override @override
String get scanner_enableBluetooth => 'Povolte Bluetooth'; String get scanner_enableBluetooth => 'Povolte Bluetooth';
+7
View File
@@ -150,6 +150,13 @@ class AppLocalizationsSl extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Prosimo, vklopite Bluetooth, da lahko poiščete naprave.'; 'Prosimo, vklopite Bluetooth, da lahko poiščete naprave.';
@override
String get scanner_chromeRequired => 'Zahtevan brskalnik Chrome';
@override
String get scanner_chromeRequiredMessage =>
'Ta spletna aplikacija za podporo Bluetooth zahteva Google Chrome ali brskalnik na osnovi Chromiuma.';
@override @override
String get scanner_enableBluetooth => 'Omogočite Bluetooth'; String get scanner_enableBluetooth => 'Omogočite Bluetooth';
+7
View File
@@ -149,6 +149,13 @@ class AppLocalizationsSv extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Vänligen aktivera Bluetooth för att söka efter enheter.'; 'Vänligen aktivera Bluetooth för att söka efter enheter.';
@override
String get scanner_chromeRequired => 'Chrome-webbläsare krävs';
@override
String get scanner_chromeRequiredMessage =>
'Denna webbapplikation kräver Google Chrome oder en Chromium-baserader webbläsare för Bluetooth-stöd.';
@override @override
String get scanner_enableBluetooth => 'Aktivera Bluetooth'; String get scanner_enableBluetooth => 'Aktivera Bluetooth';
+7
View File
@@ -150,6 +150,13 @@ class AppLocalizationsUk extends AppLocalizations {
String get scanner_bluetoothOffMessage => String get scanner_bluetoothOffMessage =>
'Будь ласка, увімкніть Bluetooth, щоб сканувати пристрої.'; 'Будь ласка, увімкніть Bluetooth, щоб сканувати пристрої.';
@override
String get scanner_chromeRequired => 'Потрібен браузер Chrome';
@override
String get scanner_chromeRequiredMessage =>
'Для підтримки Bluetooth у цьому веб-додатку потрібен Google Chrome або браузер на базі Chromium.';
@override @override
String get scanner_enableBluetooth => 'Увімкніть Bluetooth'; String get scanner_enableBluetooth => 'Увімкніть Bluetooth';
+7
View File
@@ -148,6 +148,13 @@ class AppLocalizationsZh extends AppLocalizations {
@override @override
String get scanner_bluetoothOffMessage => '请开启蓝牙以搜索设备'; String get scanner_bluetoothOffMessage => '请开启蓝牙以搜索设备';
@override
String get scanner_chromeRequired => '需要 Chrome 浏览器';
@override
String get scanner_chromeRequiredMessage =>
'此 Web 应用程序需要 Google Chrome 或基于 Chromium 的浏览器以支持蓝牙。';
@override @override
String get scanner_enableBluetooth => '启用蓝牙'; String get scanner_enableBluetooth => '启用蓝牙';
+2
View File
@@ -1605,6 +1605,8 @@
"map_runTrace": "Padeshulp traceren", "map_runTrace": "Padeshulp traceren",
"scanner_enableBluetooth": "Activeer Bluetooth", "scanner_enableBluetooth": "Activeer Bluetooth",
"scanner_bluetoothOffMessage": "Zorg ervoor dat Bluetooth is ingeschakeld om naar apparaten te zoeken.", "scanner_bluetoothOffMessage": "Zorg ervoor dat Bluetooth is ingeschakeld om naar apparaten te zoeken.",
"scanner_chromeRequired": "Chrome-browser vereist",
"scanner_chromeRequiredMessage": "Deze webapplicatie vereist Google Chrome of een op Chromium gebaseerde browser voor Bluetooth-ondersteuning.",
"scanner_bluetoothOff": "Bluetooth is uitgeschakeld", "scanner_bluetoothOff": "Bluetooth is uitgeschakeld",
"snrIndicator_lastSeen": "Laatst gezien", "snrIndicator_lastSeen": "Laatst gezien",
"snrIndicator_nearByRepeaters": "Nabije herhalingseenheden", "snrIndicator_nearByRepeaters": "Nabije herhalingseenheden",
+2
View File
@@ -1604,6 +1604,8 @@
"map_removeLast": "Usuń ostatni", "map_removeLast": "Usuń ostatni",
"map_tapToAdd": "Kliknij na węzły, aby dodać je do ścieżki.", "map_tapToAdd": "Kliknij na węzły, aby dodać je do ścieżki.",
"scanner_bluetoothOffMessage": "Prosimy włączyć Bluetooth, aby przeskanować urządzenia.", "scanner_bluetoothOffMessage": "Prosimy włączyć Bluetooth, aby przeskanować urządzenia.",
"scanner_chromeRequired": "Wymagana przeglądarka Chrome",
"scanner_chromeRequiredMessage": "Ta aplikacja internetowa wymaga przeglądarki Google Chrome lub opartej na Chromium do obsługi Bluetooth.",
"scanner_bluetoothOff": "Bluetooth jest wyłączony", "scanner_bluetoothOff": "Bluetooth jest wyłączony",
"scanner_enableBluetooth": "Włącz Bluetooth", "scanner_enableBluetooth": "Włącz Bluetooth",
"snrIndicator_lastSeen": "Ostatnio widziany", "snrIndicator_lastSeen": "Ostatnio widziany",
+2
View File
@@ -1606,6 +1606,8 @@
"scanner_enableBluetooth": "Ative o Bluetooth", "scanner_enableBluetooth": "Ative o Bluetooth",
"scanner_bluetoothOff": "Bluetooth está desativado", "scanner_bluetoothOff": "Bluetooth está desativado",
"scanner_bluetoothOffMessage": "Por favor, ative o Bluetooth para escanear por dispositivos.", "scanner_bluetoothOffMessage": "Por favor, ative o Bluetooth para escanear por dispositivos.",
"scanner_chromeRequired": "Navegador Chrome necessário",
"scanner_chromeRequiredMessage": "Esta aplicação web requer o Google Chrome ou um navegador baseado no Chromium para suporte de Bluetooth.",
"snrIndicator_nearByRepeaters": "Repetidores Próximos", "snrIndicator_nearByRepeaters": "Repetidores Próximos",
"snrIndicator_lastSeen": "Visto pela última vez", "snrIndicator_lastSeen": "Visto pela última vez",
"chat_ShowAllPaths": "Mostrar todos os caminhos", "chat_ShowAllPaths": "Mostrar todos os caminhos",
+2
View File
@@ -846,6 +846,8 @@
"scanner_enableBluetooth": "Включите Bluetooth", "scanner_enableBluetooth": "Включите Bluetooth",
"scanner_bluetoothOff": "Bluetooth выключен", "scanner_bluetoothOff": "Bluetooth выключен",
"scanner_bluetoothOffMessage": "Пожалуйста, включите Bluetooth, чтобы найти устройства.", "scanner_bluetoothOffMessage": "Пожалуйста, включите Bluetooth, чтобы найти устройства.",
"scanner_chromeRequired": "Требуется браузер Chrome",
"scanner_chromeRequiredMessage": "Для поддержки Bluetooth в этом веб-приложении требуется Google Chrome или браузер на базе Chromium.",
"snrIndicator_nearByRepeaters": "Ближайшие ретрансляторы", "snrIndicator_nearByRepeaters": "Ближайшие ретрансляторы",
"snrIndicator_lastSeen": "Последний раз видели", "snrIndicator_lastSeen": "Последний раз видели",
"chat_ShowAllPaths": "Показать все пути", "chat_ShowAllPaths": "Показать все пути",
+2
View File
@@ -1604,6 +1604,8 @@
"map_runTrace": "Spustiť trasovaním cesty", "map_runTrace": "Spustiť trasovaním cesty",
"map_pathTraceCancelled": "Zrušenie stopáže cesty bolo zrušené.", "map_pathTraceCancelled": "Zrušenie stopáže cesty bolo zrušené.",
"scanner_bluetoothOffMessage": "Prosím, zapnite Bluetooth, aby ste mohli skenovať pre zariadenia.", "scanner_bluetoothOffMessage": "Prosím, zapnite Bluetooth, aby ste mohli skenovať pre zariadenia.",
"scanner_chromeRequired": "Vyžaduje sa prehliadač Chrome",
"scanner_chromeRequiredMessage": "Táto webová aplikácia vyžaduje Google Chrome alebo prehliadač založený na Chromium pre podporu Bluetooth.",
"scanner_bluetoothOff": "Bluetooth je vypnutý", "scanner_bluetoothOff": "Bluetooth je vypnutý",
"scanner_enableBluetooth": "Povolte Bluetooth", "scanner_enableBluetooth": "Povolte Bluetooth",
"snrIndicator_lastSeen": "Naposledy videný", "snrIndicator_lastSeen": "Naposledy videný",
+2
View File
@@ -1605,6 +1605,8 @@
"map_pathTraceCancelled": "Spremljanje poti je prekinjeno.", "map_pathTraceCancelled": "Spremljanje poti je prekinjeno.",
"scanner_enableBluetooth": "Omogočite Bluetooth", "scanner_enableBluetooth": "Omogočite Bluetooth",
"scanner_bluetoothOffMessage": "Prosimo, vklopite Bluetooth, da lahko poiščete naprave.", "scanner_bluetoothOffMessage": "Prosimo, vklopite Bluetooth, da lahko poiščete naprave.",
"scanner_chromeRequired": "Zahtevan brskalnik Chrome",
"scanner_chromeRequiredMessage": "Ta spletna aplikacija za podporo Bluetooth zahteva Google Chrome ali brskalnik na osnovi Chromiuma.",
"scanner_bluetoothOff": "Bluetooth je izklopljen", "scanner_bluetoothOff": "Bluetooth je izklopljen",
"snrIndicator_lastSeen": "Zadnjič videno", "snrIndicator_lastSeen": "Zadnjič videno",
"snrIndicator_nearByRepeaters": "Bližnji ponovitelji", "snrIndicator_nearByRepeaters": "Bližnji ponovitelji",
+2
View File
@@ -1605,6 +1605,8 @@
"map_removeLast": "Ta bort sista", "map_removeLast": "Ta bort sista",
"scanner_enableBluetooth": "Aktivera Bluetooth", "scanner_enableBluetooth": "Aktivera Bluetooth",
"scanner_bluetoothOffMessage": "Vänligen aktivera Bluetooth för att söka efter enheter.", "scanner_bluetoothOffMessage": "Vänligen aktivera Bluetooth för att söka efter enheter.",
"scanner_chromeRequired": "Chrome-webbläsare krävs",
"scanner_chromeRequiredMessage": "Denna webbapplikation kräver Google Chrome oder en Chromium-baserader webbläsare för Bluetooth-stöd.",
"scanner_bluetoothOff": "Bluetooth är avstängt", "scanner_bluetoothOff": "Bluetooth är avstängt",
"snrIndicator_lastSeen": "Senast sedd", "snrIndicator_lastSeen": "Senast sedd",
"snrIndicator_nearByRepeaters": "Närliggande uppreparstationer", "snrIndicator_nearByRepeaters": "Närliggande uppreparstationer",
+2
View File
@@ -1605,6 +1605,8 @@
"map_pathTraceCancelled": "Відмінується трасування шляху", "map_pathTraceCancelled": "Відмінується трасування шляху",
"scanner_enableBluetooth": "Увімкніть Bluetooth", "scanner_enableBluetooth": "Увімкніть Bluetooth",
"scanner_bluetoothOffMessage": "Будь ласка, увімкніть Bluetooth, щоб сканувати пристрої.", "scanner_bluetoothOffMessage": "Будь ласка, увімкніть Bluetooth, щоб сканувати пристрої.",
"scanner_chromeRequired": "Потрібен браузер Chrome",
"scanner_chromeRequiredMessage": "Для підтримки Bluetooth у цьому веб-додатку потрібен Google Chrome або браузер на базі Chromium.",
"scanner_bluetoothOff": "Bluetooth вимкнено", "scanner_bluetoothOff": "Bluetooth вимкнено",
"snrIndicator_lastSeen": "Останній раз бачили", "snrIndicator_lastSeen": "Останній раз бачили",
"snrIndicator_nearByRepeaters": "Ближні ретранслятори", "snrIndicator_nearByRepeaters": "Ближні ретранслятори",
+2
View File
@@ -1609,6 +1609,8 @@
"map_removeLast": "移除最后一个", "map_removeLast": "移除最后一个",
"map_runTrace": "运行路径追踪", "map_runTrace": "运行路径追踪",
"scanner_bluetoothOffMessage": "请开启蓝牙以搜索设备", "scanner_bluetoothOffMessage": "请开启蓝牙以搜索设备",
"scanner_chromeRequired": "需要 Chrome 浏览器",
"scanner_chromeRequiredMessage": "此 Web 应用程序需要 Google Chrome 或基于 Chromium 的浏览器以支持蓝牙。",
"scanner_bluetoothOff": "蓝牙已关闭", "scanner_bluetoothOff": "蓝牙已关闭",
"scanner_enableBluetooth": "启用蓝牙", "scanner_enableBluetooth": "启用蓝牙",
"snrIndicator_lastSeen": "最近访问", "snrIndicator_lastSeen": "最近访问",
+6 -1
View File
@@ -4,6 +4,9 @@ import 'package:flutter/foundation.dart';
import 'l10n/app_localizations.dart'; import 'l10n/app_localizations.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'screens/chrome_required_screen.dart';
import 'utils/platform_info.dart';
import 'connector/meshcore_connector.dart'; import 'connector/meshcore_connector.dart';
import 'screens/scanner_screen.dart'; import 'screens/scanner_screen.dart';
import 'services/storage_service.dart'; import 'services/storage_service.dart';
@@ -187,7 +190,9 @@ class MeshCoreApp extends StatelessWidget {
NotificationService().setLocale(locale); NotificationService().setLocale(locale);
return child ?? const SizedBox.shrink(); return child ?? const SizedBox.shrink();
}, },
home: const ScannerScreen(), home: (PlatformInfo.isWeb && !PlatformInfo.isChrome)
? const ChromeRequiredScreen()
: const ScannerScreen(),
); );
}, },
), ),
+89
View File
@@ -0,0 +1,89 @@
import 'package:flutter/material.dart';
import '../l10n/l10n.dart';
class ChromeRequiredScreen extends StatelessWidget {
const ChromeRequiredScreen({super.key});
@override
Widget build(BuildContext context) {
final l10n = context.l10n;
final theme = Theme.of(context);
final isDark = theme.brightness == Brightness.dark;
return Scaffold(
body: Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 32),
decoration: BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: isDark
? [const Color(0xFF1A1A1A), const Color(0xFF0D0D0D)]
: [const Color(0xFFF5F7FA), const Color(0xFFE4E7EB)],
),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: Colors.orange.withValues(alpha: 0.1),
shape: BoxShape.circle,
),
child: const Icon(
Icons.browser_not_supported_rounded,
size: 80,
color: Colors.orange,
),
),
const SizedBox(height: 32),
Text(
l10n.scanner_chromeRequired,
textAlign: TextAlign.center,
style: theme.textTheme.headlineMedium?.copyWith(
fontWeight: FontWeight.bold,
color: isDark ? Colors.white : Colors.black87,
),
),
const SizedBox(height: 16),
Text(
l10n.scanner_chromeRequiredMessage,
textAlign: TextAlign.center,
style: theme.textTheme.bodyLarge?.copyWith(
color: isDark ? Colors.white70 : Colors.black54,
height: 1.5,
),
),
const SizedBox(height: 48),
// We can't really "fix" it for them other than telling them to use Chrome
// but we can provide a nice visual.
Container(
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 12),
decoration: BoxDecoration(
color: Colors.blue.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(30),
border: Border.all(color: Colors.blue.withValues(alpha: 0.3)),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.info_outline, size: 20, color: Colors.blue),
const SizedBox(width: 12),
Text(
"Web Bluetooth requires a Chromium browser",
style: theme.textTheme.bodyMedium?.copyWith(
color: Colors.blue,
fontWeight: FontWeight.w500,
),
),
],
),
),
],
),
),
);
}
}
+22 -14
View File
@@ -1,7 +1,6 @@
import 'dart:async'; import 'dart:async';
import 'dart:io' show Platform;
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import '../utils/platform_info.dart';
import 'package:flutter_blue_plus/flutter_blue_plus.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -46,17 +45,22 @@ class _ScannerScreenState extends State<ScannerScreen> {
connector.addListener(_connectionListener); connector.addListener(_connectionListener);
_bluetoothStateSubscription = FlutterBluePlus.adapterState.listen((state) { _bluetoothStateSubscription = FlutterBluePlus.adapterState.listen(
if (mounted) { (state) {
setState(() { if (mounted) {
_bluetoothState = state; setState(() {
}); _bluetoothState = state;
// Cancel scan if Bluetooth turns off while scanning });
if (state != BluetoothAdapterState.on) { // Cancel scan if Bluetooth turns off while scanning
unawaited(connector.stopScan()); if (state != BluetoothAdapterState.on) {
unawaited(connector.stopScan());
}
} }
} },
}); onError: (Object e) {
debugPrint("Scanner adapterState stream error: $e");
},
);
} }
@override @override
@@ -108,7 +112,11 @@ class _ScannerScreenState extends State<ScannerScreen> {
if (isScanning) { if (isScanning) {
connector.stopScan(); connector.stopScan();
} else { } else {
connector.startScan(); unawaited(
connector.startScan().catchError((e) {
debugPrint("Scanner screen startScan error: $e");
}),
);
} }
}, },
icon: isScanning icon: isScanning
@@ -265,7 +273,7 @@ class _ScannerScreenState extends State<ScannerScreen> {
], ],
), ),
), ),
if (Platform.isAndroid) if (PlatformInfo.isAndroid)
TextButton( TextButton(
onPressed: () => FlutterBluePlus.turnOn(), onPressed: () => FlutterBluePlus.turnOn(),
child: Text(context.l10n.scanner_enableBluetooth), child: Text(context.l10n.scanner_enableBluetooth),
+4 -5
View File
@@ -1,12 +1,11 @@
import 'dart:io'; import '../utils/platform_info.dart';
import 'package:flutter_foreground_task/flutter_foreground_task.dart'; import 'package:flutter_foreground_task/flutter_foreground_task.dart';
class BackgroundService { class BackgroundService {
bool _initialized = false; bool _initialized = false;
Future<void> initialize() async { Future<void> initialize() async {
if (!Platform.isAndroid || _initialized) return; if (!PlatformInfo.isAndroid || _initialized) return;
FlutterForegroundTask.init( FlutterForegroundTask.init(
androidNotificationOptions: AndroidNotificationOptions( androidNotificationOptions: AndroidNotificationOptions(
channelId: 'meshcore_background', channelId: 'meshcore_background',
@@ -29,7 +28,7 @@ class BackgroundService {
} }
Future<void> start() async { Future<void> start() async {
if (!Platform.isAndroid) return; if (!PlatformInfo.isAndroid) return;
if (!_initialized) { if (!_initialized) {
await initialize(); await initialize();
} }
@@ -43,7 +42,7 @@ class BackgroundService {
} }
Future<void> stop() async { Future<void> stop() async {
if (!Platform.isAndroid) return; if (!PlatformInfo.isAndroid) return;
final running = await FlutterForegroundTask.isRunningService; final running = await FlutterForegroundTask.isRunningService;
if (!running) return; if (!running) return;
await FlutterForegroundTask.stopService(); await FlutterForegroundTask.stopService();
+2
View File
@@ -0,0 +1,2 @@
export 'browser_detection_stub.dart'
if (dart.library.js_interop) 'browser_detection_web.dart';
+3
View File
@@ -0,0 +1,3 @@
class BrowserDetection {
static bool get isChrome => false;
}
+9
View File
@@ -0,0 +1,9 @@
import 'package:web/web.dart' as web;
class BrowserDetection {
static bool get isChrome {
final userAgent = web.window.navigator.userAgent.toLowerCase();
final isChrome = userAgent.contains('chrome');
return isChrome;
}
}
+5
View File
@@ -4,6 +4,7 @@ import 'package:meshcore_open/connector/meshcore_connector.dart';
import 'package:meshcore_open/connector/meshcore_protocol.dart'; import 'package:meshcore_open/connector/meshcore_protocol.dart';
import 'package:path_provider/path_provider.dart'; import 'package:path_provider/path_provider.dart';
import 'dart:io'; import 'dart:io';
import '../utils/platform_info.dart';
import 'package:share_plus/share_plus.dart'; import 'package:share_plus/share_plus.dart';
@@ -109,6 +110,10 @@ class GpxExport {
String shareText, String shareText,
String subject, String subject,
) async { ) async {
if (PlatformInfo.isWeb) {
debugPrint("GPX export is not supported on Web.");
return gpxExportNotAvailable;
}
if (_contacts.isEmpty) { if (_contacts.isEmpty) {
debugPrint("No repeaters to export nothing to share."); debugPrint("No repeaters to export nothing to share.");
return gpxExportNoContacts; return gpxExportNoContacts;
+36
View File
@@ -0,0 +1,36 @@
import 'package:flutter/foundation.dart';
import 'dart:io' show Platform;
import 'browser_detection.dart';
/// Utility class to safely check the current platform across web and native.
///
/// Using `Platform` from `dart:io` directly on Web causes a crash.
/// This class handles the `kIsWeb` check first to avoid those crashes.
class PlatformInfo {
/// Whether the app is running in a web browser.
static bool get isWeb => kIsWeb;
/// Whether the app is running in the Chrome browser (only relevant if [isWeb] is true).
static bool get isChrome => isWeb && BrowserDetection.isChrome;
/// Whether the app is running on Android.
static bool get isAndroid => !kIsWeb && Platform.isAndroid;
/// Whether the app is running on iOS.
static bool get isIOS => !kIsWeb && Platform.isIOS;
/// Whether the app is running on macOS.
static bool get isMacOS => !kIsWeb && Platform.isMacOS;
/// Whether the app is running on Windows.
static bool get isWindows => !kIsWeb && Platform.isWindows;
/// Whether the app is running on Linux.
static bool get isLinux => !kIsWeb && Platform.isLinux;
/// Whether the app is running on a mobile platform (Android or iOS).
static bool get isMobile => isAndroid || isIOS;
/// Whether the app is running on a desktop platform (macOS, Windows, or Linux).
static bool get isDesktop => isMacOS || isWindows || isLinux;
}
+2 -2
View File
@@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import '../utils/platform_info.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@@ -326,8 +327,7 @@ class _RepeaterLoginDialogState extends State<RepeaterLoginDialog> {
}, },
onSubmitted: (_) => _handleLogin(), onSubmitted: (_) => _handleLogin(),
autofocus: autofocus:
!(defaultTargetPlatform == TargetPlatform.android || !PlatformInfo.isMobile &&
defaultTargetPlatform == TargetPlatform.iOS) &&
_passwordController.text.isEmpty, _passwordController.text.isEmpty,
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
+2 -2
View File
@@ -1,4 +1,5 @@
import 'dart:async'; import 'dart:async';
import '../utils/platform_info.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
@@ -274,8 +275,7 @@ class _RoomLoginDialogState extends State<RoomLoginDialog> {
), ),
onSubmitted: (_) => _handleLogin(), onSubmitted: (_) => _handleLogin(),
autofocus: autofocus:
!(defaultTargetPlatform == TargetPlatform.android || !PlatformInfo.isMobile &&
defaultTargetPlatform == TargetPlatform.iOS) &&
_passwordController.text.isEmpty, _passwordController.text.isEmpty,
), ),
const SizedBox(height: 12), const SizedBox(height: 12),
+7
View File
@@ -0,0 +1,7 @@
{
"name": "meshcore-open",
"scripts": {
"build": "dart run build_pipe:build",
"deploy": "bun x wrangler deploy"
}
}
+14
View File
@@ -60,6 +60,7 @@ dependencies:
gpx: ^2.3.0 gpx: ^2.3.0
path_provider: ^2.1.5 path_provider: ^2.1.5
share_plus: ^12.0.1 share_plus: ^12.0.1
build_pipe: ^0.3.1
material_symbols_icons: ^4.2906.0 material_symbols_icons: ^4.2906.0
web: ^1.1.1 web: ^1.1.1
flutter_svg: ^2.0.10+1 flutter_svg: ^2.0.10+1
@@ -128,3 +129,16 @@ flutter_launcher_icons:
# #
# For details regarding fonts from package dependencies, # For details regarding fonts from package dependencies,
# see https://flutter.dev/to/font-from-package # see https://flutter.dev/to/font-from-package
build_pipe:
workflows:
default:
clean_flutter: true # Optional: Cleans old build artifacts before running
generate_log: true # Optional: Outputs a build log file for debugging
platforms:
web:
build:
build_command: flutter build web --release --pwa-strategy=none
# Strongly recommended: disables the default service worker which often causes more cache headaches
add_version_query_param: true
# This is the key flag! It appends ?v=<your pubspec version> to bootstrap/JS files
+7
View File
@@ -0,0 +1,7 @@
#:schema node_modules/wrangler/config-schema.json
name = "meshcore"
compatibility_date = "2025-10-08"
[assets]
directory = "build/web"