mirror of
https://github.com/zjs81/meshcore-open.git
synced 2026-06-15 07:04:26 +10:00
Compare commits
3 Commits
ui
...
dev-toolTranslate
| Author | SHA1 | Date | |
|---|---|---|---|
| d104edd65c | |||
| 094d5d2706 | |||
| 396f70c994 |
@@ -40,6 +40,7 @@ import '../storage/contact_discovery_store.dart';
|
|||||||
import '../storage/contact_settings_store.dart';
|
import '../storage/contact_settings_store.dart';
|
||||||
import '../storage/contact_store.dart';
|
import '../storage/contact_store.dart';
|
||||||
import '../storage/message_store.dart';
|
import '../storage/message_store.dart';
|
||||||
|
import '../storage/prefs_manager.dart';
|
||||||
import '../storage/unread_store.dart';
|
import '../storage/unread_store.dart';
|
||||||
import '../utils/app_logger.dart';
|
import '../utils/app_logger.dart';
|
||||||
import '../utils/battery_utils.dart';
|
import '../utils/battery_utils.dart';
|
||||||
@@ -124,6 +125,8 @@ class MeshCoreRadioStateSnapshot {
|
|||||||
class MeshCoreConnector extends ChangeNotifier {
|
class MeshCoreConnector extends ChangeNotifier {
|
||||||
// Message windowing to limit memory usage
|
// Message windowing to limit memory usage
|
||||||
static const int _messageWindowSize = 200;
|
static const int _messageWindowSize = 200;
|
||||||
|
static const String _lastCompanionPublicKeyPref =
|
||||||
|
'last_companion_public_key_hex';
|
||||||
|
|
||||||
MeshCoreConnectionState _state = MeshCoreConnectionState.disconnected;
|
MeshCoreConnectionState _state = MeshCoreConnectionState.disconnected;
|
||||||
BluetoothDevice? _device;
|
BluetoothDevice? _device;
|
||||||
@@ -476,6 +479,9 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
List<Message> getMessages(Contact contact) {
|
List<Message> getMessages(Contact contact) {
|
||||||
|
if (!_loadedConversationKeys.contains(contact.publicKeyHex)) {
|
||||||
|
unawaited(_loadMessagesForContact(contact.publicKeyHex));
|
||||||
|
}
|
||||||
return _conversations[contact.publicKeyHex] ?? [];
|
return _conversations[contact.publicKeyHex] ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -653,7 +659,14 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> loadCachedChannels() async {
|
Future<void> loadCachedChannels() async {
|
||||||
_cachedChannels = await _channelStore.loadChannels();
|
final loaded = await _channelStore.loadChannels();
|
||||||
|
_cachedChannels = loaded;
|
||||||
|
if (_channels.isEmpty && loaded.isNotEmpty) {
|
||||||
|
_channels
|
||||||
|
..clear()
|
||||||
|
..addAll(loaded);
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void setActiveContact(String? contactKeyHex) {
|
void setActiveContact(String? contactKeyHex) {
|
||||||
@@ -913,6 +926,69 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> loadAllCachedDataForCurrentCompanion() async {
|
||||||
|
await loadContactCache();
|
||||||
|
await _loadDiscoveredContactCache();
|
||||||
|
await loadChannelSettings();
|
||||||
|
await loadCachedChannels();
|
||||||
|
await loadAllChannelMessages();
|
||||||
|
await loadUnreadState();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> restoreLastCompanionScope() async {
|
||||||
|
final prefs = PrefsManager.instance;
|
||||||
|
final lastCompanionPublicKeyHex = prefs.getString(
|
||||||
|
_lastCompanionPublicKeyPref,
|
||||||
|
);
|
||||||
|
if (lastCompanionPublicKeyHex == null ||
|
||||||
|
lastCompanionPublicKeyHex.trim().isEmpty) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_setScopedStorePublicKey(lastCompanionPublicKeyHex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> loadDiscoveredContactCache() => _loadDiscoveredContactCache();
|
||||||
|
|
||||||
|
void _setScopedStorePublicKey(String publicKeyHex) {
|
||||||
|
_channelMessageStore.setPublicKeyHex = publicKeyHex;
|
||||||
|
_messageStore.setPublicKeyHex = publicKeyHex;
|
||||||
|
_channelOrderStore.setPublicKeyHex = publicKeyHex;
|
||||||
|
_channelSettingsStore.setPublicKeyHex = publicKeyHex;
|
||||||
|
_contactSettingsStore.setPublicKeyHex = publicKeyHex;
|
||||||
|
_contactStore.setPublicKeyHex = publicKeyHex;
|
||||||
|
_channelStore.setPublicKeyHex = publicKeyHex;
|
||||||
|
_unreadStore.setPublicKeyHex = publicKeyHex;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _clearCachedCompanionData() {
|
||||||
|
_contacts.clear();
|
||||||
|
_discoveredContacts.clear();
|
||||||
|
_conversations.clear();
|
||||||
|
_loadedConversationKeys.clear();
|
||||||
|
_channelMessages.clear();
|
||||||
|
_cachedChannels.clear();
|
||||||
|
_knownContactKeys.clear();
|
||||||
|
_contactUnreadCount.clear();
|
||||||
|
_unreadStateLoaded = false;
|
||||||
|
notifyListeners();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _persistLastCompanionScope() async {
|
||||||
|
final keyHex = selfPublicKeyHex;
|
||||||
|
if (keyHex.isEmpty) return;
|
||||||
|
final prefs = PrefsManager.instance;
|
||||||
|
await prefs.setString(_lastCompanionPublicKeyPref, keyHex);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> _reloadOfflineCachesForLastCompanion() async {
|
||||||
|
if (_state != MeshCoreConnectionState.disconnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await restoreLastCompanionScope();
|
||||||
|
await loadContactCache();
|
||||||
|
await _loadDiscoveredContactCache();
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _loadDiscoveredContactCache() async {
|
Future<void> _loadDiscoveredContactCache() async {
|
||||||
final cached = await _discoveryContactStore.loadContacts();
|
final cached = await _discoveryContactStore.loadContacts();
|
||||||
_discoveredContacts
|
_discoveredContacts
|
||||||
@@ -1450,6 +1526,7 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
_cancelReconnectTimer();
|
_cancelReconnectTimer();
|
||||||
_manualDisconnect = false;
|
_manualDisconnect = false;
|
||||||
_resetConnectionHandshakeState();
|
_resetConnectionHandshakeState();
|
||||||
|
_clearCachedCompanionData();
|
||||||
_activeTransport = MeshCoreTransportType.usb;
|
_activeTransport = MeshCoreTransportType.usb;
|
||||||
_setState(MeshCoreConnectionState.connecting);
|
_setState(MeshCoreConnectionState.connecting);
|
||||||
|
|
||||||
@@ -1531,6 +1608,7 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
_cancelReconnectTimer();
|
_cancelReconnectTimer();
|
||||||
_manualDisconnect = false;
|
_manualDisconnect = false;
|
||||||
_resetConnectionHandshakeState();
|
_resetConnectionHandshakeState();
|
||||||
|
_clearCachedCompanionData();
|
||||||
_activeTransport = MeshCoreTransportType.tcp;
|
_activeTransport = MeshCoreTransportType.tcp;
|
||||||
_setState(MeshCoreConnectionState.connecting);
|
_setState(MeshCoreConnectionState.connecting);
|
||||||
|
|
||||||
@@ -1665,6 +1743,7 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
_activeTransport = MeshCoreTransportType.bluetooth;
|
_activeTransport = MeshCoreTransportType.bluetooth;
|
||||||
|
|
||||||
await stopScan();
|
await stopScan();
|
||||||
|
_clearCachedCompanionData();
|
||||||
_setState(MeshCoreConnectionState.connecting);
|
_setState(MeshCoreConnectionState.connecting);
|
||||||
_device = device;
|
_device = device;
|
||||||
_deviceId = device.remoteId.toString();
|
_deviceId = device.remoteId.toString();
|
||||||
@@ -2416,6 +2495,7 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
'Disconnect complete transport=$transportLabel manual=$manual',
|
'Disconnect complete transport=$transportLabel manual=$manual',
|
||||||
tag: 'Connection',
|
tag: 'Connection',
|
||||||
);
|
);
|
||||||
|
unawaited(_reloadOfflineCachesForLastCompanion());
|
||||||
if (!manual && transportAtDisconnect == MeshCoreTransportType.bluetooth) {
|
if (!manual && transportAtDisconnect == MeshCoreTransportType.bluetooth) {
|
||||||
_scheduleReconnect();
|
_scheduleReconnect();
|
||||||
}
|
}
|
||||||
@@ -3796,26 +3876,12 @@ class MeshCoreConnector extends ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//set all the stores' public key so they can load the correct data
|
// Set scoped stores to this companion and remember it for next launch.
|
||||||
_channelMessageStore.setPublicKeyHex = selfPublicKeyHex;
|
_setScopedStorePublicKey(selfPublicKeyHex);
|
||||||
_messageStore.setPublicKeyHex = selfPublicKeyHex;
|
unawaited(_persistLastCompanionScope());
|
||||||
_channelOrderStore.setPublicKeyHex = selfPublicKeyHex;
|
|
||||||
_channelSettingsStore.setPublicKeyHex = selfPublicKeyHex;
|
|
||||||
_contactSettingsStore.setPublicKeyHex = selfPublicKeyHex;
|
|
||||||
_contactStore.setPublicKeyHex = selfPublicKeyHex;
|
|
||||||
_channelStore.setPublicKeyHex = selfPublicKeyHex;
|
|
||||||
_unreadStore.setPublicKeyHex = selfPublicKeyHex;
|
|
||||||
|
|
||||||
// Now that we have self info, we can load all the persisted data for this node
|
// Now that we have self info, we can load all the persisted data for this node.
|
||||||
_loadChannelOrder();
|
unawaited(loadAllCachedDataForCurrentCompanion());
|
||||||
loadContactCache();
|
|
||||||
loadChannelSettings();
|
|
||||||
loadCachedChannels();
|
|
||||||
|
|
||||||
// Load persisted channel messages
|
|
||||||
loadAllChannelMessages();
|
|
||||||
loadUnreadState();
|
|
||||||
_loadDiscoveredContactCache();
|
|
||||||
|
|
||||||
_awaitingSelfInfo = false;
|
_awaitingSelfInfo = false;
|
||||||
_selfInfoRetryTimer?.cancel();
|
_selfInfoRetryTimer?.cancel();
|
||||||
|
|||||||
+2
-1
@@ -2311,5 +2311,6 @@
|
|||||||
"settings_companionDebugLogSubtitle": "Команди, отговори и сурови данни за протоколите BLE/TCP/USB",
|
"settings_companionDebugLogSubtitle": "Команди, отговори и сурови данни за протоколите BLE/TCP/USB",
|
||||||
"chat_newMessages": "Нови съобщения",
|
"chat_newMessages": "Нови съобщения",
|
||||||
"settings_companionDebugLog": "Лог за отстраняване на грешки (за съпътстваща програма)",
|
"settings_companionDebugLog": "Лог за отстраняване на грешки (за съпътстваща програма)",
|
||||||
"repeater_chanUtil": "Използване на канала"
|
"repeater_chanUtil": "Използване на канала",
|
||||||
|
"contact_connectCompanion": "Свържете се с придружител, за да получите достъп до функциите на ретранслатора и сървъра за стаи."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2339,5 +2339,6 @@
|
|||||||
"chat_newMessages": "Neue Nachrichten",
|
"chat_newMessages": "Neue Nachrichten",
|
||||||
"settings_companionDebugLog": "Debug-Protokoll für die Begleitsoftware",
|
"settings_companionDebugLog": "Debug-Protokoll für die Begleitsoftware",
|
||||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB-Befehle, Antworten und Rohdaten",
|
"settings_companionDebugLogSubtitle": "BLE/TCP/USB-Befehle, Antworten und Rohdaten",
|
||||||
"repeater_chanUtil": "Nutzung des Kanals"
|
"repeater_chanUtil": "Nutzung des Kanals",
|
||||||
|
"contact_connectCompanion": "Verbinden Sie sich mit einem Companion, um auf die Funktionen des Repeaters und des Raumservers zuzugreifen."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2366,5 +2366,6 @@
|
|||||||
"contact_typeRepeater": "Repeater",
|
"contact_typeRepeater": "Repeater",
|
||||||
"contact_typeRoom": "Room",
|
"contact_typeRoom": "Room",
|
||||||
"contact_typeSensor": "Sensor",
|
"contact_typeSensor": "Sensor",
|
||||||
"contact_typeUnknown": "Unknown"
|
"contact_typeUnknown": "Unknown",
|
||||||
|
"contact_connectCompanion": "Connect to a companion to access repeater and room server features."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2339,5 +2339,6 @@
|
|||||||
"chat_newMessages": "Nuevos mensajes",
|
"chat_newMessages": "Nuevos mensajes",
|
||||||
"settings_companionDebugLogSubtitle": "Comandos, respuestas y datos brutos para protocolos BLE/TCP/USB",
|
"settings_companionDebugLogSubtitle": "Comandos, respuestas y datos brutos para protocolos BLE/TCP/USB",
|
||||||
"chat_markAsUnread": "Marcar como no leído",
|
"chat_markAsUnread": "Marcar como no leído",
|
||||||
"repeater_chanUtil": "Utilización del canal"
|
"repeater_chanUtil": "Utilización del canal",
|
||||||
|
"contact_connectCompanion": "Conéctate a un compañero para acceder a las funciones de repetidor y servidor de sala."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2318,5 +2318,6 @@
|
|||||||
"chat_markAsUnread": "Signaler comme non lu",
|
"chat_markAsUnread": "Signaler comme non lu",
|
||||||
"chat_newMessages": "Nouveaux messages",
|
"chat_newMessages": "Nouveaux messages",
|
||||||
"settings_companionDebugLogSubtitle": "Commandes, réponses et données brutes pour les protocoles BLE/TCP/USB",
|
"settings_companionDebugLogSubtitle": "Commandes, réponses et données brutes pour les protocoles BLE/TCP/USB",
|
||||||
"repeater_chanUtil": "Utilisation du canal"
|
"repeater_chanUtil": "Utilisation du canal",
|
||||||
|
"contact_connectCompanion": "Connectez-vous à un compagnon pour accéder aux fonctionnalités de répéteur et de serveur de salle."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2349,5 +2349,6 @@
|
|||||||
"chat_newMessages": "Új üzenetek",
|
"chat_newMessages": "Új üzenetek",
|
||||||
"settings_companionDebugLog": "Párhuzamos hibakeresési napló",
|
"settings_companionDebugLog": "Párhuzamos hibakeresési napló",
|
||||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB parancsok, válaszok és alapvető adatok",
|
"settings_companionDebugLogSubtitle": "BLE/TCP/USB parancsok, válaszok és alapvető adatok",
|
||||||
"repeater_chanUtil": "Csatorna-használat"
|
"repeater_chanUtil": "Csatorna-használat",
|
||||||
|
"contact_connectCompanion": "Csatlakozzon egy kísérőhöz a ismétlő és szobaszerver funkciók eléréséhez."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2311,5 +2311,6 @@
|
|||||||
"settings_companionDebugLog": "Registro di debug per il supporto",
|
"settings_companionDebugLog": "Registro di debug per il supporto",
|
||||||
"chat_newMessages": "Nuovi messaggi",
|
"chat_newMessages": "Nuovi messaggi",
|
||||||
"chat_markAsUnread": "Segna come non letto",
|
"chat_markAsUnread": "Segna come non letto",
|
||||||
"repeater_chanUtil": "Utilizzo del canale"
|
"repeater_chanUtil": "Utilizzo del canale",
|
||||||
|
"contact_connectCompanion": "Connettiti a un dispositivo companion per accedere alle funzionalità di ripetitore e server stanza."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2349,5 +2349,6 @@
|
|||||||
"settings_companionDebugLog": "同伴デバッグログ",
|
"settings_companionDebugLog": "同伴デバッグログ",
|
||||||
"chat_newMessages": "新しいメッセージ",
|
"chat_newMessages": "新しいメッセージ",
|
||||||
"chat_markAsUnread": "未読としてマークする",
|
"chat_markAsUnread": "未読としてマークする",
|
||||||
"repeater_chanUtil": "チャンネルの利用状況"
|
"repeater_chanUtil": "チャンネルの利用状況",
|
||||||
|
"contact_connectCompanion": "コネクトしてリピーターとルームサーバー機能にアクセス"
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2349,5 +2349,6 @@
|
|||||||
"chat_newMessages": "새로운 메시지",
|
"chat_newMessages": "새로운 메시지",
|
||||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB 명령어, 응답 및 원시 데이터",
|
"settings_companionDebugLogSubtitle": "BLE/TCP/USB 명령어, 응답 및 원시 데이터",
|
||||||
"chat_markAsUnread": "미리 읽지 않음으로 표시",
|
"chat_markAsUnread": "미리 읽지 않음으로 표시",
|
||||||
"repeater_chanUtil": "채널 활용도"
|
"repeater_chanUtil": "채널 활용도",
|
||||||
|
"contact_connectCompanion": "리피터 및 룸 서버 기능에 액세스하려면 컴패니언에 연결하세요."
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7335,6 +7335,12 @@ abstract class AppLocalizations {
|
|||||||
/// In en, this message translates to:
|
/// In en, this message translates to:
|
||||||
/// **'Unknown'**
|
/// **'Unknown'**
|
||||||
String get contact_typeUnknown;
|
String get contact_typeUnknown;
|
||||||
|
|
||||||
|
/// No description provided for @contact_connectCompanion.
|
||||||
|
///
|
||||||
|
/// In en, this message translates to:
|
||||||
|
/// **'Connect to a companion to access repeater and room server features.'**
|
||||||
|
String get contact_connectCompanion;
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AppLocalizationsDelegate
|
class _AppLocalizationsDelegate
|
||||||
|
|||||||
@@ -4288,4 +4288,8 @@ class AppLocalizationsBg extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Свържете се с придружител, за да получите достъп до функциите на ретранслатора и сървъра за стаи.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4305,4 +4305,8 @@ class AppLocalizationsDe extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Verbinden Sie sich mit einem Companion, um auf die Funktionen des Repeaters und des Raumservers zuzugreifen.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4210,4 +4210,8 @@ class AppLocalizationsEn extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Connect to a companion to access repeater and room server features.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4292,4 +4292,8 @@ class AppLocalizationsEs extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Conéctate a un compañero para acceder a las funciones de repetidor y servidor de sala.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4321,4 +4321,8 @@ class AppLocalizationsFr extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Connectez-vous à un compagnon pour accéder aux fonctionnalités de répéteur et de serveur de salle.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4309,4 +4309,8 @@ class AppLocalizationsHu extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Csatlakozzon egy kísérőhöz a ismétlő és szobaszerver funkciók eléréséhez.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4297,4 +4297,8 @@ class AppLocalizationsIt extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Connettiti a un dispositivo companion per accedere alle funzionalità di ripetitore e server stanza.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4063,4 +4063,7 @@ class AppLocalizationsJa extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion => 'コネクトしてリピーターとルームサーバー機能にアクセス';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4064,4 +4064,7 @@ class AppLocalizationsKo extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion => '리피터 및 룸 서버 기능에 액세스하려면 컴패니언에 연결하세요.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4273,4 +4273,8 @@ class AppLocalizationsNl extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Maak verbinding met een companion om repeater- en kamerserverfuncties te gebruiken.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4309,4 +4309,8 @@ class AppLocalizationsPl extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Połącz się z towarzyszem, aby uzyskać dostęp do funkcji powtarzacza i serwera pokoi.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4285,4 +4285,8 @@ class AppLocalizationsPt extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Conecte-se a um dispositivo companion para acessar as funcionalidades de repetidor e servidor de salas.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4303,4 +4303,8 @@ class AppLocalizationsRu extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Неизвестно';
|
String get contact_typeUnknown => 'Неизвестно';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Подключитесь к компаньону, чтобы получить доступ к функциям ретранслятора и сервера комнат.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4269,4 +4269,8 @@ class AppLocalizationsSk extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Pripojte sa k sprievodcovi a získajte prístup k funkciám opakovača a serveru miestností.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4267,4 +4267,8 @@ class AppLocalizationsSl extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Povežite se s spremljevalnikom za dostop do funkcij ponavljalnika in strežnika sob.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4241,4 +4241,8 @@ class AppLocalizationsSv extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Anslut till en sällskapstjänst för att komma åt upprepning och rumsserverfunktioner.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4304,4 +4304,8 @@ class AppLocalizationsUk extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Невідомо';
|
String get contact_typeUnknown => 'Невідомо';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion =>
|
||||||
|
'Підключіться до супутнього пристрою, щоб отримати доступ до функцій ретранслятора та сервера кімнат.';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3938,4 +3938,7 @@ class AppLocalizationsZh extends AppLocalizations {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
String get contact_typeUnknown => 'Unknown';
|
String get contact_typeUnknown => 'Unknown';
|
||||||
|
|
||||||
|
@override
|
||||||
|
String get contact_connectCompanion => '连接伴机以访问中继器和房间服务器功能。';
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2311,5 +2311,6 @@
|
|||||||
"chat_newMessages": "Nieuwe berichten",
|
"chat_newMessages": "Nieuwe berichten",
|
||||||
"chat_markAsUnread": "Markeer als ongelezen",
|
"chat_markAsUnread": "Markeer als ongelezen",
|
||||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB commando's, antwoorden en ruwe data",
|
"settings_companionDebugLogSubtitle": "BLE/TCP/USB commando's, antwoorden en ruwe data",
|
||||||
"repeater_chanUtil": "Gebruik van het kanaal"
|
"repeater_chanUtil": "Gebruik van het kanaal",
|
||||||
|
"contact_connectCompanion": "Maak verbinding met een companion om repeater- en kamerserverfuncties te gebruiken."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2349,5 +2349,6 @@
|
|||||||
"settings_companionDebugLogSubtitle": "Polecenia, odpowiedzi i surowe dane związane z protokołami BLE/TCP/USB",
|
"settings_companionDebugLogSubtitle": "Polecenia, odpowiedzi i surowe dane związane z protokołami BLE/TCP/USB",
|
||||||
"chat_markAsUnread": "Oznacz jako nieprzeczytane",
|
"chat_markAsUnread": "Oznacz jako nieprzeczytane",
|
||||||
"settings_companionDebugLog": "Log debugowania (dla pomocy w rozwiązywaniu problemów)",
|
"settings_companionDebugLog": "Log debugowania (dla pomocy w rozwiązywaniu problemów)",
|
||||||
"repeater_chanUtil": "Wykorzystanie kanału"
|
"repeater_chanUtil": "Wykorzystanie kanału",
|
||||||
|
"contact_connectCompanion": "Połącz się z towarzyszem, aby uzyskać dostęp do funkcji powtarzacza i serwera pokoi."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2311,5 +2311,6 @@
|
|||||||
"settings_companionDebugLogSubtitle": "Comandos, respostas e dados brutos para protocolos BLE/TCP/USB",
|
"settings_companionDebugLogSubtitle": "Comandos, respostas e dados brutos para protocolos BLE/TCP/USB",
|
||||||
"chat_markAsUnread": "Marcar como não lido",
|
"chat_markAsUnread": "Marcar como não lido",
|
||||||
"chat_newMessages": "Novas mensagens",
|
"chat_newMessages": "Novas mensagens",
|
||||||
"repeater_chanUtil": "Utilização do canal"
|
"repeater_chanUtil": "Utilização do canal",
|
||||||
|
"contact_connectCompanion": "Conecte-se a um dispositivo companion para acessar as funcionalidades de repetidor e servidor de salas."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -1614,5 +1614,6 @@
|
|||||||
"repeater_cliHelpStatsCore": "(Только для серийного оборудования) Отображает основные статистические данные прошивки.",
|
"repeater_cliHelpStatsCore": "(Только для серийного оборудования) Отображает основные статистические данные прошивки.",
|
||||||
"settings_companionDebugLogSubtitle": "Команды, ответы и необработанные данные, используемые для протоколов BLE, TCP и USB.",
|
"settings_companionDebugLogSubtitle": "Команды, ответы и необработанные данные, используемые для протоколов BLE, TCP и USB.",
|
||||||
"repeater_chanUtil": "Использование канала",
|
"repeater_chanUtil": "Использование канала",
|
||||||
"settings_companionDebugLog": "Журнал отладки (для сопутствующего приложения)"
|
"settings_companionDebugLog": "Журнал отладки (для сопутствующего приложения)",
|
||||||
|
"contact_connectCompanion": "Подключитесь к компаньону, чтобы получить доступ к функциям ретранслятора и сервера комнат."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2311,5 +2311,6 @@
|
|||||||
"settings_companionDebugLogSubtitle": "Príkazy, odpovede a surové dáta pre protokoly BLE/TCP/USB",
|
"settings_companionDebugLogSubtitle": "Príkazy, odpovede a surové dáta pre protokoly BLE/TCP/USB",
|
||||||
"settings_companionDebugLog": "Logovanie pre ladenie (sprievodný log)",
|
"settings_companionDebugLog": "Logovanie pre ladenie (sprievodný log)",
|
||||||
"chat_newMessages": "Nové správy",
|
"chat_newMessages": "Nové správy",
|
||||||
"repeater_chanUtil": "Využitie kanálu"
|
"repeater_chanUtil": "Využitie kanálu",
|
||||||
|
"contact_connectCompanion": "Pripojte sa k sprievodcovi a získajte prístup k funkciám opakovača a serveru miestností."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2311,5 +2311,6 @@
|
|||||||
"chat_markAsUnread": "Označiti kot neneobdelano",
|
"chat_markAsUnread": "Označiti kot neneobdelano",
|
||||||
"chat_newMessages": "Nove novice",
|
"chat_newMessages": "Nove novice",
|
||||||
"settings_companionDebugLogSubtitle": "Navodila, odgovori in surova podatka za BLE/TCP/USB.",
|
"settings_companionDebugLogSubtitle": "Navodila, odgovori in surova podatka za BLE/TCP/USB.",
|
||||||
"repeater_chanUtil": "Uporaba kanala"
|
"repeater_chanUtil": "Uporaba kanala",
|
||||||
|
"contact_connectCompanion": "Povežite se s spremljevalnikom za dostop do funkcij ponavljalnika in strežnika sob."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2311,5 +2311,6 @@
|
|||||||
"settings_companionDebugLog": "Följande felsökningslogg",
|
"settings_companionDebugLog": "Följande felsökningslogg",
|
||||||
"chat_newMessages": "Nya meddelanden",
|
"chat_newMessages": "Nya meddelanden",
|
||||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB-kommandon, svar och rådata",
|
"settings_companionDebugLogSubtitle": "BLE/TCP/USB-kommandon, svar och rådata",
|
||||||
"repeater_chanUtil": "Användning av kanal"
|
"repeater_chanUtil": "Användning av kanal",
|
||||||
|
"contact_connectCompanion": "Anslut till en sällskapstjänst för att komma åt upprepning och rumsserverfunktioner."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2291,5 +2291,6 @@
|
|||||||
"settings_companionDebugLogSubtitle": "Команди, відповіді та необроблена інформація для протоколів BLE/TCP/USB",
|
"settings_companionDebugLogSubtitle": "Команди, відповіді та необроблена інформація для протоколів BLE/TCP/USB",
|
||||||
"chat_newMessages": "Нові повідомлення",
|
"chat_newMessages": "Нові повідомлення",
|
||||||
"chat_markAsUnread": "Позначити як непрочитане",
|
"chat_markAsUnread": "Позначити як непрочитане",
|
||||||
"repeater_chanUtil": "Використання каналу"
|
"repeater_chanUtil": "Використання каналу",
|
||||||
|
"contact_connectCompanion": "Підключіться до супутнього пристрою, щоб отримати доступ до функцій ретранслятора та сервера кімнат."
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-1
@@ -2316,5 +2316,6 @@
|
|||||||
"settings_companionDebugLog": "调试日志",
|
"settings_companionDebugLog": "调试日志",
|
||||||
"chat_newMessages": "新的消息",
|
"chat_newMessages": "新的消息",
|
||||||
"settings_companionDebugLogSubtitle": "BLE/TCP/USB 协议、响应和原始数据",
|
"settings_companionDebugLogSubtitle": "BLE/TCP/USB 协议、响应和原始数据",
|
||||||
"repeater_chanUtil": "频道利用率"
|
"repeater_chanUtil": "频道利用率",
|
||||||
|
"contact_connectCompanion": "连接伴机以访问中继器和房间服务器功能。"
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-9
@@ -5,10 +5,10 @@ import 'l10n/app_localizations.dart';
|
|||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import 'screens/chrome_required_screen.dart';
|
import 'screens/chrome_required_screen.dart';
|
||||||
|
import 'screens/contacts_screen.dart';
|
||||||
import 'utils/platform_info.dart';
|
import 'utils/platform_info.dart';
|
||||||
|
|
||||||
import 'connector/meshcore_connector.dart';
|
import 'connector/meshcore_connector.dart';
|
||||||
import 'screens/scanner_screen.dart';
|
|
||||||
import 'services/storage_service.dart';
|
import 'services/storage_service.dart';
|
||||||
import 'services/message_retry_service.dart';
|
import 'services/message_retry_service.dart';
|
||||||
import 'services/path_history_service.dart';
|
import 'services/path_history_service.dart';
|
||||||
@@ -81,13 +81,8 @@ void main() async {
|
|||||||
timeoutPredictionService: timeoutPredictionService,
|
timeoutPredictionService: timeoutPredictionService,
|
||||||
);
|
);
|
||||||
|
|
||||||
await connector.loadContactCache();
|
await connector.restoreLastCompanionScope();
|
||||||
await connector.loadChannelSettings();
|
await connector.loadAllCachedDataForCurrentCompanion();
|
||||||
await connector.loadCachedChannels();
|
|
||||||
|
|
||||||
// Load persisted channel messages
|
|
||||||
await connector.loadAllChannelMessages();
|
|
||||||
await connector.loadUnreadState();
|
|
||||||
|
|
||||||
runApp(
|
runApp(
|
||||||
MeshCoreApp(
|
MeshCoreApp(
|
||||||
@@ -218,7 +213,7 @@ class MeshCoreApp extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
home: (PlatformInfo.isWeb && !PlatformInfo.isChrome)
|
home: (PlatformInfo.isWeb && !PlatformInfo.isChrome)
|
||||||
? const ChromeRequiredScreen()
|
? const ChromeRequiredScreen()
|
||||||
: const ScannerScreen(),
|
: const ContactsScreen(),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ class PathRecord {
|
|||||||
final int tripTimeMs;
|
final int tripTimeMs;
|
||||||
final DateTime? timestamp;
|
final DateTime? timestamp;
|
||||||
final bool wasFloodDiscovery;
|
final bool wasFloodDiscovery;
|
||||||
|
final int byteCount;
|
||||||
final List<int> pathBytes;
|
final List<int> pathBytes;
|
||||||
final int successCount;
|
final int successCount;
|
||||||
final int failureCount;
|
final int failureCount;
|
||||||
@@ -17,6 +18,7 @@ class PathRecord {
|
|||||||
required this.successCount,
|
required this.successCount,
|
||||||
required this.failureCount,
|
required this.failureCount,
|
||||||
this.routeWeight = 1.0,
|
this.routeWeight = 1.0,
|
||||||
|
this.byteCount = 0,
|
||||||
});
|
});
|
||||||
|
|
||||||
String get displayText =>
|
String get displayText =>
|
||||||
|
|||||||
@@ -1057,6 +1057,9 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
|
|
||||||
Widget _buildMessageComposer() {
|
Widget _buildMessageComposer() {
|
||||||
final connector = context.watch<MeshCoreConnector>();
|
final connector = context.watch<MeshCoreConnector>();
|
||||||
|
if (!connector.isConnected) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
final maxBytes = maxChannelMessageBytes(connector.selfName);
|
final maxBytes = maxChannelMessageBytes(connector.selfName);
|
||||||
final settings = context.watch<AppSettingsService>().settings;
|
final settings = context.watch<AppSettingsService>().settings;
|
||||||
return Column(
|
return Column(
|
||||||
@@ -1208,6 +1211,9 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _sendMessage() async {
|
Future<void> _sendMessage() async {
|
||||||
|
final connector = context.read<MeshCoreConnector>();
|
||||||
|
if (!connector.isConnected) return;
|
||||||
|
|
||||||
final text = _textController.text.trim();
|
final text = _textController.text.trim();
|
||||||
if (text.isEmpty) return;
|
if (text.isEmpty) return;
|
||||||
|
|
||||||
@@ -1222,7 +1228,6 @@ class _ChannelChatScreenState extends State<ChannelChatScreen> {
|
|||||||
}
|
}
|
||||||
_lastChannelSendAt = now;
|
_lastChannelSendAt = now;
|
||||||
|
|
||||||
final connector = context.read<MeshCoreConnector>();
|
|
||||||
final settings = context.read<AppSettingsService>().settings;
|
final settings = context.read<AppSettingsService>().settings;
|
||||||
final translationService = context.read<TranslationService>();
|
final translationService = context.read<TranslationService>();
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import '../models/channel.dart';
|
|||||||
import '../models/community.dart';
|
import '../models/community.dart';
|
||||||
import '../storage/community_store.dart';
|
import '../storage/community_store.dart';
|
||||||
import '../utils/dialog_utils.dart';
|
import '../utils/dialog_utils.dart';
|
||||||
import '../utils/disconnect_navigation_mixin.dart';
|
|
||||||
import '../utils/route_transitions.dart';
|
import '../utils/route_transitions.dart';
|
||||||
import '../widgets/list_filter_widget.dart';
|
import '../widgets/list_filter_widget.dart';
|
||||||
import '../widgets/empty_state.dart';
|
import '../widgets/empty_state.dart';
|
||||||
@@ -29,6 +28,7 @@ import 'channel_chat_screen.dart';
|
|||||||
import 'community_qr_scanner_screen.dart';
|
import 'community_qr_scanner_screen.dart';
|
||||||
import 'contacts_screen.dart';
|
import 'contacts_screen.dart';
|
||||||
import 'map_screen.dart';
|
import 'map_screen.dart';
|
||||||
|
import 'scanner_screen.dart';
|
||||||
import 'settings_screen.dart';
|
import 'settings_screen.dart';
|
||||||
|
|
||||||
class ChannelsScreen extends StatefulWidget {
|
class ChannelsScreen extends StatefulWidget {
|
||||||
@@ -41,7 +41,7 @@ class ChannelsScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ChannelsScreenState extends State<ChannelsScreen>
|
class _ChannelsScreenState extends State<ChannelsScreen>
|
||||||
with DisconnectNavigationMixin {
|
{
|
||||||
final TextEditingController _searchController = TextEditingController();
|
final TextEditingController _searchController = TextEditingController();
|
||||||
final CommunityStore _communityStore = CommunityStore();
|
final CommunityStore _communityStore = CommunityStore();
|
||||||
Timer? _searchDebounce;
|
Timer? _searchDebounce;
|
||||||
@@ -117,11 +117,6 @@ class _ChannelsScreenState extends State<ChannelsScreen>
|
|||||||
final channelMessageStore = ChannelMessageStore();
|
final channelMessageStore = ChannelMessageStore();
|
||||||
channelMessageStore.setPublicKeyHex = connector.selfPublicKeyHex;
|
channelMessageStore.setPublicKeyHex = connector.selfPublicKeyHex;
|
||||||
|
|
||||||
// Auto-navigate back to scanner if disconnected
|
|
||||||
if (!checkConnectionAndNavigate(connector)) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
|
|
||||||
final allowBack = !connector.isConnected;
|
final allowBack = !connector.isConnected;
|
||||||
|
|
||||||
return PopScope(
|
return PopScope(
|
||||||
@@ -134,16 +129,33 @@ class _ChannelsScreenState extends State<ChannelsScreen>
|
|||||||
actions: [
|
actions: [
|
||||||
PopupMenuButton(
|
PopupMenuButton(
|
||||||
itemBuilder: (context) => [
|
itemBuilder: (context) => [
|
||||||
PopupMenuItem(
|
if (connector.isConnected)
|
||||||
child: Row(
|
PopupMenuItem(
|
||||||
children: [
|
child: Row(
|
||||||
const Icon(Icons.logout, color: Colors.red),
|
children: [
|
||||||
const SizedBox(width: 8),
|
const Icon(Icons.logout, color: Colors.red),
|
||||||
Text(context.l10n.common_disconnect),
|
const SizedBox(width: 8),
|
||||||
],
|
Text(context.l10n.common_disconnect),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () => _disconnect(context),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
PopupMenuItem(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.bluetooth_searching),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(context.l10n.common_connect),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () => Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const ScannerScreen(),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onTap: () => _disconnect(context),
|
|
||||||
),
|
|
||||||
if (_communities.isNotEmpty)
|
if (_communities.isNotEmpty)
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
child: Row(
|
child: Row(
|
||||||
|
|||||||
@@ -414,7 +414,7 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
_buildInputBar(connector),
|
if (connector.isConnected) _buildInputBar(connector),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@@ -693,6 +693,9 @@ class _ChatScreenState extends State<ChatScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _sendMessage(MeshCoreConnector connector) async {
|
Future<void> _sendMessage(MeshCoreConnector connector) async {
|
||||||
|
if (!connector.isConnected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
final text = _textController.text.trim();
|
final text = _textController.text.trim();
|
||||||
if (text.isEmpty) return;
|
if (text.isEmpty) return;
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ import '../services/ui_view_state_service.dart';
|
|||||||
import '../utils/contact_search.dart';
|
import '../utils/contact_search.dart';
|
||||||
import '../storage/contact_group_store.dart';
|
import '../storage/contact_group_store.dart';
|
||||||
import '../utils/dialog_utils.dart';
|
import '../utils/dialog_utils.dart';
|
||||||
import '../utils/disconnect_navigation_mixin.dart';
|
|
||||||
import '../utils/emoji_utils.dart';
|
import '../utils/emoji_utils.dart';
|
||||||
import '../utils/route_transitions.dart';
|
import '../utils/route_transitions.dart';
|
||||||
import '../widgets/list_filter_widget.dart';
|
import '../widgets/list_filter_widget.dart';
|
||||||
@@ -34,6 +33,7 @@ import 'chat_screen.dart';
|
|||||||
import 'discovery_screen.dart';
|
import 'discovery_screen.dart';
|
||||||
import 'map_screen.dart';
|
import 'map_screen.dart';
|
||||||
import 'repeater_hub_screen.dart';
|
import 'repeater_hub_screen.dart';
|
||||||
|
import 'scanner_screen.dart';
|
||||||
import 'settings_screen.dart';
|
import 'settings_screen.dart';
|
||||||
|
|
||||||
enum RoomLoginDestination { chat, management }
|
enum RoomLoginDestination { chat, management }
|
||||||
@@ -50,7 +50,7 @@ class ContactsScreen extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ContactsScreenState extends State<ContactsScreen>
|
class _ContactsScreenState extends State<ContactsScreen>
|
||||||
with DisconnectNavigationMixin {
|
{
|
||||||
final TextEditingController _searchController = TextEditingController();
|
final TextEditingController _searchController = TextEditingController();
|
||||||
final ContactGroupStore _groupStore = ContactGroupStore();
|
final ContactGroupStore _groupStore = ContactGroupStore();
|
||||||
MeshCoreConnector? _scopeSyncConnector;
|
MeshCoreConnector? _scopeSyncConnector;
|
||||||
@@ -306,11 +306,6 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final connector = context.watch<MeshCoreConnector>();
|
final connector = context.watch<MeshCoreConnector>();
|
||||||
|
|
||||||
// Auto-navigate back to scanner if disconnected
|
|
||||||
if (!checkConnectionAndNavigate(connector)) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
|
|
||||||
final allowBack = !connector.isConnected;
|
final allowBack = !connector.isConnected;
|
||||||
return PopScope(
|
return PopScope(
|
||||||
canPop: allowBack,
|
canPop: allowBack,
|
||||||
@@ -378,16 +373,33 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
),
|
),
|
||||||
PopupMenuButton(
|
PopupMenuButton(
|
||||||
itemBuilder: (context) => [
|
itemBuilder: (context) => [
|
||||||
PopupMenuItem(
|
if (connector.isConnected)
|
||||||
child: Row(
|
PopupMenuItem(
|
||||||
children: [
|
child: Row(
|
||||||
const Icon(Icons.logout, color: Colors.red),
|
children: [
|
||||||
const SizedBox(width: 8),
|
const Icon(Icons.logout, color: Colors.red),
|
||||||
Text(context.l10n.common_disconnect),
|
const SizedBox(width: 8),
|
||||||
],
|
Text(context.l10n.common_disconnect),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () => _disconnect(context, connector),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
PopupMenuItem(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.bluetooth_searching),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(context.l10n.common_connect),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () => Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const ScannerScreen(),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onTap: () => _disconnect(context, connector),
|
|
||||||
),
|
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
@@ -965,6 +977,11 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _showRepeaterLogin(BuildContext context, Contact repeater) {
|
void _showRepeaterLogin(BuildContext context, Contact repeater) {
|
||||||
|
final connector = context.read<MeshCoreConnector>();
|
||||||
|
if (!connector.isConnected) {
|
||||||
|
_showCompanionRequiredDialog(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => RepeaterLoginDialog(
|
builder: (context) => RepeaterLoginDialog(
|
||||||
@@ -991,6 +1008,11 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
Contact room,
|
Contact room,
|
||||||
RoomLoginDestination destination,
|
RoomLoginDestination destination,
|
||||||
) {
|
) {
|
||||||
|
final connector = context.read<MeshCoreConnector>();
|
||||||
|
if (!connector.isConnected) {
|
||||||
|
_showCompanionRequiredDialog(context);
|
||||||
|
return;
|
||||||
|
}
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) => RoomLoginDialog(
|
builder: (context) => RoomLoginDialog(
|
||||||
@@ -1019,6 +1041,22 @@ class _ContactsScreenState extends State<ContactsScreen>
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _showCompanionRequiredDialog(BuildContext context) {
|
||||||
|
showDialog<void>(
|
||||||
|
context: context,
|
||||||
|
builder: (dialogContext) => AlertDialog(
|
||||||
|
title: Text(context.l10n.scanner_notConnected),
|
||||||
|
content: Text(context.l10n.contact_connectCompanion),
|
||||||
|
actions: [
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => Navigator.pop(dialogContext),
|
||||||
|
child: Text(context.l10n.common_ok),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void _confirmDeleteGroup(BuildContext context, ContactGroup group) {
|
void _confirmDeleteGroup(BuildContext context, ContactGroup group) {
|
||||||
if (!_hasGroupStoreScope(context.read<MeshCoreConnector>())) {
|
if (!_hasGroupStoreScope(context.read<MeshCoreConnector>())) {
|
||||||
_showGroupsUnavailableMessage(context);
|
_showGroupsUnavailableMessage(context);
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import '../widgets/repeater_login_dialog.dart';
|
|||||||
import '../widgets/room_login_dialog.dart';
|
import '../widgets/room_login_dialog.dart';
|
||||||
import '../helpers/snack_bar_builder.dart';
|
import '../helpers/snack_bar_builder.dart';
|
||||||
import 'repeater_hub_screen.dart';
|
import 'repeater_hub_screen.dart';
|
||||||
|
import 'scanner_screen.dart';
|
||||||
import 'settings_screen.dart';
|
import 'settings_screen.dart';
|
||||||
import 'line_of_sight_map_screen.dart';
|
import 'line_of_sight_map_screen.dart';
|
||||||
|
|
||||||
@@ -466,16 +467,33 @@ class _MapScreenState extends State<MapScreen> {
|
|||||||
),
|
),
|
||||||
PopupMenuButton(
|
PopupMenuButton(
|
||||||
itemBuilder: (context) => [
|
itemBuilder: (context) => [
|
||||||
PopupMenuItem(
|
if (connector.isConnected)
|
||||||
child: Row(
|
PopupMenuItem(
|
||||||
children: [
|
child: Row(
|
||||||
const Icon(Icons.logout, color: Colors.red),
|
children: [
|
||||||
const SizedBox(width: 8),
|
const Icon(Icons.logout, color: Colors.red),
|
||||||
Text(context.l10n.common_disconnect),
|
const SizedBox(width: 8),
|
||||||
],
|
Text(context.l10n.common_disconnect),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () => _disconnect(context, connector),
|
||||||
|
)
|
||||||
|
else
|
||||||
|
PopupMenuItem(
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
const Icon(Icons.bluetooth_searching),
|
||||||
|
const SizedBox(width: 8),
|
||||||
|
Text(context.l10n.common_connect),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
onTap: () => Navigator.push(
|
||||||
|
context,
|
||||||
|
MaterialPageRoute(
|
||||||
|
builder: (context) => const ScannerScreen(),
|
||||||
|
),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
onTap: () => _disconnect(context, connector),
|
|
||||||
),
|
|
||||||
PopupMenuItem(
|
PopupMenuItem(
|
||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
import '../connector/meshcore_connector.dart';
|
|
||||||
|
|
||||||
/// Mixin that automatically navigates back to scanner when disconnected.
|
|
||||||
/// Use in State classes for screens that require active connection.
|
|
||||||
mixin DisconnectNavigationMixin<T extends StatefulWidget> on State<T> {
|
|
||||||
/// Call this in your Widget build method to enable auto-navigation.
|
|
||||||
/// Returns true if still connected, false if navigation was triggered.
|
|
||||||
bool checkConnectionAndNavigate(MeshCoreConnector connector) {
|
|
||||||
if (!connector.isConnected) {
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
|
||||||
if (mounted) {
|
|
||||||
Navigator.popUntil(context, (route) => route.isFirst);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+928
-420
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user