diff --git a/lib/connector/meshcore_connector.dart b/lib/connector/meshcore_connector.dart index c57a85a..8f42d2e 100644 --- a/lib/connector/meshcore_connector.dart +++ b/lib/connector/meshcore_connector.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'dart:convert'; import 'package:crypto/crypto.dart' as crypto; +import 'package:meshcore_open/models/discovery_contact.dart'; import 'package:pointycastle/export.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_blue_plus/flutter_blue_plus.dart'; @@ -24,6 +25,7 @@ import '../storage/channel_message_store.dart'; import '../storage/channel_order_store.dart'; import '../storage/channel_settings_store.dart'; import '../storage/channel_store.dart'; +import '../storage/contact_discovery_store.dart'; import '../storage/contact_settings_store.dart'; import '../storage/contact_store.dart'; import '../storage/message_store.dart'; @@ -111,6 +113,7 @@ class MeshCoreConnector extends ChangeNotifier { final List _scanResults = []; final List _contacts = []; + final List _discoveredContacts = []; final List _channels = []; final Map> _conversations = {}; final Map> _channelMessages = {}; @@ -155,6 +158,18 @@ class MeshCoreConnector extends ChangeNotifier { bool _batteryRequested = false; bool _awaitingSelfInfo = false; bool _preserveContactsOnRefresh = false; + bool _autoAddUsers = false; + bool _autoAddRepeaters = false; + bool _autoAddRoomServers = false; + bool _autoAddSensors = false; + bool _overwriteOldest = false; + bool _manualAddContacts = false; + int _telemetryModeBase = 0; + int _telemetryModeLoc = 0; + int _telemetryModeEnv = 0; + int _advertLocPolicy = 0; + int _multiAcks = 0; + static const int _defaultMaxContacts = 32; static const int _defaultMaxChannels = 8; int _maxContacts = _defaultMaxContacts; @@ -195,6 +210,7 @@ class MeshCoreConnector extends ChangeNotifier { final ChannelSettingsStore _channelSettingsStore = ChannelSettingsStore(); final ContactSettingsStore _contactSettingsStore = ContactSettingsStore(); final ContactStore _contactStore = ContactStore(); + final ContactDiscoveryStore _discoveryContactStore = ContactDiscoveryStore(); final ChannelStore _channelStore = ChannelStore(); final UnreadStore _unreadStore = UnreadStore(); List _cachedChannels = []; @@ -242,6 +258,10 @@ class MeshCoreConnector extends ChangeNotifier { ); } + List get discoveredContacts { + return List.unmodifiable(_discoveredContacts); + } + List get channels => List.unmodifiable(_channels); bool get isConnected => _state == MeshCoreConnectionState.connected; bool get isLoadingContacts => _isLoadingContacts; @@ -258,12 +278,18 @@ class MeshCoreConnector extends ChangeNotifier { int? get currentBwHz => _currentBwHz; int? get currentSf => _currentSf; int? get currentCr => _currentCr; + bool? get autoAddUsers => _autoAddUsers; + bool? get autoAddRepeaters => _autoAddRepeaters; + bool? get autoAddRoomServers => _autoAddRoomServers; + bool? get autoAddSensors => _autoAddSensors; + bool? get autoAddOverwriteOldest => _overwriteOldest; bool? get clientRepeat => _clientRepeat; int? get firmwareVerCode => _firmwareVerCode; Map? get currentCustomVars => _currentCustomVars; int? get batteryMillivolts => _batteryMillivolts; int get maxContacts => _maxContacts; int get maxChannels => _maxChannels; + Set get knownContactKeys => Set.unmodifiable(_knownContactKeys); bool get isSyncingQueuedMessages => _isSyncingQueuedMessages; bool get isSyncingChannels => _isSyncingChannels; int get channelSyncProgress => @@ -602,6 +628,13 @@ class MeshCoreConnector extends ChangeNotifier { } } + Future loadDiscoveredContactCache() async { + final cached = await _discoveryContactStore.loadContacts(); + _discoveredContacts + ..clear() + ..addAll(cached); + } + Future loadChannelSettings({int? maxChannels}) async { _channelSmazEnabled.clear(); final channelCount = maxChannels ?? _maxChannels; @@ -848,6 +881,9 @@ class MeshCoreConnector extends ChangeNotifier { // Fetch channels so we can track unread counts for incoming messages unawaited(getChannels()); + + // Load discovered contacts from storage + unawaited(loadDiscoveredContactCache()); } catch (e) { debugPrint("Connection error: $e"); await disconnect(manual: false); @@ -968,6 +1004,7 @@ class MeshCoreConnector extends ChangeNotifier { _deviceDisplayName = null; _deviceId = null; _contacts.clear(); + _discoveredContacts.clear(); _conversations.clear(); _loadedConversationKeys.clear(); _selfPublicKey = null; @@ -1058,8 +1095,9 @@ class MeshCoreConnector extends ChangeNotifier { await sendFrame(buildDeviceQueryFrame()); await sendFrame(buildAppStartFrame()); await requestBatteryStatus(force: true); - await sendFrame(buildGetRadioSettingsFrame()); await sendFrame(buildGetCustomVarsFrame()); + await sendFrame(buildGetAutoAddFlagsFrame()); + _scheduleSelfInfoRetry(); } @@ -1070,7 +1108,7 @@ class MeshCoreConnector extends ChangeNotifier { await sendFrame(buildAppStartFrame()); await sendFrame(buildGetCustomVarsFrame()); await requestBatteryStatus(); - + await sendFrame(buildGetAutoAddFlagsFrame()); _scheduleSelfInfoRetry(); } @@ -1485,6 +1523,8 @@ class MeshCoreConnector extends ChangeNotifier { Future removeContact(Contact contact) async { if (!isConnected) return; + _handleDiscovery(contact, Uint8List(0), noNotify: true); + await sendFrame(buildRemoveContactFrame(contact.publicKey)); _contacts.removeWhere((c) => c.publicKeyHex == contact.publicKeyHex); _knownContactKeys.remove(contact.publicKeyHex); @@ -1499,6 +1539,42 @@ class MeshCoreConnector extends ChangeNotifier { notifyListeners(); } + Future removeDiscoveredContact(DiscoveryContact contact) async { + if (!isConnected) return; + _discoveredContacts.removeWhere( + (c) => c.publicKeyHex == contact.publicKeyHex, + ); + unawaited(_persistDiscoveredContacts()); + notifyListeners(); + } + + Future importDiscoveredContact(DiscoveryContact contact) async { + if (!isConnected) return; + + await sendFrame( + buildUpdateContactPathFrame( + contact.publicKey, + contact.path, + contact.pathLength, + type: contact.type, + flags: 0, + name: contact.name, + ), + ); + + _handleContactAdvert( + Contact( + publicKey: contact.publicKey, + name: contact.name, + type: contact.type, + pathLength: contact.pathLength, + path: contact.path, + lastSeen: DateTime.now(), + ), + ); + notifyListeners(); + } + Future clearContactPath(Contact contact) async { if (!isConnected) return; @@ -1899,8 +1975,9 @@ class MeshCoreConnector extends ChangeNotifier { case respCodeChannelInfo: _handleChannelInfo(frame); break; - case respCodeRadioSettings: - _handleRadioSettings(frame); + case respCodeAutoAddConfig: + _handleAutoAddConfig(frame); + _checkManualAddContacts(); break; case respCodeBattAndStorage: _handleBatteryAndStorage(frame); @@ -1973,25 +2050,35 @@ class MeshCoreConnector extends ChangeNotifier { // [56] = sf // [57] = cr // [58+] = node_name - if (frame.length < 4 + pubKeySize) return; + final reader = BufferReader(frame); + try { + reader.skipBytes(2); + _currentTxPower = reader.readByte(); + _maxTxPower = reader.readByte(); + _selfPublicKey = reader.readBytes(pubKeySize); + _selfLatitude = reader.readInt32LE() / 1000000.0; + _selfLongitude = reader.readInt32LE() / 1000000.0; + _multiAcks = reader.readByte(); + _advertLocPolicy = reader.readByte(); - _currentTxPower = frame[2]; - _maxTxPower = frame[3]; - _selfPublicKey = Uint8List.fromList(frame.sublist(4, 4 + pubKeySize)); - _selfLatitude = readInt32LE(frame, 36) / 1000000.0; - _selfLongitude = readInt32LE(frame, 40) / 1000000.0; + final telemetryFlag = reader.readByte(); + _telemetryModeBase = telemetryFlag & 0x03; + _telemetryModeEnv = telemetryFlag >> 2 & 0x03; + _telemetryModeLoc = telemetryFlag >> 4 & 0x03; - // Radio settings (if frame is long enough) - if (frame.length >= 58) { - _currentFreqHz = readUint32LE(frame, 48); - _currentBwHz = readUint32LE(frame, 52); - _currentSf = frame[56]; - _currentCr = frame[57]; - } + _manualAddContacts = reader.readByte() & 0x01 == 0x00; - // Node name starts at offset 58 if frame is long enough - if (frame.length > 58) { - _selfName = readCString(frame, 58, frame.length - 58); + _currentFreqHz = reader.readUInt32LE(); + _currentBwHz = reader.readUInt32LE(); + _currentSf = reader.readByte(); + _currentCr = reader.readByte(); + + _selfName = reader.readString(); + } catch (e) { + _appDebugLogService?.error( + 'Error parsing SELF_INFO frame: $e', + tag: 'Connector', + ); } _awaitingSelfInfo = false; _selfInfoRetryTimer?.cancel(); @@ -2052,25 +2139,6 @@ class MeshCoreConnector extends ChangeNotifier { unawaited(_requestNextQueuedMessage()); } - void _handleRadioSettings(Uint8List frame) { - // Frame format from C++: - // [0] = RESP_CODE_RADIO_SETTINGS - // [1-4] = freq (uint32 LE, in Hz) - // [5-8] = bw (uint32 LE, in Hz) - // [9] = sf - // [10] = cr - if (frame.length >= 11) { - _currentFreqHz = readUint32LE(frame, 1); - _currentBwHz = readUint32LE(frame, 5); - _currentSf = frame[9]; - _currentCr = frame[10]; - debugPrint( - 'Radio settings: freq=$_currentFreqHz bw=$_currentBwHz sf=$_currentSf cr=$_currentCr', - ); - notifyListeners(); - } - } - void _handleBatteryAndStorage(Uint8List frame) { // Frame format from C++: // [0] = RESP_CODE_BATT_AND_STORAGE @@ -2088,6 +2156,32 @@ class MeshCoreConnector extends ChangeNotifier { } } + void _checkManualAddContacts() async { + // If manual add contacts is enabled, set auto add config and other params. + // and disable it after + if (_manualAddContacts) { + await sendFrame( + buildSetAutoAddConfigFrame( + autoAddChat: true, + autoAddRepeater: true, + autoAddRoomServer: true, + autoAddSensor: true, + overwriteOldest: _overwriteOldest, + ), + ); + await sendFrame( + buildSetOtherParamsFrame( + (_telemetryModeEnv << 4) | + (_telemetryModeLoc << 2) | + (_telemetryModeBase), + _advertLocPolicy, + _multiAcks, + ), + ); + _manualAddContacts = false; + } + } + /// Calculate timeout for a message based on radio settings and path length /// Returns timeout in milliseconds, considering number of hops int calculateTimeout({required int pathLength, int messageBytes = 100}) { @@ -2271,6 +2365,10 @@ class MeshCoreConnector extends ChangeNotifier { await _contactStore.saveContacts(_contacts); } + Future _persistDiscoveredContacts() async { + await _discoveryContactStore.saveContacts(_discoveredContacts); + } + int _latestContactLastmod() { if (_contacts.isEmpty) return 0; var latest = 0; @@ -3705,22 +3803,99 @@ class MeshCoreConnector extends ChangeNotifier { appLogger.warn('Malformed RX frame: $e', tag: 'Connector'); return; } - + final rawPacket = frame.sublist(3); switch (payloadType) { case payloadTypeADVERT: - _handlePayloadAdvertReceived(payload, pathBytes, routeType, snr); + _handlePayloadAdvertReceived( + rawPacket, + payload, + pathBytes, + routeType, + snr, + ); break; default: } } + void importContact(Uint8List frame) { + final packet = BufferReader(frame); + int payloadType = 0; + Uint8List pathBytes = Uint8List(0); + try { + packet.skipBytes(1); // Skip frame type byte + packet.skipBytes(1); // Skip SNR byte + packet.skipBytes(1); // Skip RSSI byte + final header = packet.readByte(); + payloadType = (header >> 2) & 0x0F; + //final payloadVer = (header >> 6) & 0x03; + final pathLen = packet.readByte(); + pathBytes = packet.readBytes(pathLen); + } catch (e) { + appLogger.warn('Malformed RX frame: $e', tag: 'Connector'); + return; + } + double latitude = 0.0; + double longitude = 0.0; + String name = ''; + Uint8List publicKey = Uint8List(0); + int type = 0; + int timestamp = 0; + bool hasLocation = false; + bool hasName = false; + if (payloadType != payloadTypeADVERT) { + appLogger.warn('Unexpected payload type: $payloadType', tag: 'Connector'); + return; + } + try { + publicKey = packet.readBytes(32); + timestamp = packet.readInt32LE(); + //TODO add signature verification + packet.skipBytes(64); // Skip signature for now + final flags = packet.readByte(); + type = flags & 0x0F; + hasLocation = (flags & 0x10) != 0; + // For future use: + //final hasFeature1 = (flags & 0x20) != 0; + //final hasFeature2 = (flags & 0x40) != 0; + hasName = (flags & 0x80) != 0; + if (hasLocation && packet.remaining >= 8) { + latitude = packet.readInt32LE() / 1e6; + longitude = packet.readInt32LE() / 1e6; + } + if (hasName && packet.remaining > 0) { + name = packet.readString(); + } + } catch (e) { + appLogger.warn('Malformed advert frame: $e', tag: 'Connector'); + return; + } + + importDiscoveredContact( + DiscoveryContact( + rawPacket: frame, + publicKey: publicKey, + name: name, + type: type, + pathLength: pathBytes.length, + path: Uint8List.fromList( + pathBytes.reversed.toList(), + ), // Store path in reverse for easier use in outgoing messages + latitude: latitude, + longitude: longitude, + lastSeen: DateTime.fromMillisecondsSinceEpoch(timestamp * 1000), + ), + ); + } + void _handlePayloadAdvertReceived( - Uint8List frame, + Uint8List rawPacket, + Uint8List payload, Uint8List path, int routeType, double snr, ) { - final advert = BufferReader(frame); + final advert = BufferReader(payload); double latitude = 0.0; double longitude = 0.0; String name = ''; @@ -3758,6 +3933,7 @@ class MeshCoreConnector extends ChangeNotifier { return; } + //We ignore our own adverts if (listEquals(publicKey, _selfPublicKey)) { return; } @@ -3778,7 +3954,14 @@ class MeshCoreConnector extends ChangeNotifier { longitude: longitude, lastSeen: DateTime.fromMillisecondsSinceEpoch(timestamp * 1000), ); - _handleContactAdvert(newContact); + if ((_autoAddUsers && type == advTypeChat) || + (_autoAddRepeaters && type == advTypeRepeater) || + (_autoAddRoomServers && type == advTypeRoom) || + (_autoAddSensors && type == advTypeSensor)) { + _handleContactAdvert(newContact); + } else { + _handleDiscovery(newContact, rawPacket); + } _updateDirectRepeater(newContact, snr, path); return; } @@ -3866,6 +4049,84 @@ class MeshCoreConnector extends ChangeNotifier { } notifyListeners(); } + + void _handleAutoAddConfig(Uint8List frame) { + final reader = BufferReader(frame); + try { + reader.skipBytes(1); // Skip the response code byte + final flags = reader.readByte(); + _autoAddUsers = flags & autoAddChatFlag != 0; + _autoAddRepeaters = flags & autoAddRepeaterFlag != 0; + _autoAddRoomServers = flags & autoAddRoomServerFlag != 0; + _autoAddSensors = flags & autoAddSensorFlag != 0; + _overwriteOldest = flags & autoAddOverwriteOldestFlag != 0; + } catch (e) { + appLogger.error('Failed to parse auto-add config: $e', tag: 'Connector'); + } + } + + void _handleDiscovery( + Contact contact, + Uint8List rawPacket, { + bool noNotify = false, + }) { + appLogger.info('Discovered new contact: ${contact.name}', tag: 'Connector'); + + final existingIndex = _discoveredContacts.indexWhere( + (c) => c.publicKeyHex == contact.publicKeyHex, + ); + + // Update existing contact + if (existingIndex >= 0) { + _discoveredContacts[existingIndex] = _discoveredContacts[existingIndex] + .copyWith( + rawPacket: rawPacket, + name: contact.name, + type: contact.type, + pathLength: contact.pathLength, + path: contact.path, + latitude: contact.latitude, + longitude: contact.longitude, + lastSeen: contact.lastSeen, + ); + notifyListeners(); + unawaited(_persistDiscoveredContacts()); + return; + } + + final disContact = DiscoveryContact( + rawPacket: rawPacket, + publicKey: contact.publicKey, + name: contact.name, + type: contact.type, + pathLength: contact.pathLength, + path: contact.path, + latitude: contact.latitude, + longitude: contact.longitude, + lastSeen: contact.lastSeen, + ); + _discoveredContacts.add(disContact); + + unawaited(_persistDiscoveredContacts()); + + // Show notification for new contact (advertisement) + if (_appSettingsService != null && !noNotify) { + final settings = _appSettingsService!.settings; + if (settings.notificationsEnabled && settings.notifyOnNewAdvert) { + _notificationService.showAdvertNotification( + contactName: contact.name, + contactType: contact.typeLabel, + contactId: contact.publicKeyHex, + ); + } + } + } + + void removeAllDiscoveredContacts() { + _discoveredContacts.clear(); + unawaited(_persistDiscoveredContacts()); + notifyListeners(); + } } const int _phRouteMask = 0x03; diff --git a/lib/connector/meshcore_protocol.dart b/lib/connector/meshcore_protocol.dart index 938a274..58abf6f 100644 --- a/lib/connector/meshcore_protocol.dart +++ b/lib/connector/meshcore_protocol.dart @@ -120,25 +120,27 @@ class BufferWriter { } void writeHex(String hex) { - // Validate hex string length is even and not empty - if (hex.isEmpty || hex.length % 2 != 0) { - throw FormatException('Invalid hex string length: ${hex.length}'); - } - List result = []; - for (int i = 0; i < hex.length ~/ 2; i++) { - final hexByte = hex.substring(i * 2, i * 2 + 2); - final byte = int.tryParse(hexByte, radix: 16); - if (byte == null) { - throw FormatException( - 'Invalid hex characters at position $i: $hexByte', - ); - } - result.add(byte); - } - writeBytes(Uint8List.fromList(result)); + writeBytes(hex2Uint8List(hex)); } } +Uint8List hex2Uint8List(String hex) { + // Validate hex string length is even and not empty + if (hex.isEmpty || hex.length % 2 != 0) { + throw FormatException('Invalid hex string length: ${hex.length}'); + } + List result = []; + for (int i = 0; i < hex.length ~/ 2; i++) { + final hexByte = hex.substring(i * 2, i * 2 + 2); + final byte = int.tryParse(hexByte, radix: 16); + if (byte == null) { + throw FormatException('Invalid hex characters at position $i: $hexByte'); + } + result.add(byte); + } + return Uint8List.fromList(result); +} + // Command codes (to device) const int cmdAppStart = 1; const int cmdSendTxtMsg = 2; @@ -168,11 +170,13 @@ const int cmdGetChannel = 31; const int cmdSetChannel = 32; const int cmdSendTracePath = 36; const int cmdSetOtherParams = 38; -const int cmdGetRadioSettings = 57; +const int cmdSendAnonReq = 57; const int cmdGetTelemetryReq = 39; const int cmdGetCustomVar = 40; const int cmdSetCustomVar = 41; const int cmdSendBinaryReq = 50; +const int cmdSetAutoAddConfig = 58; +const int cmdGetAutoAddConfig = 59; // Text message types const int txtTypePlain = 0; @@ -206,8 +210,8 @@ const int respCodeDeviceInfo = 13; const int respCodeContactMsgRecvV3 = 16; const int respCodeChannelMsgRecvV3 = 17; const int respCodeChannelInfo = 18; -const int respCodeRadioSettings = 25; const int respCodeCustomVars = 21; +const int respCodeAutoAddConfig = 25; // Push codes (async from device) const int pushCodeAdvert = 0x80; @@ -253,6 +257,18 @@ const int payloadTypeCONTROL = 0x0B; // a control/discovery packet const int payloadTypeRawCustom = 0x0F; // custom packet as raw bytes, for applications with custom encryption, payloads, etc +//auto-add flags +const int autoAddOverwriteOldestFlag = + 1 << 0; // 0x01 - overwrite oldest non-favourite when full +const int autoAddChatFlag = + 1 << 1; // 0x02 - auto-add Chat (Companion) (ADV_TYPE_CHAT) +const int autoAddRepeaterFlag = + 1 << 2; // 0x04 - auto-add Repeater (ADV_TYPE_REPEATER) +const int autoAddRoomServerFlag = + 1 << 3; // 0x08 - auto-add Room Server (ADV_TYPE_ROOM) +const int autoAddSensorFlag = + 1 << 4; // 0x10 - auto-add Sensor (ADV_TYPE_SENSOR) + // Sizes const int pubKeySize = 32; const int maxPathSize = 64; @@ -303,7 +319,7 @@ const int contactNameOffset = 100; const int contactTimestampOffset = 132; const int contactLatOffset = 136; const int contactLonOffset = 140; -const int contactLastmodOffset = 144; +const int contactLastModOffset = 144; const int contactFrameSize = 148; // Message frame offsets @@ -681,16 +697,15 @@ Uint8List buildGetContactByKeyFrame(Uint8List pubKey) { return writer.toBytes(); } -// Build CMD_GET_RADIO_SETTINGS frame -Uint8List buildGetRadioSettingsFrame() { - return Uint8List.fromList([cmdGetRadioSettings]); -} - //Build CMD_GET_CUSTOM_VARS frame Uint8List buildGetCustomVarsFrame() { return Uint8List.fromList([cmdGetCustomVar]); } +Uint8List buildGetAutoAddFlagsFrame() { + return Uint8List.fromList([cmdGetAutoAddConfig]); +} + // Calculate LoRa airtime for a packet // Based on Semtech SX127x datasheet formula // Returns airtime in milliseconds @@ -815,10 +830,10 @@ Uint8List buildExportContactFrame(Uint8List pubKey) { // Build a import contact frame // [cmd][contact_frame x98+] -Uint8List buildImportContactFrame(String contactFrame) { +Uint8List buildImportContactFrame(Uint8List contactFrame) { final writer = BufferWriter(); writer.writeByte(cmdImportContact); - writer.writeHex(contactFrame); + writer.writeBytes(contactFrame); return writer.toBytes(); } @@ -832,20 +847,40 @@ Uint8List buildZeroHopContact(Uint8List pubKey) { } // Build CMD_SET_OTHER_PARAMS frame -// Format: [cmd][allowAutoAddContacts][allowTelemetryFlags][advertLocationPolicy][multiAcks] +// Format: [cmd][allowTelemetryFlags][advertLocationPolicy][multiAcks] Uint8List buildSetOtherParamsFrame( - bool allowAutoAddContacts, int allowTelemetryFlags, int advertLocationPolicy, int multiAcks, ) { final writer = BufferWriter(); writer.writeByte(cmdSetOtherParams); - writer.writeByte( - allowAutoAddContacts ? 0x00 : 0x01, - ); // Allow Auto Add Contacts + //Going forward the app will just set Auto Add Contacts to disabled, and use the filter flags + //Allow Auto Add Contacts use inverted logic (0x01 = disabled, 0x00 = enabled). + writer.writeByte(0x01); writer.writeByte(allowTelemetryFlags); // Allow Telemetry Flags writer.writeByte(advertLocationPolicy); // Advertisement Location Policy writer.writeByte(multiAcks); // Multi Acknowledgements return writer.toBytes(); } + +// Build CMD_SET_AUTO_ADD_CONFIG frame +// Format: [cmd][flags] +Uint8List buildSetAutoAddConfigFrame({ + required bool autoAddChat, + required bool autoAddRepeater, + required bool autoAddRoomServer, + required bool autoAddSensor, + required bool overwriteOldest, +}) { + final writer = BufferWriter(); + writer.writeByte(cmdSetAutoAddConfig); + int flags = 0; + if (autoAddChat) flags |= autoAddChatFlag; + if (autoAddRepeater) flags |= autoAddRepeaterFlag; + if (autoAddRoomServer) flags |= autoAddRoomServerFlag; + if (autoAddSensor) flags |= autoAddSensorFlag; + if (overwriteOldest) flags |= autoAddOverwriteOldestFlag; + writer.writeByte(flags); + return writer.toBytes(); +} diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index 2dbcf5e..832e090 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -1801,5 +1801,30 @@ "contacts_unread": "Непрочетено", "contacts_searchRepeaters": "Търсене на {number}{str} повтарящи се...", "contacts_searchContactsNoNumber": "Търси контакти...", - "contacts_searchUsers": "Търсене на {number}{str} потребители..." + "contacts_searchUsers": "Търсене на {number}{str} потребители...", + "contactsSettings_title": "Настройки на контактите", + "contactsSettings_autoAddTitle": "Автоматично откриване", + "contactsSettings_autoAddUsersTitle": "Автоматично добавяне на потребители", + "contactsSettings_otherTitle": "Други настройки свързани с контакти", + "settings_contactSettingsSubtitle": "Настройки за добавяне на контакти.", + "settings_contactSettings": "Настройки за контакти", + "contactsSettings_autoAddSensorsTitle": "Автоматично добавяне на датчици", + "contactsSettings_autoAddRoomServersTitle": "Автоматично добавяне на сървъри на стаите", + "contactsSettings_autoAddRoomServersSubtitle": "Позволи на спътника да добавя автоматично откритите сървъри на стаите.", + "contactsSettings_autoAddRepeatersTitle": "Автоматично добавяне на повтарящи се елементи", + "contactsSettings_autoAddUsersSubtitle": "Позволи на спътника да добавя автоматично откритите потребители.", + "contactsSettings_autoAddRepeatersSubtitle": "Позволи на спътника да добавя автоматично откритите повтарящи се устройства.", + "contactsSettings_autoAddSensorsSubtitle": "Позволи на спътника да добавя автоматично откритите датчици.", + "contactsSettings_overwriteOldestTitle": "Премахни най-старото", + "discoveredContacts_Title": "Открити контакти", + "discoveredContacts_searchHint": "Търсене на открити контакти", + "discoveredContacts_noMatching": "Няма съвпадащи контакти", + "discoveredContacts_contactAdded": "Контакт добавен", + "discoveredContacts_copyContact": "Копирай контакт в клипборда", + "discoveredContacts_deleteContact": "Изтрий контакт", + "discoveredContacts_addContact": "Добави контакт", + "contactsSettings_overwriteOldestSubtitle": "Когато списъкът с контакти е пълен, най-старият неключов контакт ще бъде заменен.", + "discoveredContacts_deleteContactAll": "Изтриване на Всички Открити Контакти", + "discoveredContacts_deleteContactAllContent": "Сигурни ли сте, че искате да изтриете всички открити контакти?", + "common_deleteAll": "Изтрий всичко" } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index 07190a9..c1d344f 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1829,5 +1829,30 @@ "contacts_searchRepeaters": "Suche {number}{str} Repeater...", "contacts_searchFavorites": "Suche {number}{str} Favoriten...", "contacts_searchUsers": "Suche {number}{str} Benutzer...", - "contacts_searchRoomServers": "Suche {number}{str} Raumserver..." + "contacts_searchRoomServers": "Suche {number}{str} Raumserver...", + "settings_contactSettings": "Kontakteinstellungen", + "contactsSettings_otherTitle": "Weitere Einstellungen zu Kontakten", + "contactsSettings_title": "Kontakteinstellungen", + "contactsSettings_autoAddTitle": "Automatische Erkennung", + "contactsSettings_autoAddUsersTitle": "Automatische Hinzufügung von Benutzern", + "settings_contactSettingsSubtitle": "Einstellungen für das Hinzufügen von Kontakten", + "contactsSettings_autoAddSensorsTitle": "Automatisch Sensoren hinzufügen", + "contactsSettings_autoAddUsersSubtitle": "Ermöglichen Sie dem Begleiter, automatisch entdeckte Benutzer hinzuzufügen", + "contactsSettings_autoAddRoomServersTitle": "Automatisch Raumservers hinzufügen", + "contactsSettings_autoAddRoomServersSubtitle": "Ermöglichen Sie dem Begleiter, entdeckte Raumserver automatisch hinzuzufügen", + "contactsSettings_autoAddRepeatersTitle": "Automatisch Repeater hinzufügen", + "contactsSettings_autoAddRepeatersSubtitle": "Ermöglichen Sie dem Begleiter, automatisch entdeckte Repeater hinzuzufügen.", + "discoveredContacts_noMatching": "Keine passenden Kontakte", + "discoveredContacts_searchHint": "Entdeckte Kontakte suchen", + "discoveredContacts_addContact": "Kontakt hinzufügen", + "discoveredContacts_contactAdded": "Kontakt hinzugefügt", + "discoveredContacts_deleteContact": "Kontakt löschen", + "discoveredContacts_Title": "Entdeckte Kontakte", + "discoveredContacts_copyContact": "Kontakt in die Zwischenablage kopieren", + "contactsSettings_overwriteOldestTitle": "Überschreiben des Ältesten", + "contactsSettings_autoAddSensorsSubtitle": "Ermöglichen Sie dem Begleiter, automatisch entdeckte Sensoren hinzuzufügen", + "contactsSettings_overwriteOldestSubtitle": "Wenn die Kontaktliste voll ist, wird der älteste nicht favorisierte Kontakt ersetzt.", + "common_deleteAll": "Alles löschen", + "discoveredContacts_deleteContactAllContent": "Sind Sie sicher, dass Sie alle gefundenen Kontakte löschen möchten?", + "discoveredContacts_deleteContactAll": "Alle entdeckten Kontakte löschen" } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index f0b0587..99221dc 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -10,6 +10,7 @@ "common_unknownDevice": "Unknown Device", "common_save": "Save", "common_delete": "Delete", + "common_deleteAll": "Delete All", "common_close": "Close", "common_edit": "Edit", "common_add": "Add", @@ -100,6 +101,8 @@ "settings_locationIntervalInvalid": "Interval must be at least 60 seconds, and less than 86400 seconds.", "settings_latitude": "Latitude", "settings_longitude": "Longitude", + "settings_contactSettings": "Contact Settings", + "settings_contactSettingsSubtitle": "Settings for how contacts are added.", "settings_privacyMode": "Privacy Mode", "settings_privacyModeSubtitle": "Hide name/location in advertisements", "settings_privacyModeToggle": "Toggle privacy mode to hide your name and location in advertisements.", @@ -1839,5 +1842,27 @@ "settings_gpxExportShareText": "Map data exported from meshcore-open", "settings_gpxExportShareSubject": "meshcore-open GPX map data export", "snrIndicator_nearByRepeaters": "Nearby Repeaters", - "snrIndicator_lastSeen": "Last seen" -} + "snrIndicator_lastSeen": "Last seen", + "contactsSettings_title": "Contacts settings", + "contactsSettings_autoAddTitle": "Automatic Discovery", + "contactsSettings_otherTitle": "Other contact related settings", + "contactsSettings_autoAddUsersTitle": "Auto-add users", + "contactsSettings_autoAddUsersSubtitle": "Allow the companion to automatically add discovered users.", + "contactsSettings_autoAddRepeatersTitle": "Auto-add repeaters", + "contactsSettings_autoAddRepeatersSubtitle": "Allow the companion to automatically add discovered repeaters.", + "contactsSettings_autoAddRoomServersTitle": "Auto-add room servers", + "contactsSettings_autoAddRoomServersSubtitle": "Allow the companion to automatically add discovered room servers.", + "contactsSettings_autoAddSensorsTitle": "Auto-add sensors", + "contactsSettings_autoAddSensorsSubtitle": "Allow the companion to automatically add discovered sensors.", + "contactsSettings_overwriteOldestTitle": "Overwrite Oldest", + "contactsSettings_overwriteOldestSubtitle": "When the contact list is full, the oldest non-favorited contact will be replaced.", + "discoveredContacts_Title": "Discovered Contacts", + "discoveredContacts_noMatching": "No matching contacts", + "discoveredContacts_searchHint": "Search discovered contacts", + "discoveredContacts_contactAdded": "Contact added", + "discoveredContacts_addContact": "Add Contact", + "discoveredContacts_copyContact": "Copy Contact to clipboard", + "discoveredContacts_deleteContact": "Delete Discovered Contact", + "discoveredContacts_deleteContactAll": "Delete All Discovered Contacts", + "discoveredContacts_deleteContactAllContent": "Are you sure you want to delete all discovered contacts?" +} \ No newline at end of file diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 47765c6..1d3c4d5 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1829,5 +1829,30 @@ "contacts_searchFavorites": "Buscar {number}{str} Favoritos...", "contacts_searchUsers": "Buscar {number}{str} Usuarios...", "contacts_searchRepeaters": "Buscar {number}{str} Repetidores...", - "contacts_searchRoomServers": "Buscar {number}{str} servidores de sala..." + "contacts_searchRoomServers": "Buscar {number}{str} servidores de sala...", + "contactsSettings_autoAddTitle": "Detección automática", + "settings_contactSettings": "Configuración de contacto", + "contactsSettings_autoAddUsersTitle": "Agregar usuarios automáticamente", + "contactsSettings_otherTitle": "Otras configuraciones relacionadas con el contacto", + "contactsSettings_autoAddUsersSubtitle": "Permitir que el compañero agregue automáticamente a los usuarios descubiertos.", + "contactsSettings_autoAddRepeatersSubtitle": "Permitir que el compañero agregue automáticamente los repetidores descubiertos.", + "contactsSettings_autoAddRoomServersSubtitle": "Permitir que el compañero agregue automáticamente los servidores de salas descubiertos.", + "contactsSettings_autoAddSensorsTitle": "Agregar sensores automáticamente", + "contactsSettings_title": "Configuración de contactos", + "settings_contactSettingsSubtitle": "Configuración de cómo se agregan los contactos.", + "contactsSettings_autoAddSensorsSubtitle": "Permitir que el compañero agregue automáticamente los sensores descubiertos.", + "contactsSettings_autoAddRepeatersTitle": "Agregar repetidores automáticamente", + "contactsSettings_overwriteOldestTitle": "Sobreescribir el más antiguo", + "contactsSettings_autoAddRoomServersTitle": "Agregar automáticamente servidores de sala", + "discoveredContacts_noMatching": "No se encontraron contactos coincidentes", + "discoveredContacts_contactAdded": "Contacto agregado", + "discoveredContacts_copyContact": "Copiar contacto al portapapeles", + "discoveredContacts_deleteContact": "Eliminar contacto", + "discoveredContacts_Title": "Contactos descubiertos", + "discoveredContacts_searchHint": "Buscar contactos descubiertos", + "discoveredContacts_addContact": "Agregar contacto", + "contactsSettings_overwriteOldestSubtitle": "Cuando la lista de contactos esté llena, se reemplazará el contacto no favorito más antiguo.", + "common_deleteAll": "Eliminar todo", + "discoveredContacts_deleteContactAll": "Eliminar Todos los Contactos Descubiertos", + "discoveredContacts_deleteContactAllContent": "¿Está seguro de que desea eliminar todos los contactos descubiertos!" } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index b742dc9..1eae5b9 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1801,5 +1801,30 @@ "contacts_searchUsers": "Rechercher {number}{str} utilisateurs...", "contacts_searchRoomServers": "Rechercher {number}{str} serveurs de salle...", "contacts_searchRepeaters": "Rechercher {number}{str} Répéteurs...", - "contacts_searchContactsNoNumber": "Rechercher des contacts..." + "contacts_searchContactsNoNumber": "Rechercher des contacts...", + "settings_contactSettings": "Paramètres de contact", + "settings_contactSettingsSubtitle": "Paramètres pour l'ajout de contacts", + "contactsSettings_autoAddRepeatersTitle": "Ajouter automatiquement les répéteurs", + "contactsSettings_autoAddRepeatersSubtitle": "Autoriser le compagnon à ajouter automatiquement les répéteurs découverts", + "contactsSettings_autoAddRoomServersTitle": "Ajouter automatiquement les serveurs de salle", + "contactsSettings_autoAddRoomServersSubtitle": "Autoriser le compagnon à ajouter automatiquement les serveurs de salles découverts", + "contactsSettings_otherTitle": "Autres paramètres liés aux contacts", + "contactsSettings_title": "Paramètres des contacts", + "contactsSettings_autoAddUsersTitle": "Ajouter automatiquement les utilisateurs", + "contactsSettings_autoAddTitle": "Découverte automatique", + "contactsSettings_autoAddSensorsTitle": "Ajouter automatiquement les capteurs", + "contactsSettings_autoAddUsersSubtitle": "Autoriser le compagnon à ajouter automatiquement les utilisateurs découverts", + "discoveredContacts_noMatching": "Aucun contact correspondant", + "discoveredContacts_contactAdded": "Contact ajouté", + "discoveredContacts_addContact": "Ajouter un contact", + "discoveredContacts_copyContact": "Copier le contact dans le presse-papiers", + "discoveredContacts_deleteContact": "Supprimer le contact", + "contactsSettings_overwriteOldestTitle": "Écraser le plus ancien", + "contactsSettings_autoAddSensorsSubtitle": "Autoriser le compagnon à ajouter automatiquement les capteurs découverts.", + "discoveredContacts_Title": "Contacts découverts", + "discoveredContacts_searchHint": "Rechercher des contacts découverts", + "contactsSettings_overwriteOldestSubtitle": "Lorsque la liste de contacts est pleine, le contact le plus ancien non favori sera remplacé.", + "common_deleteAll": "Supprimer tout", + "discoveredContacts_deleteContactAll": "Supprimer tous les contacts découverts", + "discoveredContacts_deleteContactAllContent": "Êtes-vous sûr de vouloir supprimer tous les contacts découverts ?" } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index 82adad8..9a1f1a4 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1801,5 +1801,30 @@ "contacts_searchFavorites": "Cerca {number}{str} Preferiti...", "contacts_unread": "Non letti", "contacts_searchRepeaters": "Cerca {number}{str} Ripetitori...", - "contacts_searchRoomServers": "Cerca {number}{str} server Room..." + "contacts_searchRoomServers": "Cerca {number}{str} server Room...", + "contactsSettings_title": "Impostazioni dei contatti", + "settings_contactSettings": "Impostazioni di contatto", + "contactsSettings_otherTitle": "Altre impostazioni relative ai contatti", + "contactsSettings_autoAddUsersSubtitle": "Consenti al compagno di aggiungere automaticamente gli utenti scoperti.", + "contactsSettings_autoAddRepeatersTitle": "Aggiungere ripetitori automaticamente", + "contactsSettings_autoAddRoomServersSubtitle": "Consenti al compagno di aggiungere automaticamente i server delle stanze scoperte.", + "contactsSettings_autoAddSensorsTitle": "Aggiungere automaticamente i sensori", + "settings_contactSettingsSubtitle": "Impostazioni per l'aggiunta dei contatti", + "contactsSettings_autoAddUsersTitle": "Aggiungere utenti automaticamente", + "contactsSettings_autoAddTitle": "Scoperta automatica", + "contactsSettings_autoAddSensorsSubtitle": "Consenti al compagno di aggiungere automaticamente i sensori scoperti", + "discoveredContacts_noMatching": "Nessun contatto corrispondente", + "contactsSettings_autoAddRepeatersSubtitle": "Consenti al compagno di aggiungere automaticamente i ripetitori scoperti.", + "discoveredContacts_searchHint": "Cerca contatti scoperti", + "contactsSettings_autoAddRoomServersTitle": "Aggiungere automaticamente i server delle stanze", + "discoveredContacts_addContact": "Aggiungi contatto", + "contactsSettings_overwriteOldestTitle": "Sostituisci il più vecchio", + "discoveredContacts_Title": "Contatti scoperti", + "discoveredContacts_contactAdded": "Contatto aggiunto", + "discoveredContacts_deleteContact": "Elimina Contatto", + "discoveredContacts_copyContact": "Copia contatto negli appunti", + "contactsSettings_overwriteOldestSubtitle": "Quando l'elenco dei contatti è pieno, il contatto più vecchio non tra i preferiti verrà sostituito.", + "common_deleteAll": "Elimina tutto", + "discoveredContacts_deleteContactAllContent": "Sei sicuro di voler eliminare tutti i contatti scoperti?", + "discoveredContacts_deleteContactAll": "Eliminare tutti i contatti scoperti" } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index c48994c..0eee461 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -184,6 +184,12 @@ abstract class AppLocalizations { /// **'Delete'** String get common_delete; + /// No description provided for @common_deleteAll. + /// + /// In en, this message translates to: + /// **'Delete All'** + String get common_deleteAll; + /// No description provided for @common_close. /// /// In en, this message translates to: @@ -556,6 +562,18 @@ abstract class AppLocalizations { /// **'Longitude'** String get settings_longitude; + /// No description provided for @settings_contactSettings. + /// + /// In en, this message translates to: + /// **'Contact Settings'** + String get settings_contactSettings; + + /// No description provided for @settings_contactSettingsSubtitle. + /// + /// In en, this message translates to: + /// **'Settings for how contacts are added.'** + String get settings_contactSettingsSubtitle; + /// No description provided for @settings_privacyMode. /// /// In en, this message translates to: @@ -5392,6 +5410,138 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Last seen'** String get snrIndicator_lastSeen; + + /// No description provided for @contactsSettings_title. + /// + /// In en, this message translates to: + /// **'Contacts settings'** + String get contactsSettings_title; + + /// No description provided for @contactsSettings_autoAddTitle. + /// + /// In en, this message translates to: + /// **'Automatic Discovery'** + String get contactsSettings_autoAddTitle; + + /// No description provided for @contactsSettings_otherTitle. + /// + /// In en, this message translates to: + /// **'Other contact related settings'** + String get contactsSettings_otherTitle; + + /// No description provided for @contactsSettings_autoAddUsersTitle. + /// + /// In en, this message translates to: + /// **'Auto-add users'** + String get contactsSettings_autoAddUsersTitle; + + /// No description provided for @contactsSettings_autoAddUsersSubtitle. + /// + /// In en, this message translates to: + /// **'Allow the companion to automatically add discovered users.'** + String get contactsSettings_autoAddUsersSubtitle; + + /// No description provided for @contactsSettings_autoAddRepeatersTitle. + /// + /// In en, this message translates to: + /// **'Auto-add repeaters'** + String get contactsSettings_autoAddRepeatersTitle; + + /// No description provided for @contactsSettings_autoAddRepeatersSubtitle. + /// + /// In en, this message translates to: + /// **'Allow the companion to automatically add discovered repeaters.'** + String get contactsSettings_autoAddRepeatersSubtitle; + + /// No description provided for @contactsSettings_autoAddRoomServersTitle. + /// + /// In en, this message translates to: + /// **'Auto-add room servers'** + String get contactsSettings_autoAddRoomServersTitle; + + /// No description provided for @contactsSettings_autoAddRoomServersSubtitle. + /// + /// In en, this message translates to: + /// **'Allow the companion to automatically add discovered room servers.'** + String get contactsSettings_autoAddRoomServersSubtitle; + + /// No description provided for @contactsSettings_autoAddSensorsTitle. + /// + /// In en, this message translates to: + /// **'Auto-add sensors'** + String get contactsSettings_autoAddSensorsTitle; + + /// No description provided for @contactsSettings_autoAddSensorsSubtitle. + /// + /// In en, this message translates to: + /// **'Allow the companion to automatically add discovered sensors.'** + String get contactsSettings_autoAddSensorsSubtitle; + + /// No description provided for @contactsSettings_overwriteOldestTitle. + /// + /// In en, this message translates to: + /// **'Overwrite Oldest'** + String get contactsSettings_overwriteOldestTitle; + + /// No description provided for @contactsSettings_overwriteOldestSubtitle. + /// + /// In en, this message translates to: + /// **'When the contact list is full, the oldest non-favorited contact will be replaced.'** + String get contactsSettings_overwriteOldestSubtitle; + + /// No description provided for @discoveredContacts_Title. + /// + /// In en, this message translates to: + /// **'Discovered Contacts'** + String get discoveredContacts_Title; + + /// No description provided for @discoveredContacts_noMatching. + /// + /// In en, this message translates to: + /// **'No matching contacts'** + String get discoveredContacts_noMatching; + + /// No description provided for @discoveredContacts_searchHint. + /// + /// In en, this message translates to: + /// **'Search discovered contacts'** + String get discoveredContacts_searchHint; + + /// No description provided for @discoveredContacts_contactAdded. + /// + /// In en, this message translates to: + /// **'Contact added'** + String get discoveredContacts_contactAdded; + + /// No description provided for @discoveredContacts_addContact. + /// + /// In en, this message translates to: + /// **'Add Contact'** + String get discoveredContacts_addContact; + + /// No description provided for @discoveredContacts_copyContact. + /// + /// In en, this message translates to: + /// **'Copy Contact to clipboard'** + String get discoveredContacts_copyContact; + + /// No description provided for @discoveredContacts_deleteContact. + /// + /// In en, this message translates to: + /// **'Delete Discovered Contact'** + String get discoveredContacts_deleteContact; + + /// No description provided for @discoveredContacts_deleteContactAll. + /// + /// In en, this message translates to: + /// **'Delete All Discovered Contacts'** + String get discoveredContacts_deleteContactAll; + + /// No description provided for @discoveredContacts_deleteContactAllContent. + /// + /// In en, this message translates to: + /// **'Are you sure you want to delete all discovered contacts?'** + String get discoveredContacts_deleteContactAllContent; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index c168b7c..aa597c5 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -38,6 +38,9 @@ class AppLocalizationsBg extends AppLocalizations { @override String get common_delete => 'Изтрий'; + @override + String get common_deleteAll => 'Изтрий всичко'; + @override String get common_close => 'Затвори'; @@ -241,6 +244,13 @@ class AppLocalizationsBg extends AppLocalizations { @override String get settings_longitude => 'Дължина'; + @override + String get settings_contactSettings => 'Настройки за контакти'; + + @override + String get settings_contactSettingsSubtitle => + 'Настройки за добавяне на контакти.'; + @override String get settings_privacyMode => 'Режим на поверителност'; @@ -3119,4 +3129,82 @@ class AppLocalizationsBg extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Последно видян'; + + @override + String get contactsSettings_title => 'Настройки на контактите'; + + @override + String get contactsSettings_autoAddTitle => 'Автоматично откриване'; + + @override + String get contactsSettings_otherTitle => + 'Други настройки свързани с контакти'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Автоматично добавяне на потребители'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Позволи на спътника да добавя автоматично откритите потребители.'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Автоматично добавяне на повтарящи се елементи'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Позволи на спътника да добавя автоматично откритите повтарящи се устройства.'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Автоматично добавяне на сървъри на стаите'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Позволи на спътника да добавя автоматично откритите сървъри на стаите.'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Автоматично добавяне на датчици'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Позволи на спътника да добавя автоматично откритите датчици.'; + + @override + String get contactsSettings_overwriteOldestTitle => 'Премахни най-старото'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Когато списъкът с контакти е пълен, най-старият неключов контакт ще бъде заменен.'; + + @override + String get discoveredContacts_Title => 'Открити контакти'; + + @override + String get discoveredContacts_noMatching => 'Няма съвпадащи контакти'; + + @override + String get discoveredContacts_searchHint => 'Търсене на открити контакти'; + + @override + String get discoveredContacts_contactAdded => 'Контакт добавен'; + + @override + String get discoveredContacts_addContact => 'Добави контакт'; + + @override + String get discoveredContacts_copyContact => 'Копирай контакт в клипборда'; + + @override + String get discoveredContacts_deleteContact => 'Изтрий контакт'; + + @override + String get discoveredContacts_deleteContactAll => + 'Изтриване на Всички Открити Контакти'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Сигурни ли сте, че искате да изтриете всички открити контакти?'; } diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index c7eb927..479a050 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -38,6 +38,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get common_delete => 'Löschen'; + @override + String get common_deleteAll => 'Alles löschen'; + @override String get common_close => 'Schließen'; @@ -240,6 +243,13 @@ class AppLocalizationsDe extends AppLocalizations { @override String get settings_longitude => 'Längengrad'; + @override + String get settings_contactSettings => 'Kontakteinstellungen'; + + @override + String get settings_contactSettingsSubtitle => + 'Einstellungen für das Hinzufügen von Kontakten'; + @override String get settings_privacyMode => 'Privatsphäreeinstellung'; @@ -3128,4 +3138,84 @@ class AppLocalizationsDe extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Zuletzt gesehen'; + + @override + String get contactsSettings_title => 'Kontakteinstellungen'; + + @override + String get contactsSettings_autoAddTitle => 'Automatische Erkennung'; + + @override + String get contactsSettings_otherTitle => + 'Weitere Einstellungen zu Kontakten'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Automatische Hinzufügung von Benutzern'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Ermöglichen Sie dem Begleiter, automatisch entdeckte Benutzer hinzuzufügen'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Automatisch Repeater hinzufügen'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Ermöglichen Sie dem Begleiter, automatisch entdeckte Repeater hinzuzufügen.'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Automatisch Raumservers hinzufügen'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Ermöglichen Sie dem Begleiter, entdeckte Raumserver automatisch hinzuzufügen'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Automatisch Sensoren hinzufügen'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Ermöglichen Sie dem Begleiter, automatisch entdeckte Sensoren hinzuzufügen'; + + @override + String get contactsSettings_overwriteOldestTitle => + 'Überschreiben des Ältesten'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Wenn die Kontaktliste voll ist, wird der älteste nicht favorisierte Kontakt ersetzt.'; + + @override + String get discoveredContacts_Title => 'Entdeckte Kontakte'; + + @override + String get discoveredContacts_noMatching => 'Keine passenden Kontakte'; + + @override + String get discoveredContacts_searchHint => 'Entdeckte Kontakte suchen'; + + @override + String get discoveredContacts_contactAdded => 'Kontakt hinzugefügt'; + + @override + String get discoveredContacts_addContact => 'Kontakt hinzufügen'; + + @override + String get discoveredContacts_copyContact => + 'Kontakt in die Zwischenablage kopieren'; + + @override + String get discoveredContacts_deleteContact => 'Kontakt löschen'; + + @override + String get discoveredContacts_deleteContactAll => + 'Alle entdeckten Kontakte löschen'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Sind Sie sicher, dass Sie alle gefundenen Kontakte löschen möchten?'; } diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index 4458062..2fbc97a 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -38,6 +38,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get common_delete => 'Delete'; + @override + String get common_deleteAll => 'Delete All'; + @override String get common_close => 'Close'; @@ -239,6 +242,13 @@ class AppLocalizationsEn extends AppLocalizations { @override String get settings_longitude => 'Longitude'; + @override + String get settings_contactSettings => 'Contact Settings'; + + @override + String get settings_contactSettingsSubtitle => + 'Settings for how contacts are added.'; + @override String get settings_privacyMode => 'Privacy Mode'; @@ -3072,4 +3082,78 @@ class AppLocalizationsEn extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Last seen'; + + @override + String get contactsSettings_title => 'Contacts settings'; + + @override + String get contactsSettings_autoAddTitle => 'Automatic Discovery'; + + @override + String get contactsSettings_otherTitle => 'Other contact related settings'; + + @override + String get contactsSettings_autoAddUsersTitle => 'Auto-add users'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Allow the companion to automatically add discovered users.'; + + @override + String get contactsSettings_autoAddRepeatersTitle => 'Auto-add repeaters'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Allow the companion to automatically add discovered repeaters.'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Auto-add room servers'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Allow the companion to automatically add discovered room servers.'; + + @override + String get contactsSettings_autoAddSensorsTitle => 'Auto-add sensors'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Allow the companion to automatically add discovered sensors.'; + + @override + String get contactsSettings_overwriteOldestTitle => 'Overwrite Oldest'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'When the contact list is full, the oldest non-favorited contact will be replaced.'; + + @override + String get discoveredContacts_Title => 'Discovered Contacts'; + + @override + String get discoveredContacts_noMatching => 'No matching contacts'; + + @override + String get discoveredContacts_searchHint => 'Search discovered contacts'; + + @override + String get discoveredContacts_contactAdded => 'Contact added'; + + @override + String get discoveredContacts_addContact => 'Add Contact'; + + @override + String get discoveredContacts_copyContact => 'Copy Contact to clipboard'; + + @override + String get discoveredContacts_deleteContact => 'Delete Discovered Contact'; + + @override + String get discoveredContacts_deleteContactAll => + 'Delete All Discovered Contacts'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Are you sure you want to delete all discovered contacts?'; } diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index ce4b615..6227e5f 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -38,6 +38,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get common_delete => 'Eliminar'; + @override + String get common_deleteAll => 'Eliminar todo'; + @override String get common_close => 'Cerrar'; @@ -240,6 +243,13 @@ class AppLocalizationsEs extends AppLocalizations { @override String get settings_longitude => 'Longitud'; + @override + String get settings_contactSettings => 'Configuración de contacto'; + + @override + String get settings_contactSettingsSubtitle => + 'Configuración de cómo se agregan los contactos.'; + @override String get settings_privacyMode => 'Modo Privacidad'; @@ -3120,4 +3130,85 @@ class AppLocalizationsEs extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Visto por última vez'; + + @override + String get contactsSettings_title => 'Configuración de contactos'; + + @override + String get contactsSettings_autoAddTitle => 'Detección automática'; + + @override + String get contactsSettings_otherTitle => + 'Otras configuraciones relacionadas con el contacto'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Agregar usuarios automáticamente'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Permitir que el compañero agregue automáticamente a los usuarios descubiertos.'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Agregar repetidores automáticamente'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Permitir que el compañero agregue automáticamente los repetidores descubiertos.'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Agregar automáticamente servidores de sala'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Permitir que el compañero agregue automáticamente los servidores de salas descubiertos.'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Agregar sensores automáticamente'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Permitir que el compañero agregue automáticamente los sensores descubiertos.'; + + @override + String get contactsSettings_overwriteOldestTitle => + 'Sobreescribir el más antiguo'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Cuando la lista de contactos esté llena, se reemplazará el contacto no favorito más antiguo.'; + + @override + String get discoveredContacts_Title => 'Contactos descubiertos'; + + @override + String get discoveredContacts_noMatching => + 'No se encontraron contactos coincidentes'; + + @override + String get discoveredContacts_searchHint => 'Buscar contactos descubiertos'; + + @override + String get discoveredContacts_contactAdded => 'Contacto agregado'; + + @override + String get discoveredContacts_addContact => 'Agregar contacto'; + + @override + String get discoveredContacts_copyContact => + 'Copiar contacto al portapapeles'; + + @override + String get discoveredContacts_deleteContact => 'Eliminar contacto'; + + @override + String get discoveredContacts_deleteContactAll => + 'Eliminar Todos los Contactos Descubiertos'; + + @override + String get discoveredContacts_deleteContactAllContent => + '¿Está seguro de que desea eliminar todos los contactos descubiertos!'; } diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 6118444..7ce62b9 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -38,6 +38,9 @@ class AppLocalizationsFr extends AppLocalizations { @override String get common_delete => 'Supprimer'; + @override + String get common_deleteAll => 'Supprimer tout'; + @override String get common_close => 'Fermer'; @@ -241,6 +244,13 @@ class AppLocalizationsFr extends AppLocalizations { @override String get settings_longitude => 'Longitude'; + @override + String get settings_contactSettings => 'Paramètres de contact'; + + @override + String get settings_contactSettingsSubtitle => + 'Paramètres pour l\'ajout de contacts'; + @override String get settings_privacyMode => 'Mode de confidentialité'; @@ -3142,4 +3152,84 @@ class AppLocalizationsFr extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Dernière fois vu'; + + @override + String get contactsSettings_title => 'Paramètres des contacts'; + + @override + String get contactsSettings_autoAddTitle => 'Découverte automatique'; + + @override + String get contactsSettings_otherTitle => + 'Autres paramètres liés aux contacts'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Ajouter automatiquement les utilisateurs'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Autoriser le compagnon à ajouter automatiquement les utilisateurs découverts'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Ajouter automatiquement les répéteurs'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Autoriser le compagnon à ajouter automatiquement les répéteurs découverts'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Ajouter automatiquement les serveurs de salle'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Autoriser le compagnon à ajouter automatiquement les serveurs de salles découverts'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Ajouter automatiquement les capteurs'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Autoriser le compagnon à ajouter automatiquement les capteurs découverts.'; + + @override + String get contactsSettings_overwriteOldestTitle => 'Écraser le plus ancien'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Lorsque la liste de contacts est pleine, le contact le plus ancien non favori sera remplacé.'; + + @override + String get discoveredContacts_Title => 'Contacts découverts'; + + @override + String get discoveredContacts_noMatching => 'Aucun contact correspondant'; + + @override + String get discoveredContacts_searchHint => + 'Rechercher des contacts découverts'; + + @override + String get discoveredContacts_contactAdded => 'Contact ajouté'; + + @override + String get discoveredContacts_addContact => 'Ajouter un contact'; + + @override + String get discoveredContacts_copyContact => + 'Copier le contact dans le presse-papiers'; + + @override + String get discoveredContacts_deleteContact => 'Supprimer le contact'; + + @override + String get discoveredContacts_deleteContactAll => + 'Supprimer tous les contacts découverts'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Êtes-vous sûr de vouloir supprimer tous les contacts découverts ?'; } diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index 20873b9..d173456 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -38,6 +38,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get common_delete => 'Elimina'; + @override + String get common_deleteAll => 'Elimina tutto'; + @override String get common_close => 'Chiudi'; @@ -240,6 +243,13 @@ class AppLocalizationsIt extends AppLocalizations { @override String get settings_longitude => 'Longitudine'; + @override + String get settings_contactSettings => 'Impostazioni di contatto'; + + @override + String get settings_contactSettingsSubtitle => + 'Impostazioni per l\'aggiunta dei contatti'; + @override String get settings_privacyMode => 'Modalità Privacy'; @@ -3123,4 +3133,83 @@ class AppLocalizationsIt extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Ultimo accesso'; + + @override + String get contactsSettings_title => 'Impostazioni dei contatti'; + + @override + String get contactsSettings_autoAddTitle => 'Scoperta automatica'; + + @override + String get contactsSettings_otherTitle => + 'Altre impostazioni relative ai contatti'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Aggiungere utenti automaticamente'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Consenti al compagno di aggiungere automaticamente gli utenti scoperti.'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Aggiungere ripetitori automaticamente'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Consenti al compagno di aggiungere automaticamente i ripetitori scoperti.'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Aggiungere automaticamente i server delle stanze'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Consenti al compagno di aggiungere automaticamente i server delle stanze scoperte.'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Aggiungere automaticamente i sensori'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Consenti al compagno di aggiungere automaticamente i sensori scoperti'; + + @override + String get contactsSettings_overwriteOldestTitle => + 'Sostituisci il più vecchio'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Quando l\'elenco dei contatti è pieno, il contatto più vecchio non tra i preferiti verrà sostituito.'; + + @override + String get discoveredContacts_Title => 'Contatti scoperti'; + + @override + String get discoveredContacts_noMatching => 'Nessun contatto corrispondente'; + + @override + String get discoveredContacts_searchHint => 'Cerca contatti scoperti'; + + @override + String get discoveredContacts_contactAdded => 'Contatto aggiunto'; + + @override + String get discoveredContacts_addContact => 'Aggiungi contatto'; + + @override + String get discoveredContacts_copyContact => 'Copia contatto negli appunti'; + + @override + String get discoveredContacts_deleteContact => 'Elimina Contatto'; + + @override + String get discoveredContacts_deleteContactAll => + 'Eliminare tutti i contatti scoperti'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Sei sicuro di voler eliminare tutti i contatti scoperti?'; } diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 323981d..2a873a5 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -38,6 +38,9 @@ class AppLocalizationsNl extends AppLocalizations { @override String get common_delete => 'Verwijderen'; + @override + String get common_deleteAll => 'Alles verwijderen'; + @override String get common_close => 'Sluiten'; @@ -240,6 +243,13 @@ class AppLocalizationsNl extends AppLocalizations { @override String get settings_longitude => 'Lengtegraad'; + @override + String get settings_contactSettings => 'Contactinstellingen'; + + @override + String get settings_contactSettingsSubtitle => + 'Instellingen voor het toevoegen van contacten'; + @override String get settings_privacyMode => 'Privacy Mode'; @@ -3110,4 +3120,82 @@ class AppLocalizationsNl extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Laatst gezien'; + + @override + String get contactsSettings_title => 'Instellingen voor contacten'; + + @override + String get contactsSettings_autoAddTitle => 'Automatische detectie'; + + @override + String get contactsSettings_otherTitle => + 'Andere instellingen voor contactgerelateerde zaken'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Gebruikers automatisch toevoegen'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Sta toe dat de companion automatisch ontdekte gebruikers toevoegt'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Automatisch herhalingstoestellen toevoegen'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Sta toe dat de companion automatisch ontdekte repeaters toevoegt'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Automatisch kamerservers toevoegen'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Sta toe dat de companion automatisch ontdekte kamer servers toevoegt.'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Automatisch sensoren toevoegen'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Sta toe dat de companion automatisch ontdekte sensoren toevoegt'; + + @override + String get contactsSettings_overwriteOldestTitle => 'Overschrijf Oudste'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Wanneer de contactenlijst vol is, wordt de oudste niet-favoriete contactpersoon vervangen.'; + + @override + String get discoveredContacts_Title => 'Ontdekte contacten'; + + @override + String get discoveredContacts_noMatching => 'Geen overeenkomende contacten'; + + @override + String get discoveredContacts_searchHint => 'Ontdekte contacten zoeken'; + + @override + String get discoveredContacts_contactAdded => 'Contact toegevoegd'; + + @override + String get discoveredContacts_addContact => 'Contact toevoegen'; + + @override + String get discoveredContacts_copyContact => 'Kopieer contact naar klembord'; + + @override + String get discoveredContacts_deleteContact => 'Contact verwijderen'; + + @override + String get discoveredContacts_deleteContactAll => + 'Verwijder alle ontdekte contacten'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Weet u zeker dat u alle ontdekte contacten wilt verwijderen?'; } diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index e033359..e8ee410 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -38,6 +38,9 @@ class AppLocalizationsPl extends AppLocalizations { @override String get common_delete => 'Usuń'; + @override + String get common_deleteAll => 'Usuń wszystko'; + @override String get common_close => 'Zamknąć'; @@ -242,6 +245,13 @@ class AppLocalizationsPl extends AppLocalizations { @override String get settings_longitude => 'Długość'; + @override + String get settings_contactSettings => 'Ustawienia kontaktowe'; + + @override + String get settings_contactSettingsSubtitle => + 'Ustawienia dotyczące sposobu dodawania kontaktów'; + @override String get settings_privacyMode => 'Tryb Prywatny'; @@ -3123,4 +3133,82 @@ class AppLocalizationsPl extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Ostatnio widziany'; + + @override + String get contactsSettings_title => 'Ustawienia kontaktów'; + + @override + String get contactsSettings_autoAddTitle => 'Automatyczne odnajdywanie'; + + @override + String get contactsSettings_otherTitle => + 'Inne ustawienia związane z kontaktami'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Automatycznie dodaj użytkowników'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Pozwól towarzyszowi automatycznie dodawać znalezione użytkowników.'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Automatyczne dodawanie powtarzalników'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Zezwól na automatyczne dodawanie odkrytych repeaterów przez towarzysza.'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Automatycznie dodaj serwery pokojowe'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Zezwól towarzyszowi na automatyczne dodawanie znalezionych serwerów pokojowych.'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Automatycznie dodaj czujniki'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Zezwól towarzyszowi na automatyczne dodawanie wykrytych czujników.'; + + @override + String get contactsSettings_overwriteOldestTitle => 'Nadpisz najstarszy'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Gdy lista kontaktów jest pełna, najstarszy nieulubiony kontakt zostanie zastąpiony.'; + + @override + String get discoveredContacts_Title => 'Odkryte Kontakty'; + + @override + String get discoveredContacts_noMatching => 'Brak pasujących kontaktów'; + + @override + String get discoveredContacts_searchHint => 'Wyszukaj odkryte kontakty'; + + @override + String get discoveredContacts_contactAdded => 'Kontakt dodany'; + + @override + String get discoveredContacts_addContact => 'Dodaj kontakt'; + + @override + String get discoveredContacts_copyContact => 'Kopiuj kontakt do schowka'; + + @override + String get discoveredContacts_deleteContact => 'Usuń kontakt'; + + @override + String get discoveredContacts_deleteContactAll => + 'Usuń wszystkie odkryte kontakty'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Czy na pewno chcesz usunąć wszystkie znalezione kontakty?'; } diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index dd19452..93e1ffb 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -38,6 +38,9 @@ class AppLocalizationsPt extends AppLocalizations { @override String get common_delete => 'Excluir'; + @override + String get common_deleteAll => 'Excluir Tudo'; + @override String get common_close => 'Fechar'; @@ -241,6 +244,13 @@ class AppLocalizationsPt extends AppLocalizations { @override String get settings_longitude => 'Longitude'; + @override + String get settings_contactSettings => 'Configurações de Contato'; + + @override + String get settings_contactSettingsSubtitle => + 'Configurações para como os contatos são adicionados'; + @override String get settings_privacyMode => 'Modo de Privacidade'; @@ -3118,4 +3128,84 @@ class AppLocalizationsPt extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Visto pela última vez'; + + @override + String get contactsSettings_title => 'Configurações de contatos'; + + @override + String get contactsSettings_autoAddTitle => 'Descoberta Automática'; + + @override + String get contactsSettings_otherTitle => + 'Outras configurações relacionadas a contatos'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Adicionar usuários automaticamente'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Permitir que o companheiro adicione automaticamente os usuários descobertos.'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Adicionar repetidores automaticamente'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Permitir que o companheiro adicione automaticamente os repetidores descobertos.'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Adicionar automaticamente servidores de sala'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Permitir que o companheiro adicione automaticamente os servidores de salas descobertos.'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Adicionar sensores automaticamente'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Permitir que o companheiro adicione automaticamente sensores descobertos.'; + + @override + String get contactsSettings_overwriteOldestTitle => + 'Sobrescrever o Mais Antigo'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Quando a lista de contatos estiver cheia, o contato mais antigo não favoritado será substituído.'; + + @override + String get discoveredContacts_Title => 'Contatos Descobertos'; + + @override + String get discoveredContacts_noMatching => 'Nenhum contato correspondente'; + + @override + String get discoveredContacts_searchHint => 'Pesquisar contatos descobertos'; + + @override + String get discoveredContacts_contactAdded => 'Contato adicionado'; + + @override + String get discoveredContacts_addContact => 'Adicionar Contato'; + + @override + String get discoveredContacts_copyContact => + 'Copiar Contato para a área de transferência'; + + @override + String get discoveredContacts_deleteContact => 'Excluir Contato'; + + @override + String get discoveredContacts_deleteContactAll => + 'Excluir Todos os Contatos Descobertos'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Tem certeza de que deseja excluir todos os contatos descobertos?'; } diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 5f5591d..1e59160 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -38,6 +38,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get common_delete => 'Удалить'; + @override + String get common_deleteAll => 'Удалить все'; + @override String get common_close => 'Закрыть'; @@ -239,6 +242,13 @@ class AppLocalizationsRu extends AppLocalizations { @override String get settings_longitude => 'Долгота'; + @override + String get settings_contactSettings => 'Настройки контактов'; + + @override + String get settings_contactSettingsSubtitle => + 'Настройки добавления контактов'; + @override String get settings_privacyMode => 'Режим конфиденциальности'; @@ -3130,4 +3140,84 @@ class AppLocalizationsRu extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Последний раз видели'; + + @override + String get contactsSettings_title => 'Настройки контактов'; + + @override + String get contactsSettings_autoAddTitle => 'Автоматическое обнаружение'; + + @override + String get contactsSettings_otherTitle => + 'Другие настройки, связанные с контактами'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Автоматически добавлять пользователей'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Разрешить компаньону автоматически добавлять обнаруженных пользователей'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Автоматически добавлять ретрансляторы'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Разрешить спутнику автоматически добавлять обнаруженные ретрансляторы'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Автоматически добавлять серверы комнат'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Разрешить компаньону автоматически добавлять обнаруженные сервера комнат.'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Автоматически добавлять датчики'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Разрешить компаньону автоматически добавлять обнаруженные датчики'; + + @override + String get contactsSettings_overwriteOldestTitle => + 'Перезаписать самое старое'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Когда список контактов заполнен, будет заменен самый старый контакт, который не находится в избранном.'; + + @override + String get discoveredContacts_Title => 'Обнаруженные контакты'; + + @override + String get discoveredContacts_noMatching => 'Нет совпадающих контактов'; + + @override + String get discoveredContacts_searchHint => 'Найденные контакты поиска'; + + @override + String get discoveredContacts_contactAdded => 'Контакт добавлен'; + + @override + String get discoveredContacts_addContact => 'Добавить контакт'; + + @override + String get discoveredContacts_copyContact => + 'Копировать контакт в буфер обмена'; + + @override + String get discoveredContacts_deleteContact => 'Удалить контакт'; + + @override + String get discoveredContacts_deleteContactAll => + 'Удалить Все Обнаруженные Контакты'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Вы уверены, что хотите удалить все обнаруженные контакты?'; } diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 82e4d06..6e68a97 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -38,6 +38,9 @@ class AppLocalizationsSk extends AppLocalizations { @override String get common_delete => 'Odstrániť'; + @override + String get common_deleteAll => 'Zmazať všetko'; + @override String get common_close => 'Zavrieť'; @@ -240,6 +243,13 @@ class AppLocalizationsSk extends AppLocalizations { @override String get settings_longitude => 'Dĺžka'; + @override + String get settings_contactSettings => 'Nastavenia kontaktov'; + + @override + String get settings_contactSettingsSubtitle => + 'Nastavenia pre pridávanie kontaktov.'; + @override String get settings_privacyMode => 'Režim ochrany súkromia'; @@ -3105,4 +3115,82 @@ class AppLocalizationsSk extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Naposledy videný'; + + @override + String get contactsSettings_title => 'Nastavenia kontaktov'; + + @override + String get contactsSettings_autoAddTitle => 'Automatické zisťovanie'; + + @override + String get contactsSettings_otherTitle => + 'Ďalšie nastavenia súvisiace s kontaktami'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Automaticky pridávať užívateľov'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Povoliť spoločníkovi automaticky pridávať objavených užívateľov.'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Automaticky pridávať opakovače'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Povoliť spoločníkovi automaticky pridávať objavené repeater.'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Automaticky pridávať server miestnosti'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Povoliť spoločníkovi automaticky pridať objavené serverové miestnosti.'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Automaticky pridávať senzory'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Povoliť spoločníkovi automaticky pridávať objavené senzory.'; + + @override + String get contactsSettings_overwriteOldestTitle => 'Prepísať najstaršie'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Keď je zoznam kontaktov plný, bude nahradený najstarší neoznačený kontakt.'; + + @override + String get discoveredContacts_Title => 'Objavené kontakty'; + + @override + String get discoveredContacts_noMatching => 'Žiadne zhodné kontakty'; + + @override + String get discoveredContacts_searchHint => 'Vyhľadať objavené kontakty'; + + @override + String get discoveredContacts_contactAdded => 'Kontakt bol pridaný'; + + @override + String get discoveredContacts_addContact => 'Pridať kontakt'; + + @override + String get discoveredContacts_copyContact => 'Kopírovať kontakt do schránky'; + + @override + String get discoveredContacts_deleteContact => 'Zmazať kontakt'; + + @override + String get discoveredContacts_deleteContactAll => + 'Zmazať všetky objavené kontakty'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Ste si istí, že chcete zmazať všetky objavené kontakty?'; } diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 9b1bfc9..9b08106 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -38,6 +38,9 @@ class AppLocalizationsSl extends AppLocalizations { @override String get common_delete => 'Izbrisati'; + @override + String get common_deleteAll => 'Izbriši vse'; + @override String get common_close => 'Zapri'; @@ -240,6 +243,13 @@ class AppLocalizationsSl extends AppLocalizations { @override String get settings_longitude => 'Dolžina'; + @override + String get settings_contactSettings => 'Nastavitve stika'; + + @override + String get settings_contactSettingsSubtitle => + 'Nastavitve za dodajanje stikov.'; + @override String get settings_privacyMode => 'Zasebnost'; @@ -3110,4 +3120,81 @@ class AppLocalizationsSl extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Zadnjič videno'; + + @override + String get contactsSettings_title => 'Nastavitve stikov'; + + @override + String get contactsSettings_autoAddTitle => 'Avtomatsko odkrivanje'; + + @override + String get contactsSettings_otherTitle => 'Druge nastavitve v zvezi s stiki'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Avtomatsko dodaj uporabnike'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Dovoli spremljevalcu, da samodejno doda odkrite uporabnike.'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Avtomatsko dodaj ponovitelje'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Dovoli spremljevalcu, da samodejno doda odkrite ponovitelje.'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Avtomatsko dodaj strežnike sob'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Dovoli spremljevalcu, da samodejno doda odkrite strežnike sob.'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Avtomatsko dodaj senzorje'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Dovoli spremljevalcu, da samodejno doda odkrite senzorje.'; + + @override + String get contactsSettings_overwriteOldestTitle => 'Prepiši najstarejše'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Ko je seznam stikov poln, bo najstarejši nestarševski stik zamenjan.'; + + @override + String get discoveredContacts_Title => 'Odkriti stiki'; + + @override + String get discoveredContacts_noMatching => 'Ni ujemajočih stikov'; + + @override + String get discoveredContacts_searchHint => 'Najdeni stiki po iskanju'; + + @override + String get discoveredContacts_contactAdded => 'Kontakt dodan'; + + @override + String get discoveredContacts_addContact => 'Dodaj stik'; + + @override + String get discoveredContacts_copyContact => 'Kopiraj stik v odložišče'; + + @override + String get discoveredContacts_deleteContact => 'Izbriši stik'; + + @override + String get discoveredContacts_deleteContactAll => + 'Izbriši vse odkrite kontakte'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Ste prepričani, da želite izbrisati vse odkrite kontakte?'; } diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index ddfcf41..2a41947 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -38,6 +38,9 @@ class AppLocalizationsSv extends AppLocalizations { @override String get common_delete => 'Radera'; + @override + String get common_deleteAll => 'Ta bort alla'; + @override String get common_close => 'Stänga'; @@ -239,6 +242,13 @@ class AppLocalizationsSv extends AppLocalizations { @override String get settings_longitude => 'Längdgrad'; + @override + String get settings_contactSettings => 'Kontaktinställningar'; + + @override + String get settings_contactSettingsSubtitle => + 'Inställningar för hur kontakter läggs till.'; + @override String get settings_privacyMode => 'Privatläge'; @@ -3088,4 +3098,82 @@ class AppLocalizationsSv extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Senast sedd'; + + @override + String get contactsSettings_title => 'Kontaktinställningar'; + + @override + String get contactsSettings_autoAddTitle => 'Automatisk upptäckt'; + + @override + String get contactsSettings_otherTitle => + 'Andra inställningar relaterade till kontakt'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Lägg till användare automatiskt'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Tillåt kompanjonen att automatiskt lägga till upptäckta användare'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Lägg till upprepande enheter automatiskt'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Tillåt kompanjonen att automatiskt lägga till upptäckta repeater.'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Lägg automatiskt till rumsservrar'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Tillåt kompanjonen att automatiskt lägga till upptäckta rumsservrar.'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Lägg till sensorer automatiskt'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Tillåt kompanjonen att automatiskt lägga till upptäckta sensorer.'; + + @override + String get contactsSettings_overwriteOldestTitle => 'Skriv över äldst'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'När kontaktlistan är full ersätts den äldsta icke-favoriterade kontakten.'; + + @override + String get discoveredContacts_Title => 'Upptäckta kontakter'; + + @override + String get discoveredContacts_noMatching => 'Inga matchande kontakter'; + + @override + String get discoveredContacts_searchHint => 'Sök uppfunna kontakter'; + + @override + String get discoveredContacts_contactAdded => 'Kontakt tillagd'; + + @override + String get discoveredContacts_addContact => 'Lägg till kontakt'; + + @override + String get discoveredContacts_copyContact => 'Kopiera kontakt till urklipp'; + + @override + String get discoveredContacts_deleteContact => 'Ta bort kontakt'; + + @override + String get discoveredContacts_deleteContactAll => + 'Ta bort alla upptäckta kontakter'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Är du säker på att du vill ta bort alla upptäckta kontakter?'; } diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index b44a7cb..87d2318 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -38,6 +38,9 @@ class AppLocalizationsUk extends AppLocalizations { @override String get common_delete => 'Видалити'; + @override + String get common_deleteAll => 'Видалити все'; + @override String get common_close => 'Закрити'; @@ -239,6 +242,13 @@ class AppLocalizationsUk extends AppLocalizations { @override String get settings_longitude => 'Довгота'; + @override + String get settings_contactSettings => 'Налаштування контактів'; + + @override + String get settings_contactSettingsSubtitle => + 'Налаштування для додавання контактів'; + @override String get settings_privacyMode => 'Режим приватності'; @@ -3137,4 +3147,84 @@ class AppLocalizationsUk extends AppLocalizations { @override String get snrIndicator_lastSeen => 'Останній раз бачили'; + + @override + String get contactsSettings_title => 'Налаштування контактів'; + + @override + String get contactsSettings_autoAddTitle => 'Автоматичне виявлення'; + + @override + String get contactsSettings_otherTitle => + 'Інші налаштування, пов\'язані з контактами'; + + @override + String get contactsSettings_autoAddUsersTitle => + 'Автоматично додавати користувачів'; + + @override + String get contactsSettings_autoAddUsersSubtitle => + 'Дозволити супутникові автоматично додавати виявлених користувачів'; + + @override + String get contactsSettings_autoAddRepeatersTitle => + 'Автоматично додавати повторювачі'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => + 'Дозволити супутнику автоматично додавати виявлені ретранслятори'; + + @override + String get contactsSettings_autoAddRoomServersTitle => + 'Автоматично додавати сервери кімнат'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => + 'Дозволити супровіднику автоматично додавати виявлені сервери кімнат.'; + + @override + String get contactsSettings_autoAddSensorsTitle => + 'Автоматично додавати датчики'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => + 'Дозволити супровіднику автоматично додавати виявлені сенсори'; + + @override + String get contactsSettings_overwriteOldestTitle => 'Перезаписати найстаріше'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + 'Коли список контактів заповнений, найстарший контакт без позначки улюбленого буде замінений.'; + + @override + String get discoveredContacts_Title => 'Виявлені контакти'; + + @override + String get discoveredContacts_noMatching => + 'Відповідних контактів не знайдено'; + + @override + String get discoveredContacts_searchHint => 'Знайти виявлені контакти'; + + @override + String get discoveredContacts_contactAdded => 'Контакт додано'; + + @override + String get discoveredContacts_addContact => 'Додати контакт'; + + @override + String get discoveredContacts_copyContact => + 'Копіювати контакт у буфер обміну'; + + @override + String get discoveredContacts_deleteContact => 'Видалити контакт'; + + @override + String get discoveredContacts_deleteContactAll => + 'Видалити всі виявлені контакти'; + + @override + String get discoveredContacts_deleteContactAllContent => + 'Ви впевнені, що хочете видалити всі виявлені контакти?'; } diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index b3d85ed..eb79671 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -38,6 +38,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get common_delete => '删除'; + @override + String get common_deleteAll => '删除全部'; + @override String get common_close => '关闭'; @@ -233,6 +236,12 @@ class AppLocalizationsZh extends AppLocalizations { @override String get settings_longitude => '经度'; + @override + String get settings_contactSettings => '联系人设置'; + + @override + String get settings_contactSettingsSubtitle => '添加联系人的设置'; + @override String get settings_privacyMode => '隐私模式'; @@ -2897,4 +2906,71 @@ class AppLocalizationsZh extends AppLocalizations { @override String get snrIndicator_lastSeen => '最近访问'; + + @override + String get contactsSettings_title => '联系人设置'; + + @override + String get contactsSettings_autoAddTitle => '自动发现'; + + @override + String get contactsSettings_otherTitle => '其他联系人相关设置'; + + @override + String get contactsSettings_autoAddUsersTitle => '自动添加用户'; + + @override + String get contactsSettings_autoAddUsersSubtitle => '允许伴侣自动添加发现的用户'; + + @override + String get contactsSettings_autoAddRepeatersTitle => '自动添加重复器'; + + @override + String get contactsSettings_autoAddRepeatersSubtitle => '允许伴侣自动添加发现的重复器'; + + @override + String get contactsSettings_autoAddRoomServersTitle => '自动添加房间服务器'; + + @override + String get contactsSettings_autoAddRoomServersSubtitle => '允许伴侣自动添加发现的房间服务器'; + + @override + String get contactsSettings_autoAddSensorsTitle => '自动添加传感器'; + + @override + String get contactsSettings_autoAddSensorsSubtitle => '允许伴侣自动添加发现的传感器'; + + @override + String get contactsSettings_overwriteOldestTitle => '覆盖最旧的'; + + @override + String get contactsSettings_overwriteOldestSubtitle => + '当联系人列表已满时,将替换最老的非收藏联系人。'; + + @override + String get discoveredContacts_Title => '已发现的联系人'; + + @override + String get discoveredContacts_noMatching => '没有匹配的联系人'; + + @override + String get discoveredContacts_searchHint => '搜索已发现的联系人'; + + @override + String get discoveredContacts_contactAdded => '联系人已添加'; + + @override + String get discoveredContacts_addContact => '添加联系人'; + + @override + String get discoveredContacts_copyContact => '复制联系人到剪贴板'; + + @override + String get discoveredContacts_deleteContact => '删除联系人'; + + @override + String get discoveredContacts_deleteContactAll => '删除所有发现的联系人'; + + @override + String get discoveredContacts_deleteContactAllContent => '您确定要删除所有发现的联系人吗?'; } diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index 35cb375..ce533e7 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1801,5 +1801,30 @@ "contacts_searchContactsNoNumber": "Zoek contacten...", "contacts_searchUsers": "Zoek {number}{str} gebruikers...", "contacts_searchFavorites": "Zoek {number}{str} favorieten...", - "contacts_searchRoomServers": "Zoek {number}{str} Room servers..." + "contacts_searchRoomServers": "Zoek {number}{str} Room servers...", + "contactsSettings_autoAddUsersTitle": "Gebruikers automatisch toevoegen", + "contactsSettings_title": "Instellingen voor contacten", + "settings_contactSettings": "Contactinstellingen", + "contactsSettings_otherTitle": "Andere instellingen voor contactgerelateerde zaken", + "contactsSettings_autoAddRepeatersSubtitle": "Sta toe dat de companion automatisch ontdekte repeaters toevoegt", + "contactsSettings_autoAddRoomServersTitle": "Automatisch kamerservers toevoegen", + "contactsSettings_autoAddRoomServersSubtitle": "Sta toe dat de companion automatisch ontdekte kamer servers toevoegt.", + "contactsSettings_autoAddSensorsTitle": "Automatisch sensoren toevoegen", + "settings_contactSettingsSubtitle": "Instellingen voor het toevoegen van contacten", + "contactsSettings_autoAddTitle": "Automatische detectie", + "contactsSettings_autoAddSensorsSubtitle": "Sta toe dat de companion automatisch ontdekte sensoren toevoegt", + "contactsSettings_autoAddUsersSubtitle": "Sta toe dat de companion automatisch ontdekte gebruikers toevoegt", + "contactsSettings_autoAddRepeatersTitle": "Automatisch herhalingstoestellen toevoegen", + "contactsSettings_overwriteOldestTitle": "Overschrijf Oudste", + "discoveredContacts_noMatching": "Geen overeenkomende contacten", + "discoveredContacts_addContact": "Contact toevoegen", + "discoveredContacts_copyContact": "Kopieer contact naar klembord", + "discoveredContacts_deleteContact": "Contact verwijderen", + "discoveredContacts_Title": "Ontdekte contacten", + "discoveredContacts_contactAdded": "Contact toegevoegd", + "discoveredContacts_searchHint": "Ontdekte contacten zoeken", + "contactsSettings_overwriteOldestSubtitle": "Wanneer de contactenlijst vol is, wordt de oudste niet-favoriete contactpersoon vervangen.", + "common_deleteAll": "Alles verwijderen", + "discoveredContacts_deleteContactAll": "Verwijder alle ontdekte contacten", + "discoveredContacts_deleteContactAllContent": "Weet u zeker dat u alle ontdekte contacten wilt verwijderen?" } diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 23c4cbc..509be40 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1801,5 +1801,30 @@ "contacts_searchFavorites": "Wyszukaj {number}{str} ulubione...", "contacts_searchRoomServers": "Wyszukaj {number}{str} serwerów Room...", "contacts_searchUsers": "Wyszukaj {number}{str} Użytkowników...", - "contacts_searchRepeaters": "Wyszukaj {number}{str} powtórników..." + "contacts_searchRepeaters": "Wyszukaj {number}{str} powtórników...", + "contactsSettings_title": "Ustawienia kontaktów", + "settings_contactSettingsSubtitle": "Ustawienia dotyczące sposobu dodawania kontaktów", + "contactsSettings_autoAddUsersSubtitle": "Pozwól towarzyszowi automatycznie dodawać znalezione użytkowników.", + "contactsSettings_autoAddRepeatersTitle": "Automatyczne dodawanie powtarzalników", + "contactsSettings_autoAddRepeatersSubtitle": "Zezwól na automatyczne dodawanie odkrytych repeaterów przez towarzysza.", + "contactsSettings_autoAddRoomServersTitle": "Automatycznie dodaj serwery pokojowe", + "contactsSettings_autoAddUsersTitle": "Automatycznie dodaj użytkowników", + "settings_contactSettings": "Ustawienia kontaktowe", + "contactsSettings_otherTitle": "Inne ustawienia związane z kontaktami", + "contactsSettings_autoAddTitle": "Automatyczne odnajdywanie", + "contactsSettings_autoAddRoomServersSubtitle": "Zezwól towarzyszowi na automatyczne dodawanie znalezionych serwerów pokojowych.", + "contactsSettings_autoAddSensorsTitle": "Automatycznie dodaj czujniki", + "discoveredContacts_searchHint": "Wyszukaj odkryte kontakty", + "discoveredContacts_contactAdded": "Kontakt dodany", + "discoveredContacts_addContact": "Dodaj kontakt", + "discoveredContacts_copyContact": "Kopiuj kontakt do schowka", + "contactsSettings_overwriteOldestTitle": "Nadpisz najstarszy", + "discoveredContacts_Title": "Odkryte Kontakty", + "contactsSettings_autoAddSensorsSubtitle": "Zezwól towarzyszowi na automatyczne dodawanie wykrytych czujników.", + "discoveredContacts_noMatching": "Brak pasujących kontaktów", + "discoveredContacts_deleteContact": "Usuń kontakt", + "contactsSettings_overwriteOldestSubtitle": "Gdy lista kontaktów jest pełna, najstarszy nieulubiony kontakt zostanie zastąpiony.", + "common_deleteAll": "Usuń wszystko", + "discoveredContacts_deleteContactAllContent": "Czy na pewno chcesz usunąć wszystkie znalezione kontakty?", + "discoveredContacts_deleteContactAll": "Usuń wszystkie odkryte kontakty" } diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 05792c6..8989d29 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1801,5 +1801,30 @@ "contacts_searchUsers": "Pesquisar {number}{str} Usuários...", "contacts_searchContactsNoNumber": "Pesquisar Contatos...", "contacts_unread": "Não lido", - "contacts_searchRoomServers": "Pesquisar {number}{str} servidores de sala..." + "contacts_searchRoomServers": "Pesquisar {number}{str} servidores de sala...", + "settings_contactSettings": "Configurações de Contato", + "contactsSettings_otherTitle": "Outras configurações relacionadas a contatos", + "contactsSettings_title": "Configurações de contatos", + "contactsSettings_autoAddTitle": "Descoberta Automática", + "settings_contactSettingsSubtitle": "Configurações para como os contatos são adicionados", + "contactsSettings_autoAddUsersTitle": "Adicionar usuários automaticamente", + "contactsSettings_autoAddRepeatersSubtitle": "Permitir que o companheiro adicione automaticamente os repetidores descobertos.", + "contactsSettings_autoAddRoomServersTitle": "Adicionar automaticamente servidores de sala", + "contactsSettings_overwriteOldestTitle": "Sobrescrever o Mais Antigo", + "contactsSettings_autoAddSensorsTitle": "Adicionar sensores automaticamente", + "discoveredContacts_Title": "Contatos Descobertos", + "contactsSettings_autoAddUsersSubtitle": "Permitir que o companheiro adicione automaticamente os usuários descobertos.", + "contactsSettings_autoAddRepeatersTitle": "Adicionar repetidores automaticamente", + "discoveredContacts_noMatching": "Nenhum contato correspondente", + "contactsSettings_autoAddRoomServersSubtitle": "Permitir que o companheiro adicione automaticamente os servidores de salas descobertos.", + "discoveredContacts_searchHint": "Pesquisar contatos descobertos", + "contactsSettings_autoAddSensorsSubtitle": "Permitir que o companheiro adicione automaticamente sensores descobertos.", + "discoveredContacts_copyContact": "Copiar Contato para a área de transferência", + "discoveredContacts_deleteContact": "Excluir Contato", + "discoveredContacts_contactAdded": "Contato adicionado", + "discoveredContacts_addContact": "Adicionar Contato", + "contactsSettings_overwriteOldestSubtitle": "Quando a lista de contatos estiver cheia, o contato mais antigo não favoritado será substituído.", + "common_deleteAll": "Excluir Tudo", + "discoveredContacts_deleteContactAll": "Excluir Todos os Contatos Descobertos", + "discoveredContacts_deleteContactAllContent": "Tem certeza de que deseja excluir todos os contatos descobertos?" } diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index 9460f44..42b440f 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -1041,5 +1041,30 @@ "contacts_unread": "Непрочитанное", "contacts_searchRoomServers": "Поиск {number}{str} серверов комнат...", "contacts_searchFavorites": "Поиск {number}{str} избранного...", - "contacts_searchUsers": "Поиск {number}{str} пользователей..." + "contacts_searchUsers": "Поиск {number}{str} пользователей...", + "settings_contactSettings": "Настройки контактов", + "settings_contactSettingsSubtitle": "Настройки добавления контактов", + "contactsSettings_autoAddTitle": "Автоматическое обнаружение", + "contactsSettings_title": "Настройки контактов", + "contactsSettings_otherTitle": "Другие настройки, связанные с контактами", + "contactsSettings_autoAddUsersSubtitle": "Разрешить компаньону автоматически добавлять обнаруженных пользователей", + "contactsSettings_autoAddRoomServersTitle": "Автоматически добавлять серверы комнат", + "contactsSettings_autoAddSensorsTitle": "Автоматически добавлять датчики", + "contactsSettings_autoAddSensorsSubtitle": "Разрешить компаньону автоматически добавлять обнаруженные датчики", + "contactsSettings_autoAddUsersTitle": "Автоматически добавлять пользователей", + "contactsSettings_overwriteOldestTitle": "Перезаписать самое старое", + "contactsSettings_autoAddRepeatersTitle": "Автоматически добавлять ретрансляторы", + "contactsSettings_autoAddRepeatersSubtitle": "Разрешить спутнику автоматически добавлять обнаруженные ретрансляторы", + "contactsSettings_autoAddRoomServersSubtitle": "Разрешить компаньону автоматически добавлять обнаруженные сервера комнат.", + "discoveredContacts_noMatching": "Нет совпадающих контактов", + "discoveredContacts_searchHint": "Найденные контакты поиска", + "discoveredContacts_contactAdded": "Контакт добавлен", + "discoveredContacts_copyContact": "Копировать контакт в буфер обмена", + "discoveredContacts_addContact": "Добавить контакт", + "discoveredContacts_Title": "Обнаруженные контакты", + "discoveredContacts_deleteContact": "Удалить контакт", + "contactsSettings_overwriteOldestSubtitle": "Когда список контактов заполнен, будет заменен самый старый контакт, который не находится в избранном.", + "common_deleteAll": "Удалить все", + "discoveredContacts_deleteContactAllContent": "Вы уверены, что хотите удалить все обнаруженные контакты?", + "discoveredContacts_deleteContactAll": "Удалить Все Обнаруженные Контакты" } diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index 5bc00c6..7fea7e3 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -1801,5 +1801,30 @@ "contacts_searchRepeaters": "Hľadať {number}{str} opakovače...", "contacts_searchUsers": "Hľadať {number}{str} používateľov...", "contacts_searchContactsNoNumber": "Hľadať kontakty...", - "contacts_unread": "Neprečítané" + "contacts_unread": "Neprečítané", + "settings_contactSettingsSubtitle": "Nastavenia pre pridávanie kontaktov.", + "contactsSettings_autoAddUsersTitle": "Automaticky pridávať užívateľov", + "contactsSettings_autoAddUsersSubtitle": "Povoliť spoločníkovi automaticky pridávať objavených užívateľov.", + "contactsSettings_autoAddRepeatersTitle": "Automaticky pridávať opakovače", + "contactsSettings_autoAddRoomServersTitle": "Automaticky pridávať server miestnosti", + "contactsSettings_autoAddRoomServersSubtitle": "Povoliť spoločníkovi automaticky pridať objavené serverové miestnosti.", + "contactsSettings_autoAddTitle": "Automatické zisťovanie", + "contactsSettings_title": "Nastavenia kontaktov", + "contactsSettings_otherTitle": "Ďalšie nastavenia súvisiace s kontaktami", + "settings_contactSettings": "Nastavenia kontaktov", + "contactsSettings_autoAddSensorsTitle": "Automaticky pridávať senzory", + "discoveredContacts_noMatching": "Žiadne zhodné kontakty", + "discoveredContacts_searchHint": "Vyhľadať objavené kontakty", + "contactsSettings_autoAddRepeatersSubtitle": "Povoliť spoločníkovi automaticky pridávať objavené repeater.", + "discoveredContacts_contactAdded": "Kontakt bol pridaný", + "discoveredContacts_copyContact": "Kopírovať kontakt do schránky", + "discoveredContacts_deleteContact": "Zmazať kontakt", + "contactsSettings_autoAddSensorsSubtitle": "Povoliť spoločníkovi automaticky pridávať objavené senzory.", + "discoveredContacts_Title": "Objavené kontakty", + "contactsSettings_overwriteOldestTitle": "Prepísať najstaršie", + "discoveredContacts_addContact": "Pridať kontakt", + "contactsSettings_overwriteOldestSubtitle": "Keď je zoznam kontaktov plný, bude nahradený najstarší neoznačený kontakt.", + "discoveredContacts_deleteContactAll": "Zmazať všetky objavené kontakty", + "common_deleteAll": "Zmazať všetko", + "discoveredContacts_deleteContactAllContent": "Ste si istí, že chcete zmazať všetky objavené kontakty?" } diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index 226a715..8dadec8 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1801,5 +1801,30 @@ "contacts_searchRoomServers": "Išči {number}{str} strežnikov sob...", "contacts_searchContactsNoNumber": "Iskanje stikov...", "contacts_searchRepeaters": "Išči {number}{str} ponavljalnike...", - "contacts_searchUsers": "Išči {number}{str} uporabnikov..." + "contacts_searchUsers": "Išči {number}{str} uporabnikov...", + "settings_contactSettings": "Nastavitve stika", + "contactsSettings_autoAddTitle": "Avtomatsko odkrivanje", + "contactsSettings_autoAddUsersTitle": "Avtomatsko dodaj uporabnike", + "contactsSettings_autoAddRepeatersTitle": "Avtomatsko dodaj ponovitelje", + "contactsSettings_autoAddRepeatersSubtitle": "Dovoli spremljevalcu, da samodejno doda odkrite ponovitelje.", + "contactsSettings_autoAddRoomServersTitle": "Avtomatsko dodaj strežnike sob", + "contactsSettings_autoAddRoomServersSubtitle": "Dovoli spremljevalcu, da samodejno doda odkrite strežnike sob.", + "contactsSettings_otherTitle": "Druge nastavitve v zvezi s stiki", + "settings_contactSettingsSubtitle": "Nastavitve za dodajanje stikov.", + "contactsSettings_title": "Nastavitve stikov", + "contactsSettings_autoAddSensorsTitle": "Avtomatsko dodaj senzorje", + "contactsSettings_autoAddUsersSubtitle": "Dovoli spremljevalcu, da samodejno doda odkrite uporabnike.", + "discoveredContacts_noMatching": "Ni ujemajočih stikov", + "contactsSettings_autoAddSensorsSubtitle": "Dovoli spremljevalcu, da samodejno doda odkrite senzorje.", + "discoveredContacts_addContact": "Dodaj stik", + "discoveredContacts_contactAdded": "Kontakt dodan", + "discoveredContacts_copyContact": "Kopiraj stik v odložišče", + "contactsSettings_overwriteOldestTitle": "Prepiši najstarejše", + "discoveredContacts_Title": "Odkriti stiki", + "discoveredContacts_searchHint": "Najdeni stiki po iskanju", + "discoveredContacts_deleteContact": "Izbriši stik", + "contactsSettings_overwriteOldestSubtitle": "Ko je seznam stikov poln, bo najstarejši nestarševski stik zamenjan.", + "common_deleteAll": "Izbriši vse", + "discoveredContacts_deleteContactAllContent": "Ste prepričani, da želite izbrisati vse odkrite kontakte?", + "discoveredContacts_deleteContactAll": "Izbriši vse odkrite kontakte" } diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index bfccfff..2467015 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1801,5 +1801,30 @@ "contacts_searchRepeaters": "Sök {number}{str} upprepningsenheter...", "contacts_searchFavorites": "Sök {number}{str} Favoriter...", "contacts_searchUsers": "Sök {number}{str} användare...", - "contacts_searchRoomServers": "Sök {number}{str} Room-servrar..." + "contacts_searchRoomServers": "Sök {number}{str} Room-servrar...", + "settings_contactSettingsSubtitle": "Inställningar för hur kontakter läggs till.", + "settings_contactSettings": "Kontaktinställningar", + "contactsSettings_autoAddTitle": "Automatisk upptäckt", + "contactsSettings_otherTitle": "Andra inställningar relaterade till kontakt", + "contactsSettings_autoAddUsersSubtitle": "Tillåt kompanjonen att automatiskt lägga till upptäckta användare", + "contactsSettings_autoAddRepeatersTitle": "Lägg till upprepande enheter automatiskt", + "contactsSettings_autoAddRoomServersSubtitle": "Tillåt kompanjonen att automatiskt lägga till upptäckta rumsservrar.", + "contactsSettings_autoAddSensorsTitle": "Lägg till sensorer automatiskt", + "contactsSettings_autoAddUsersTitle": "Lägg till användare automatiskt", + "contactsSettings_title": "Kontaktinställningar", + "contactsSettings_autoAddSensorsSubtitle": "Tillåt kompanjonen att automatiskt lägga till upptäckta sensorer.", + "contactsSettings_overwriteOldestTitle": "Skriv över äldst", + "contactsSettings_autoAddRepeatersSubtitle": "Tillåt kompanjonen att automatiskt lägga till upptäckta repeater.", + "contactsSettings_autoAddRoomServersTitle": "Lägg automatiskt till rumsservrar", + "discoveredContacts_noMatching": "Inga matchande kontakter", + "discoveredContacts_searchHint": "Sök uppfunna kontakter", + "discoveredContacts_deleteContact": "Ta bort kontakt", + "discoveredContacts_Title": "Upptäckta kontakter", + "discoveredContacts_contactAdded": "Kontakt tillagd", + "discoveredContacts_addContact": "Lägg till kontakt", + "discoveredContacts_copyContact": "Kopiera kontakt till urklipp", + "contactsSettings_overwriteOldestSubtitle": "När kontaktlistan är full ersätts den äldsta icke-favoriterade kontakten.", + "common_deleteAll": "Ta bort alla", + "discoveredContacts_deleteContactAllContent": "Är du säker på att du vill ta bort alla upptäckta kontakter?", + "discoveredContacts_deleteContactAll": "Ta bort alla upptäckta kontakter" } diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 6063bc8..dc48f09 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -1801,5 +1801,30 @@ "contacts_searchFavorites": "Пошук {number}{str} улюблених...", "contacts_searchContactsNoNumber": "Пошук контактів...", "contacts_searchRepeaters": "Пошук {number}{str} ретрансляторів...", - "contacts_unread": "Непрочитане" + "contacts_unread": "Непрочитане", + "settings_contactSettingsSubtitle": "Налаштування для додавання контактів", + "settings_contactSettings": "Налаштування контактів", + "contactsSettings_autoAddUsersSubtitle": "Дозволити супутникові автоматично додавати виявлених користувачів", + "contactsSettings_autoAddRepeatersTitle": "Автоматично додавати повторювачі", + "contactsSettings_autoAddRepeatersSubtitle": "Дозволити супутнику автоматично додавати виявлені ретранслятори", + "contactsSettings_autoAddRoomServersTitle": "Автоматично додавати сервери кімнат", + "contactsSettings_otherTitle": "Інші налаштування, пов'язані з контактами", + "contactsSettings_autoAddTitle": "Автоматичне виявлення", + "contactsSettings_autoAddUsersTitle": "Автоматично додавати користувачів", + "contactsSettings_title": "Налаштування контактів", + "contactsSettings_autoAddRoomServersSubtitle": "Дозволити супровіднику автоматично додавати виявлені сервери кімнат.", + "contactsSettings_autoAddSensorsTitle": "Автоматично додавати датчики", + "discoveredContacts_searchHint": "Знайти виявлені контакти", + "discoveredContacts_contactAdded": "Контакт додано", + "contactsSettings_autoAddSensorsSubtitle": "Дозволити супровіднику автоматично додавати виявлені сенсори", + "contactsSettings_overwriteOldestTitle": "Перезаписати найстаріше", + "discoveredContacts_Title": "Виявлені контакти", + "discoveredContacts_noMatching": "Відповідних контактів не знайдено", + "discoveredContacts_deleteContact": "Видалити контакт", + "discoveredContacts_copyContact": "Копіювати контакт у буфер обміну", + "discoveredContacts_addContact": "Додати контакт", + "contactsSettings_overwriteOldestSubtitle": "Коли список контактів заповнений, найстарший контакт без позначки улюбленого буде замінений.", + "common_deleteAll": "Видалити все", + "discoveredContacts_deleteContactAll": "Видалити всі виявлені контакти", + "discoveredContacts_deleteContactAllContent": "Ви впевнені, що хочете видалити всі виявлені контакти?" } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index db4953e..ad58f4c 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1806,5 +1806,30 @@ "contacts_searchRepeaters": "搜索 {number}{str} 重复器...", "contacts_searchContactsNoNumber": "搜索联系人...", "contacts_searchRoomServers": "搜索 {number}{str} 房间服务器...", - "contacts_searchFavorites": "搜索 {number}{str} 收藏..." + "contacts_searchFavorites": "搜索 {number}{str} 收藏...", + "settings_contactSettings": "联系人设置", + "contactsSettings_title": "联系人设置", + "contactsSettings_autoAddUsersTitle": "自动添加用户", + "contactsSettings_otherTitle": "其他联系人相关设置", + "contactsSettings_autoAddUsersSubtitle": "允许伴侣自动添加发现的用户", + "contactsSettings_autoAddRepeatersSubtitle": "允许伴侣自动添加发现的重复器", + "contactsSettings_autoAddSensorsTitle": "自动添加传感器", + "contactsSettings_autoAddRoomServersSubtitle": "允许伴侣自动添加发现的房间服务器", + "contactsSettings_autoAddRepeatersTitle": "自动添加重复器", + "contactsSettings_autoAddTitle": "自动发现", + "settings_contactSettingsSubtitle": "添加联系人的设置", + "contactsSettings_overwriteOldestTitle": "覆盖最旧的", + "contactsSettings_autoAddSensorsSubtitle": "允许伴侣自动添加发现的传感器", + "discoveredContacts_searchHint": "搜索已发现的联系人", + "contactsSettings_autoAddRoomServersTitle": "自动添加房间服务器", + "discoveredContacts_contactAdded": "联系人已添加", + "discoveredContacts_deleteContact": "删除联系人", + "discoveredContacts_addContact": "添加联系人", + "discoveredContacts_noMatching": "没有匹配的联系人", + "discoveredContacts_Title": "已发现的联系人", + "discoveredContacts_copyContact": "复制联系人到剪贴板", + "contactsSettings_overwriteOldestSubtitle": "当联系人列表已满时,将替换最老的非收藏联系人。", + "common_deleteAll": "删除全部", + "discoveredContacts_deleteContactAllContent": "您确定要删除所有发现的联系人吗?", + "discoveredContacts_deleteContactAll": "删除所有发现的联系人" } diff --git a/lib/models/contact.dart b/lib/models/contact.dart index 5e532e6..7d8e011 100644 --- a/lib/models/contact.dart +++ b/lib/models/contact.dart @@ -183,7 +183,7 @@ class Contact { ) : Uint8List(0); final name = readCString(data, contactNameOffset, maxNameSize); - final lastmod = readUint32LE(data, contactLastmodOffset); + final lastmod = readUint32LE(data, contactLastModOffset); double? lat, lon; final latRaw = readInt32LE(data, contactLatOffset); diff --git a/lib/models/discovery_contact.dart b/lib/models/discovery_contact.dart new file mode 100644 index 0000000..f6c6a52 --- /dev/null +++ b/lib/models/discovery_contact.dart @@ -0,0 +1,105 @@ +import 'dart:typed_data'; +import '../connector/meshcore_protocol.dart'; + +class DiscoveryContact { + final Uint8List rawPacket; + final Uint8List publicKey; + final String name; + final int type; + final int pathLength; // -1 = flood, 0+ = direct hops (from device) + final Uint8List path; // Path bytes from device + final double? latitude; + final double? longitude; + final DateTime lastSeen; + + DiscoveryContact({ + required this.rawPacket, + required this.publicKey, + required this.name, + required this.type, + required this.pathLength, + required this.path, + this.latitude, + this.longitude, + required this.lastSeen, + }); + + String get publicKeyHex => pubKeyToHex(publicKey); + + String get typeLabel { + switch (type) { + case advTypeChat: + return 'Chat'; + case advTypeRepeater: + return 'Repeater'; + case advTypeRoom: + return 'Room'; + case advTypeSensor: + return 'Sensor'; + default: + return 'Unknown'; + } + } + + String get pathLabel { + if (pathLength < 0) return 'Flood'; + if (pathLength == 0) return 'Direct'; + return '$pathLength hops'; + } + + bool get hasLocation => latitude != null && longitude != null; + + DiscoveryContact copyWith({ + Uint8List? rawPacket, + Uint8List? publicKey, + String? name, + int? type, + int? pathLength, + Uint8List? path, + double? latitude, + double? longitude, + DateTime? lastSeen, + }) { + return DiscoveryContact( + rawPacket: rawPacket ?? this.rawPacket, + publicKey: publicKey ?? this.publicKey, + name: name ?? this.name, + type: type ?? this.type, + pathLength: pathLength ?? this.pathLength, + path: path ?? this.path, + latitude: latitude ?? this.latitude, + longitude: longitude ?? this.longitude, + lastSeen: lastSeen ?? this.lastSeen, + ); + } + + String get pathIdList { + final pathBytes = path; + if (pathBytes.isEmpty) return ''; + final parts = []; + final groupSize = pathHashSize; + for (int i = 0; i < pathBytes.length; i += groupSize) { + final end = (i + groupSize) <= pathBytes.length + ? (i + groupSize) + : pathBytes.length; + final chunk = pathBytes.sublist(i, end); + parts.add( + chunk + .map((b) => b.toRadixString(16).padLeft(2, '0').toUpperCase()) + .join(), + ); + } + return parts.join(','); + } + + String get shortPubKeyHex { + return "<${publicKeyHex.substring(0, 8)}...${publicKeyHex.substring(publicKeyHex.length - 8)}>"; + } + + @override + bool operator ==(Object other) => + other is DiscoveryContact && publicKeyHex == other.publicKeyHex; + + @override + int get hashCode => publicKeyHex.hashCode; +} diff --git a/lib/screens/contacts_screen.dart b/lib/screens/contacts_screen.dart index eeecfb9..47bac9c 100644 --- a/lib/screens/contacts_screen.dart +++ b/lib/screens/contacts_screen.dart @@ -26,6 +26,7 @@ import '../widgets/room_login_dialog.dart'; import '../widgets/unread_badge.dart'; import 'channels_screen.dart'; import 'chat_screen.dart'; +import 'discovery_screen.dart'; import 'map_screen.dart'; import 'repeater_hub_screen.dart'; import 'settings_screen.dart'; @@ -218,9 +219,10 @@ class _ContactsScreenState extends State } final hexString = text.substring('meshcore://'.length); try { - final importContactFrame = buildImportContactFrame(hexString); + final bytes = hex2Uint8List(hexString); + final importContactFrame = buildImportContactFrame(bytes); _pendingOperations.add(ContactOperationType.import); - await connector.sendFrame(importContactFrame, expectsGenericAck: true); + connector.importContact(importContactFrame); } catch (e) { if (mounted) { ScaffoldMessenger.of(context).showSnackBar( @@ -318,6 +320,21 @@ class _ContactsScreenState extends State ), onTap: () => _disconnect(context, connector), ), + PopupMenuItem( + child: Row( + children: [ + const Icon(Icons.person_add_rounded), + const SizedBox(width: 8), + Text("Discovered Contacts"), + ], + ), + onTap: () => Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const DiscoveryScreen(), + ), + ), + ), PopupMenuItem( child: Row( children: [ diff --git a/lib/screens/discovery_screen.dart b/lib/screens/discovery_screen.dart new file mode 100644 index 0000000..f122654 --- /dev/null +++ b/lib/screens/discovery_screen.dart @@ -0,0 +1,419 @@ +import 'dart:async'; + +import 'package:flutter/material.dart'; +import 'package:flutter/services.dart'; +import 'package:provider/provider.dart'; + +import '../connector/meshcore_connector.dart'; +import '../connector/meshcore_protocol.dart'; +import '../l10n/l10n.dart'; +import '../models/discovery_contact.dart'; +import '../utils/contact_search.dart'; +import '../widgets/app_bar.dart'; +import '../widgets/list_filter_widget.dart'; + +enum DiscoverySortOption { lastSeen, name, type } + +class DiscoveryScreen extends StatefulWidget { + const DiscoveryScreen({super.key}); + + @override + State createState() => _DiscoveryScreenState(); +} + +class _DiscoveryScreenState extends State { + final TextEditingController _searchController = TextEditingController(); + String searchQuery = ''; + ContactSortOption sortOption = ContactSortOption.lastSeen; + bool showUnreadOnly = false; + ContactTypeFilter typeFilter = ContactTypeFilter.all; + DiscoverySortOption discoverySortOption = DiscoverySortOption.lastSeen; + Timer? _searchDebounce; + + @override + void dispose() { + _searchController.dispose(); + _searchDebounce?.cancel(); + super.dispose(); + } + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + final connector = context.watch(); + + final discoveredContacts = connector.discoveredContacts; + final filteredAndSorted = _filterAndSortContacts( + discoveredContacts, + connector, + ); + + return Scaffold( + appBar: AppBar( + title: AppBarTitle( + l10n.discoveredContacts_Title, + indicators: false, + subtitle: false, + ), + centerTitle: true, + actions: [ + PopupMenuButton( + itemBuilder: (context) => [ + PopupMenuItem( + child: Row( + children: [ + const Icon(Icons.delete, color: Colors.red), + const SizedBox(width: 8), + Text(context.l10n.discoveredContacts_deleteContactAll), + ], + ), + onTap: () { + _deleteContacts(context, connector); + }, + ), + ], + icon: const Icon(Icons.more_vert), + ), + ], + ), + body: Column( + children: [ + _buildFilters(filteredAndSorted, connector), + Expanded( + child: discoveredContacts.isEmpty + ? Center(child: Text(l10n.contacts_noContacts)) + : filteredAndSorted.isEmpty + ? Center(child: Text(l10n.discoveredContacts_noMatching)) + : ListView.builder( + itemCount: filteredAndSorted.length, + itemBuilder: (context, index) { + final contact = filteredAndSorted[index]; + return ListTile( + leading: CircleAvatar( + backgroundColor: _getTypeColor(contact.type), + child: Icon( + _getTypeIcon(contact.type), + color: Colors.white, + size: 20, + ), + ), + title: Text( + contact.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + subtitle: Text( + contact.shortPubKeyHex, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + trailing: Text( + _formatLastSeen(context, contact.lastSeen), + style: TextStyle( + fontSize: 12, + color: Colors.grey[600], + ), + ), + onTap: () { + connector.importDiscoveredContact(contact); + }, + onLongPress: () => + _showContactContextMenu(contact, connector), + ); + }, + ), + ), + ], + ), + ); + } + + Future _showContactContextMenu( + DiscoveryContact contact, + MeshCoreConnector connector, + ) async { + final action = await showModalBottomSheet( + context: context, + showDragHandle: true, + builder: (sheetContext) { + final l10n = context.l10n; + return SafeArea( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + ListTile( + leading: const Icon(Icons.add_reaction_sharp), + title: Text(l10n.discoveredContacts_addContact), + onTap: () => Navigator.of(sheetContext).pop('import_contact'), + ), + ListTile( + leading: const Icon(Icons.copy), + title: Text(l10n.discoveredContacts_copyContact), + onTap: () => Navigator.of(sheetContext).pop('copy_contact'), + ), + ListTile( + leading: const Icon(Icons.delete), + title: Text(l10n.discoveredContacts_deleteContact), + onTap: () => Navigator.of(sheetContext).pop('delete_contact'), + ), + ], + ), + ); + }, + ); + + if (!mounted || action == null) return; + + switch (action) { + case 'import_contact': + connector.importDiscoveredContact(contact); + break; + case 'copy_contact': + final hexString = pubKeyToHex(contact.rawPacket); + Clipboard.setData(ClipboardData(text: "meshcore://$hexString")); + if (!mounted) return; + ScaffoldMessenger.of(context).showSnackBar( + SnackBar(content: Text(context.l10n.contacts_contactAdvertCopied)), + ); + break; + case 'delete_contact': + connector.removeDiscoveredContact(contact); + break; + } + } + + void _deleteContacts(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; + showDialog( + context: context, + builder: (context) => AlertDialog( + title: Text(l10n.common_deleteAll), + content: Text(l10n.discoveredContacts_deleteContactAllContent), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(l10n.common_cancel), + ), + TextButton( + onPressed: () async { + Navigator.pop(context); + connector.removeAllDiscoveredContacts(); + }, + child: Text(l10n.common_deleteAll), + ), + ], + ), + ); + } + + Widget _buildFilters( + List filteredAndSorted, + MeshCoreConnector connector, + ) { + String hintText = ""; + switch (typeFilter) { + case ContactTypeFilter.all: + hintText = context.l10n.contacts_searchContacts( + filteredAndSorted.length, + showUnreadOnly ? " ${context.l10n.contacts_unread}" : "", + ); + break; + case ContactTypeFilter.users: + hintText = context.l10n.contacts_searchUsers( + filteredAndSorted.length, + showUnreadOnly ? " ${context.l10n.contacts_unread}" : "", + ); + break; + case ContactTypeFilter.repeaters: + hintText = context.l10n.contacts_searchRepeaters( + filteredAndSorted.length, + showUnreadOnly ? " ${context.l10n.contacts_unread}" : "", + ); + break; + case ContactTypeFilter.rooms: + hintText = context.l10n.contacts_searchRoomServers( + filteredAndSorted.length, + showUnreadOnly ? " ${context.l10n.contacts_unread}" : "", + ); + break; + case ContactTypeFilter.favorites: + hintText = context.l10n.contacts_searchFavorites( + filteredAndSorted.length, + showUnreadOnly ? " ${context.l10n.contacts_unread}" : "", + ); + break; + } + + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(8.0), + child: TextField( + controller: _searchController, + decoration: InputDecoration( + hintText: hintText, + prefixIcon: const Icon(Icons.search), + suffixIcon: Row( + mainAxisSize: MainAxisSize.min, + children: [ + if (searchQuery.isNotEmpty) + IconButton( + icon: const Icon(Icons.clear), + onPressed: () { + _searchController.clear(); + setState(() { + searchQuery = ''; + }); + }, + ), + _buildFilterButton(context, connector), + ], + ), + border: OutlineInputBorder( + borderRadius: BorderRadius.circular(12), + ), + contentPadding: const EdgeInsets.symmetric( + horizontal: 16, + vertical: 12, + ), + ), + onChanged: (value) { + _searchDebounce?.cancel(); + _searchDebounce = Timer(const Duration(milliseconds: 300), () { + if (!mounted) return; + setState(() { + searchQuery = value.toLowerCase(); + }); + }); + }, + ), + ), + ], + ); + } + + Widget _buildFilterButton(BuildContext context, MeshCoreConnector connector) { + return DiscoveryContactsFilterMenu( + sortOption: sortOption, + typeFilter: typeFilter, + onSortChanged: (value) { + setState(() { + sortOption = value; + }); + }, + onTypeFilterChanged: (value) { + setState(() { + typeFilter = value; + }); + }, + ); + } + + List _filterAndSortContacts( + List contacts, + MeshCoreConnector connector, + ) { + var filtered = contacts.where((contact) { + if (searchQuery.isEmpty) return true; + return matchesDiscoveryContactQuery(contact, searchQuery); + }).toList(); + + filtered = filtered.where((contact) { + return !connector.knownContactKeys.contains(contact.publicKeyHex); + }).toList(); + + // Filter out own node from the list + if (connector.selfPublicKey != null) { + final selfPubKeyHex = pubKeyToHex(connector.selfPublicKey!); + filtered = filtered.where((contact) { + return contact.publicKeyHex != selfPubKeyHex; + }).toList(); + } + + if (typeFilter != ContactTypeFilter.all) { + filtered = filtered.where(_matchesTypeFilter).toList(); + } + + switch (sortOption) { + case ContactSortOption.lastSeen: + filtered.sort((a, b) => b.lastSeen.compareTo(a.lastSeen)); + break; + case ContactSortOption.name: + filtered.sort( + (a, b) => a.name.toLowerCase().compareTo(b.name.toLowerCase()), + ); + break; + default: + break; + } + + return filtered; + } + + bool _matchesTypeFilter(DiscoveryContact contact) { + switch (typeFilter) { + case ContactTypeFilter.all: + return true; + case ContactTypeFilter.users: + return contact.type == advTypeChat; + case ContactTypeFilter.repeaters: + return contact.type == advTypeRepeater; + case ContactTypeFilter.rooms: + return contact.type == advTypeRoom; + default: + return false; + } + } + + IconData _getTypeIcon(int type) { + switch (type) { + case advTypeChat: + return Icons.chat; + case advTypeRepeater: + return Icons.cell_tower; + case advTypeRoom: + return Icons.group; + case advTypeSensor: + return Icons.sensors; + default: + return Icons.device_unknown; + } + } + + Color _getTypeColor(int type) { + switch (type) { + case advTypeChat: + return Colors.blue; + case advTypeRepeater: + return Colors.orange; + case advTypeRoom: + return Colors.purple; + case advTypeSensor: + return Colors.green; + default: + return Colors.grey; + } + } + + String _formatLastSeen(BuildContext context, DateTime lastSeen) { + final now = DateTime.now(); + final diff = now.difference(lastSeen); + + if (diff.isNegative || diff.inMinutes < 5) { + return context.l10n.contacts_lastSeenNow; + } + if (diff.inMinutes < 60) { + return context.l10n.contacts_lastSeenMinsAgo(diff.inMinutes); + } + if (diff.inHours < 24) { + final hours = diff.inHours; + return hours == 1 + ? context.l10n.contacts_lastSeenHourAgo + : context.l10n.contacts_lastSeenHoursAgo(hours); + } + final days = diff.inDays; + return days == 1 + ? context.l10n.contacts_lastSeenDayAgo + : context.l10n.contacts_lastSeenDaysAgo(days); + } +} diff --git a/lib/screens/settings_screen.dart b/lib/screens/settings_screen.dart index a198f99..d6118f5 100644 --- a/lib/screens/settings_screen.dart +++ b/lib/screens/settings_screen.dart @@ -8,7 +8,7 @@ import '../connector/meshcore_connector.dart'; import '../connector/meshcore_protocol.dart'; import '../l10n/l10n.dart'; import '../models/radio_settings.dart'; -import '../widgets/adaptive_app_bar_title.dart'; +import '../widgets/app_bar.dart'; import 'app_settings_screen.dart'; import 'app_debug_log_screen.dart'; import 'ble_debug_log_screen.dart'; @@ -43,8 +43,11 @@ class _SettingsScreenState extends State { final l10n = context.l10n; return Scaffold( appBar: AppBar( - title: AdaptiveAppBarTitle(l10n.settings_title), - centerTitle: true, + title: AppBarTitle( + l10n.settings_title, + indicators: false, + subtitle: false, + ), ), body: SafeArea( top: false, @@ -274,6 +277,14 @@ class _SettingsScreenState extends State { onTap: () => _editLocation(context, connector), ), const Divider(height: 1), + ListTile( + leading: const Icon(Icons.group_add_outlined), + title: Text(l10n.settings_contactSettings), + subtitle: Text(l10n.settings_contactSettingsSubtitle), + trailing: const Icon(Icons.chevron_right), + onTap: () => _editAutoAddConfig(context, connector), + ), + const Divider(height: 1), ListTile( leading: const Icon(Icons.visibility_off_outlined), title: Text(l10n.settings_privacyMode), @@ -849,6 +860,121 @@ class _SettingsScreenState extends State { ), ); } + + void _editAutoAddConfig(BuildContext context, MeshCoreConnector connector) { + final l10n = context.l10n; + bool autoAddChat = false; + bool autoAddRepeater = false; + bool autoAddRoomServer = false; + bool autoAddSensor = false; + bool overwriteOldest = false; + + final connector = context.read(); + autoAddChat = connector.autoAddUsers ?? false; + autoAddRepeater = connector.autoAddRepeaters ?? false; + autoAddRoomServer = connector.autoAddRoomServers ?? false; + autoAddSensor = connector.autoAddSensors ?? false; + overwriteOldest = connector.autoAddOverwriteOldest ?? false; + + showDialog( + context: context, + builder: (dialogContext) => StatefulBuilder( + builder: (context, setDialogState) => AlertDialog( + title: Text(l10n.contactsSettings_autoAddTitle), + content: SingleChildScrollView( + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + FeatureToggleRow( + title: l10n.contactsSettings_autoAddUsersTitle, + subtitle: l10n.contactsSettings_autoAddUsersSubtitle, + value: autoAddChat, + onChanged: (value) { + setDialogState(() => autoAddChat = value); + }, + ), + SizedBox(height: 8), + FeatureToggleRow( + title: l10n.contactsSettings_autoAddRepeatersTitle, + subtitle: l10n.contactsSettings_autoAddRepeatersSubtitle, + value: autoAddRepeater, + onChanged: (value) { + setDialogState(() => autoAddRepeater = value); + }, + ), + SizedBox(height: 8), + FeatureToggleRow( + title: l10n.contactsSettings_autoAddRoomServersTitle, + subtitle: l10n.contactsSettings_autoAddRoomServersSubtitle, + value: autoAddRoomServer, + onChanged: (value) { + setDialogState(() => autoAddRoomServer = value); + }, + ), + SizedBox(height: 8), + FeatureToggleRow( + title: l10n.contactsSettings_autoAddSensorsTitle, + subtitle: l10n.contactsSettings_autoAddSensorsSubtitle, + value: autoAddSensor, + onChanged: (value) { + setDialogState(() => autoAddSensor = value); + }, + ), + Divider(height: 4), + FeatureToggleRow( + title: l10n.contactsSettings_overwriteOldestTitle, + subtitle: l10n.contactsSettings_overwriteOldestSubtitle, + value: overwriteOldest, + onChanged: (value) { + setDialogState(() => overwriteOldest = value); + }, + ), + ], + ), + ), + actions: [ + TextButton( + onPressed: () => Navigator.pop(context), + child: Text(l10n.common_cancel), + ), + TextButton( + onPressed: () { + _sendSettings( + connector, + autoAddChat, + autoAddRepeater, + autoAddRoomServer, + autoAddSensor, + overwriteOldest, + ); + Navigator.pop(context); + }, + child: Text(l10n.common_save), + ), + ], + ), + ), + ); + } + + void _sendSettings( + MeshCoreConnector connector, + bool autoAddChat, + bool autoAddRepeater, + bool autoAddRoomServer, + bool autoAddSensor, + bool overwriteOldest, + ) async { + final frame = buildSetAutoAddConfigFrame( + autoAddChat: autoAddChat, + autoAddRepeater: autoAddRepeater, + autoAddRoomServer: autoAddRoomServer, + autoAddSensor: autoAddSensor, + overwriteOldest: overwriteOldest, + ); + await connector.sendFrame(frame); + await connector.sendFrame(buildGetAutoAddFlagsFrame()); + } } class _RadioSettingsDialog extends StatefulWidget { diff --git a/lib/services/ble_debug_log_service.dart b/lib/services/ble_debug_log_service.dart index bc46b59..df2822b 100644 --- a/lib/services/ble_debug_log_service.dart +++ b/lib/services/ble_debug_log_service.dart @@ -172,8 +172,6 @@ class BleDebugLogService extends ChangeNotifier { return 'CMD_GET_CHANNEL'; case cmdSetChannel: return 'CMD_SET_CHANNEL'; - case cmdGetRadioSettings: - return 'CMD_GET_RADIO_SETTINGS'; case cmdSetCustomVar: return 'CMD_SET_CUSTOM_VAR'; case cmdSendTracePath: @@ -215,8 +213,8 @@ class BleDebugLogService extends ChangeNotifier { return 'RESP_CODE_CHANNEL_MSG_RECV_V3'; case respCodeChannelInfo: return 'RESP_CODE_CHANNEL_INFO'; - case respCodeRadioSettings: - return 'RESP_CODE_RADIO_SETTINGS'; + case respCodeAutoAddConfig: + return 'RESP_CODE_AUTO_ADD_CONFIG'; case pushCodeTraceData: return 'PUSH_CODE_TRACE_DATA'; default: diff --git a/lib/storage/contact_discovery_store.dart b/lib/storage/contact_discovery_store.dart new file mode 100644 index 0000000..37bfbb4 --- /dev/null +++ b/lib/storage/contact_discovery_store.dart @@ -0,0 +1,61 @@ +import 'dart:convert'; +import 'dart:typed_data'; + +import '../models/discovery_contact.dart'; +import 'prefs_manager.dart'; + +class ContactDiscoveryStore { + static const String _key = 'discovered_contacts'; + + Future> loadContacts() async { + final prefs = PrefsManager.instance; + final jsonStr = prefs.getString(_key); + if (jsonStr == null) return []; + + try { + final jsonList = jsonDecode(jsonStr) as List; + return jsonList + .map((entry) => _fromJson(entry as Map)) + .toList(); + } catch (_) { + return []; + } + } + + Future saveContacts(List contacts) async { + final prefs = PrefsManager.instance; + final jsonList = contacts.map(_toJson).toList(); + await prefs.setString(_key, jsonEncode(jsonList)); + } + + Map _toJson(DiscoveryContact contact) { + return { + 'rawPacket': base64Encode(contact.rawPacket), + 'publicKey': base64Encode(contact.publicKey), + 'name': contact.name, + 'type': contact.type, + 'pathLength': contact.pathLength, + 'path': base64Encode(contact.path), + 'latitude': contact.latitude, + 'longitude': contact.longitude, + 'lastSeen': contact.lastSeen.millisecondsSinceEpoch, + }; + } + + DiscoveryContact _fromJson(Map json) { + final lastSeenMs = json['lastSeen'] as int? ?? 0; + return DiscoveryContact( + rawPacket: Uint8List.fromList(base64Decode(json['rawPacket'] as String)), + publicKey: Uint8List.fromList(base64Decode(json['publicKey'] as String)), + name: json['name'] as String? ?? 'Unknown', + type: json['type'] as int? ?? 0, + pathLength: json['pathLength'] as int? ?? -1, + path: json['path'] != null + ? Uint8List.fromList(base64Decode(json['path'] as String)) + : Uint8List(0), + latitude: (json['latitude'] as num?)?.toDouble(), + longitude: (json['longitude'] as num?)?.toDouble(), + lastSeen: DateTime.fromMillisecondsSinceEpoch(lastSeenMs), + ); + } +} diff --git a/lib/utils/contact_search.dart b/lib/utils/contact_search.dart index 318f307..beec880 100644 --- a/lib/utils/contact_search.dart +++ b/lib/utils/contact_search.dart @@ -1,3 +1,5 @@ +import 'package:meshcore_open/models/discovery_contact.dart'; + import '../models/contact.dart'; bool matchesContactQuery(Contact contact, String query) { @@ -14,6 +16,20 @@ bool matchesContactQuery(Contact contact, String query) { return contact.publicKeyHex.toLowerCase().startsWith(hexPrefix); } +bool matchesDiscoveryContactQuery(DiscoveryContact contact, String query) { + final normalizedQuery = query.trim().toLowerCase(); + if (normalizedQuery.isEmpty) return true; + + if (contact.name.toLowerCase().contains(normalizedQuery)) { + return true; + } + + final hexPrefix = _extractHexPrefix(normalizedQuery); + if (hexPrefix == null) return false; + + return contact.publicKeyHex.toLowerCase().startsWith(hexPrefix); +} + String? _extractHexPrefix(String query) { var cleaned = query; if (cleaned.startsWith('<')) { diff --git a/lib/widgets/app_bar.dart b/lib/widgets/app_bar.dart index 1afc531..b95984b 100644 --- a/lib/widgets/app_bar.dart +++ b/lib/widgets/app_bar.dart @@ -9,7 +9,16 @@ class AppBarTitle extends StatelessWidget { final String title; final Widget? leading; final Widget? trailing; - const AppBarTitle(this.title, {this.leading, this.trailing, super.key}); + final bool indicators; + final bool subtitle; + const AppBarTitle( + this.title, { + this.leading, + this.trailing, + this.indicators = true, + this.subtitle = true, + super.key, + }); @override Widget build(BuildContext context) { @@ -21,12 +30,12 @@ class AppBarTitle extends StatelessWidget { final availableWidth = constraints.hasBoundedWidth ? constraints.maxWidth : MediaQuery.sizeOf(context).width; - final compact = availableWidth < 240; + final compact = availableWidth < 170; final showSubtitle = - !compact && connector.isConnected && selfName != null; + !compact && connector.isConnected && selfName != null && subtitle; final showBattery = availableWidth >= 60; final showSnr = availableWidth >= 110; - final showIndicators = showBattery || showSnr; + final showIndicators = (showBattery || showSnr) && indicators; return Row( mainAxisAlignment: MainAxisAlignment.start, diff --git a/lib/widgets/list_filter_widget.dart b/lib/widgets/list_filter_widget.dart index 473a3df..ee6fcd4 100644 --- a/lib/widgets/list_filter_widget.dart +++ b/lib/widgets/list_filter_widget.dart @@ -224,3 +224,93 @@ class ContactsFilterMenu extends StatelessWidget { ); } } + +class DiscoveryContactsFilterMenu extends StatelessWidget { + final ContactSortOption sortOption; + final ContactTypeFilter typeFilter; + final ValueChanged onSortChanged; + final ValueChanged onTypeFilterChanged; + + const DiscoveryContactsFilterMenu({ + super.key, + required this.sortOption, + required this.typeFilter, + required this.onSortChanged, + required this.onTypeFilterChanged, + }); + + @override + Widget build(BuildContext context) { + final l10n = context.l10n; + return SortFilterMenu( + tooltip: l10n.listFilter_tooltip, + sections: [ + SortFilterMenuSection( + title: l10n.listFilter_sortBy, + options: [ + SortFilterMenuOption( + value: _actionSortLastSeen, + label: l10n.listFilter_heardRecently, + checked: sortOption == ContactSortOption.lastSeen, + ), + SortFilterMenuOption( + value: _actionSortName, + label: l10n.listFilter_az, + checked: sortOption == ContactSortOption.name, + ), + ], + ), + SortFilterMenuSection( + title: l10n.listFilter_filters, + options: [ + SortFilterMenuOption( + value: _actionFilterAll, + label: l10n.listFilter_all, + checked: typeFilter == ContactTypeFilter.all, + ), + SortFilterMenuOption( + value: _actionFilterUsers, + label: l10n.listFilter_users, + checked: typeFilter == ContactTypeFilter.users, + ), + SortFilterMenuOption( + value: _actionFilterRepeaters, + label: l10n.listFilter_repeaters, + checked: typeFilter == ContactTypeFilter.repeaters, + ), + SortFilterMenuOption( + value: _actionFilterRooms, + label: l10n.listFilter_roomServers, + checked: typeFilter == ContactTypeFilter.rooms, + ), + ], + ), + ], + onSelected: (action) { + switch (action) { + case _actionSortName: + onSortChanged(ContactSortOption.name); + break; + case _actionSortLastSeen: + onSortChanged(ContactSortOption.lastSeen); + break; + case _actionFilterAll: + onTypeFilterChanged(ContactTypeFilter.all); + break; + case _actionFilterUsers: + onTypeFilterChanged(ContactTypeFilter.users); + break; + case _actionFilterFavorites: + onTypeFilterChanged(ContactTypeFilter.favorites); + break; + case _actionFilterRepeaters: + onTypeFilterChanged(ContactTypeFilter.repeaters); + break; + case _actionFilterRooms: + onTypeFilterChanged(ContactTypeFilter.rooms); + break; + } + }, + ); + } +}