From a9fbf8c7f502fef9a229e9a0ae1084e7d1a2e2f9 Mon Sep 17 00:00:00 2001 From: MGJ <62177301+MGJ520@users.noreply.github.com> Date: Tue, 17 Feb 2026 13:30:19 +0800 Subject: [PATCH 01/10] Correct Chinese translation --- lib/l10n/app_zh.arb | 976 ++++++++++++++++++++++---------------------- 1 file changed, 488 insertions(+), 488 deletions(-) diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index 7b4b3ab..3e4b1d3 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1,11 +1,11 @@ { "@@locale": "zh", "appTitle": "MeshCore Open", - "nav_contacts": "联系方式", + "nav_contacts": "联系人", "nav_channels": "频道", "nav_map": "地图", "common_cancel": "取消", - "common_ok": "好的", + "common_ok": "确定", "common_connect": "连接", "common_unknownDevice": "未知设备", "common_save": "保存", @@ -15,9 +15,9 @@ "common_add": "添加", "common_settings": "设置", "common_disconnect": "断开", - "common_connected": "连接", - "common_disconnected": "断开", - "common_create": "创造", + "common_connected": "已连接", + "common_disconnected": "已断开", + "common_create": "创建", "common_continue": "继续", "common_share": "分享", "common_copy": "复制", @@ -26,7 +26,7 @@ "common_remove": "移除", "common_enable": "启用", "common_disable": "禁用", - "common_reboot": "重新启动", + "common_reboot": "重启", "common_loading": "正在加载...", "common_notAvailable": "—", "common_voltageValue": "{volts} V", @@ -45,7 +45,7 @@ } } }, - "scanner_title": "MeshCore 开放", + "scanner_title": "连接设备", "scanner_scanning": "正在搜索设备...", "scanner_connecting": "正在连接...", "scanner_disconnecting": "断开连接...", @@ -59,8 +59,8 @@ } }, "scanner_searchingDevices": "正在搜索 MeshCore 设备...", - "scanner_tapToScan": "点击“扫描”功能,以查找 MeshCore 设备。", - "scanner_connectionFailed": "Connection failed: {error}", + "scanner_tapToScan": "点击“扫描”按钮以查找 MeshCore 设备。", + "scanner_connectionFailed": "连接失败:{error}", "@scanner_connectionFailed": { "placeholders": { "error": { @@ -71,8 +71,8 @@ "scanner_stop": "停止", "scanner_scan": "扫描", "device_quickSwitch": "快速切换", - "device_meshcore": "网格核心", - "settings_title": "设置", + "device_meshcore": "MeshCore", + "settings_title": " ", "settings_deviceInfo": "设备信息", "settings_appSettings": "应用设置", "settings_appSettingsSubtitle": "通知、消息和地图偏好", @@ -80,43 +80,43 @@ "settings_nodeName": "节点名称", "settings_nodeNameNotSet": "未设置", "settings_nodeNameHint": "请输入节点名称", - "settings_nodeNameUpdated": "姓名已更新", - "settings_radioSettings": "收音机设置", + "settings_nodeNameUpdated": "节点名称已更新", + "settings_radioSettings": "无线电设置", "settings_radioSettingsSubtitle": "频率、功率、扩频因子", - "settings_radioSettingsUpdated": "收音机设置已更新", - "settings_location": "地点", + "settings_radioSettingsUpdated": "无线电设置已更新", + "settings_location": "位置", "settings_locationSubtitle": "GPS 坐标", "settings_locationUpdated": "位置和 GPS 设置已更新", - "settings_locationBothRequired": "请输入经度和纬度。", - "settings_locationInvalid": "无效的经度和纬度。", - "settings_locationGPSEnable": "开启 GPS 功能", - "settings_locationGPSEnableSubtitle": "使 GPS 能够自动更新位置。", - "settings_locationIntervalSec": "GPS 间隔时间(秒)", + "settings_locationBothRequired": "请输入经度和纬度", + "settings_locationInvalid": "无效的经度和纬度", + "settings_locationGPSEnable": "启用 GPS", + "settings_locationGPSEnableSubtitle": "启用 GPS 以自动更新位置。", + "settings_locationIntervalSec": "GPS 间隔(秒)", "settings_locationIntervalInvalid": "间隔时间必须至少为 60 秒,但不超过 86400 秒。", "settings_latitude": "纬度", "settings_longitude": "经度", "settings_privacyMode": "隐私模式", "settings_privacyModeSubtitle": "在广告中隐藏姓名/位置", - "settings_privacyModeToggle": "切换隐私模式,以隐藏您的姓名和位置,从而在广告中保护您的个人信息。", + "settings_privacyModeToggle": "切换隐私模式以在广告中隐藏姓名和位置,保护个人信息。", "settings_privacyModeEnabled": "隐私模式已启用", "settings_privacyModeDisabled": "隐私模式已关闭", - "settings_actions": "行动", - "settings_sendAdvertisement": "发布广告", - "settings_sendAdvertisementSubtitle": "现已开始进行广播节目", - "settings_advertisementSent": "已发送广告", + "settings_actions": "操作", + "settings_sendAdvertisement": "发送广播", + "settings_sendAdvertisementSubtitle": "立即发送广播", + "settings_advertisementSent": "已发送广播", "settings_syncTime": "同步时间", "settings_syncTimeSubtitle": "将设备时钟设置为与手机时间一致", - "settings_timeSynchronized": "时间同步", + "settings_timeSynchronized": "时间已同步", "settings_refreshContacts": "刷新联系人", - "settings_refreshContactsSubtitle": "从设备中重新加载联系人列表", + "settings_refreshContactsSubtitle": "从设备重新加载联系人列表", "settings_rebootDevice": "重启设备", - "settings_rebootDeviceSubtitle": "重新启动 MeshCore 设备", - "settings_rebootDeviceConfirm": "您确定要重启设备吗?这将导致您与设备断开连接。", + "settings_rebootDeviceSubtitle": "重启 MeshCore 设备", + "settings_rebootDeviceConfirm": "确定要重启设备吗?这将断开与设备的连接。", "settings_debug": "调试", "settings_bleDebugLog": "BLE 调试日志", "settings_bleDebugLogSubtitle": "BLE 命令、响应和原始数据", - "settings_appDebugLog": "应用程序调试日志", - "settings_appDebugLogSubtitle": "应用程序调试消息", + "settings_appDebugLog": "应用调试日志", + "settings_appDebugLogSubtitle": "应用调试消息", "settings_about": "关于", "settings_aboutVersion": "MeshCore Open v{version}", "@settings_aboutVersion": { @@ -128,29 +128,29 @@ }, "settings_aboutLegalese": "2026 MeshCore 开源项目", "settings_aboutDescription": "一个开源的 Flutter 客户端,用于 MeshCore LoRa 无线网络设备。", - "settings_infoName": "姓名", - "settings_infoId": "ID", + "settings_infoName": "名称", + "settings_infoId": "MAC ID", "settings_infoStatus": "状态", "settings_infoBattery": "电池", "settings_infoPublicKey": "公钥", "settings_infoContactsCount": "联系人数量", - "settings_infoChannelCount": "通道数量", + "settings_infoChannelCount": "频道数量", "settings_presets": "预设", - "settings_preset915Mhz": "915 兆赫", - "settings_preset868Mhz": "868 兆赫", - "settings_preset433Mhz": "433 兆赫", + "settings_preset915Mhz": "915 MHz", + "settings_preset868Mhz": "868 MHz", + "settings_preset433Mhz": "433 MHz", "settings_frequency": "频率 (MHz)", "settings_frequencyHelper": "300.0 - 2500.0", - "settings_frequencyInvalid": "无效频率(300-2500 MHz)", + "settings_frequencyInvalid": "无效频率范围(300-2500 MHz)", "settings_bandwidth": "带宽", - "settings_spreadingFactor": "传播系数", + "settings_spreadingFactor": "扩频因子", "settings_codingRate": "编码速率", - "settings_txPower": "TX 功率(dBm)", + "settings_txPower": "TX 功率 (dBm)", "settings_txPowerHelper": "0 - 22", "settings_txPowerInvalid": "无效的发射功率(0-22 dBm)", "settings_longRange": "远距离", "settings_fastSpeed": "高速", - "settings_error": "[保存:{message}]\n错误:{message}", + "settings_error": "错误:{message}", "@settings_error": { "placeholders": { "message": { @@ -161,49 +161,49 @@ "appSettings_title": "应用设置", "appSettings_appearance": "外观", "appSettings_theme": "主题", - "appSettings_themeSystem": "系统默认设置", - "appSettings_themeLight": "光", - "appSettings_themeDark": "黑暗", + "appSettings_themeSystem": "跟随系统", + "appSettings_themeLight": "浅色", + "appSettings_themeDark": "深色", "appSettings_language": "语言", - "appSettings_languageSystem": "系统默认设置", + "appSettings_languageSystem": "跟随系统", "appSettings_languageEn": "英语", "appSettings_languageFr": "法语", "appSettings_languageEs": "西班牙语", "appSettings_languageDe": "德语", "appSettings_languagePl": "波兰语", - "appSettings_languageSl": "斯洛文语", + "appSettings_languageSl": "斯洛文尼亚语", "appSettings_languagePt": "葡萄牙语", "appSettings_languageIt": "意大利语", "appSettings_languageZh": "中文", "appSettings_languageSv": "瑞典语", "appSettings_languageNl": "荷兰语", "appSettings_languageSk": "斯洛伐克语", - "appSettings_languageBg": "保加利亚", + "appSettings_languageBg": "保加利亚语", "appSettings_languageRu": "俄语", - "appSettings_languageUk": "乌克兰", + "appSettings_languageUk": "乌克兰语", "appSettings_notifications": "通知", "appSettings_enableNotifications": "启用通知", - "appSettings_enableNotificationsSubtitle": "接收消息和广告的通知", + "appSettings_enableNotificationsSubtitle": "接收消息和广播的通知", "appSettings_notificationPermissionDenied": "权限被拒绝", "appSettings_notificationsEnabled": "通知已启用", "appSettings_notificationsDisabled": "通知已关闭", "appSettings_messageNotifications": "消息通知", - "appSettings_messageNotificationsSubtitle": "在收到新消息时显示通知", + "appSettings_messageNotificationsSubtitle": "收到新消息时显示通知", "appSettings_channelMessageNotifications": "频道消息通知", - "appSettings_channelMessageNotificationsSubtitle": "在收到频道消息时,显示通知。", - "appSettings_advertisementNotifications": "广告通知", - "appSettings_advertisementNotificationsSubtitle": "在发现新的节点时,显示通知。", - "appSettings_messaging": "信息传递", - "appSettings_clearPathOnMaxRetry": "关于“最大重试”的清晰说明", - "appSettings_clearPathOnMaxRetrySubtitle": "在尝试发送失败后 5 次,重置联系路径。", - "appSettings_pathsWillBeCleared": "如果尝试 5 次后仍然失败,则将重新规划路径。", - "appSettings_pathsWillNotBeCleared": "路径不会自动清除。", + "appSettings_channelMessageNotificationsSubtitle": "收到频道消息时显示通知", + "appSettings_advertisementNotifications": "广播通知", + "appSettings_advertisementNotificationsSubtitle": "发现新节点时显示通知", + "appSettings_messaging": "消息", + "appSettings_clearPathOnMaxRetry": "达到最大重试次数时清除路径", + "appSettings_clearPathOnMaxRetrySubtitle": "在5次发送失败后重置联系路径。", + "appSettings_pathsWillBeCleared": "5次失败后将重新路由", + "appSettings_pathsWillNotBeCleared": "路径不会自动清除", "appSettings_autoRouteRotation": "自动路径轮换", - "appSettings_autoRouteRotationSubtitle": "在最佳路径和防洪模式之间切换", + "appSettings_autoRouteRotationSubtitle": "在最佳路径和泛洪模式之间切换", "appSettings_autoRouteRotationEnabled": "自动路径轮换已启用", "appSettings_autoRouteRotationDisabled": "自动路径轮换已禁用", "appSettings_battery": "电池", - "appSettings_batteryChemistry": "电池化学", + "appSettings_batteryChemistry": "电池类型", "appSettings_batteryChemistryPerDevice": "为每个设备设置 ({deviceName})", "@appSettings_batteryChemistryPerDevice": { "placeholders": { @@ -212,20 +212,20 @@ } } }, - "appSettings_batteryChemistryConnectFirst": "连接到设备以进行选择", - "appSettings_batteryNmc": "18650 型号,NMC 电池(3.0-4.2V)", + "appSettings_batteryChemistryConnectFirst": "请先连接设备", + "appSettings_batteryNmc": "18650 NMC 电池 (3.0-4.2V)", "appSettings_batteryLifepo4": "磷酸铁锂 (2.6-3.65V)", - "appSettings_batteryLipo": "锂离子电池 (3.0-4.2V)", - "appSettings_mapDisplay": "地图展示", - "appSettings_showRepeaters": "显示重复", - "appSettings_showRepeatersSubtitle": "在地图上显示重复节点", + "appSettings_batteryLipo": "锂聚合物电池 (3.0-4.2V)", + "appSettings_mapDisplay": "地图显示", + "appSettings_showRepeaters": "显示转发节点", + "appSettings_showRepeatersSubtitle": "在地图上显示转发节点", "appSettings_showChatNodes": "显示聊天节点", "appSettings_showChatNodesSubtitle": "在地图上显示聊天节点", "appSettings_showOtherNodes": "显示其他节点", "appSettings_showOtherNodesSubtitle": "在地图上显示其他节点类型", "appSettings_timeFilter": "时间过滤器", "appSettings_timeFilterShowAll": "显示所有节点", - "appSettings_timeFilterShowLast": "Show nodes from last {hours} hours", + "appSettings_timeFilterShowLast": "显示过去 {hours} 小时内的节点", "@appSettings_timeFilterShowLast": { "placeholders": { "hours": { @@ -234,7 +234,7 @@ } }, "appSettings_mapTimeFilter": "地图时间筛选", - "appSettings_showNodesDiscoveredWithin": "显示在以下范围内发现的节点:", + "appSettings_showNodesDiscoveredWithin": "显示在此时间段内发现的节点:", "appSettings_allTime": "所有时间", "appSettings_lastHour": "过去一小时", "appSettings_last6Hours": "过去6小时", @@ -242,7 +242,7 @@ "appSettings_lastWeek": "上周", "appSettings_offlineMapCache": "离线地图缓存", "appSettings_noAreaSelected": "未选择任何区域", - "appSettings_areaSelectedZoom": "已选择区域(缩放至 {minZoom} - {maxZoom})", + "appSettings_areaSelectedZoom": "已选择区域(缩放 {minZoom} - {maxZoom})", "@appSettings_areaSelectedZoom": { "placeholders": { "minZoom": { @@ -254,18 +254,18 @@ } }, "appSettings_debugCard": "调试", - "appSettings_appDebugLogging": "应用程序调试日志", - "appSettings_appDebugLoggingSubtitle": "用于故障排除的日志应用程序调试消息", + "appSettings_appDebugLogging": "应用调试日志", + "appSettings_appDebugLoggingSubtitle": "记录应用调试消息以进行故障排除。", "appSettings_appDebugLoggingEnabled": "调试日志已启用", - "appSettings_appDebugLoggingDisabled": "应用程序调试日志已禁用", - "contacts_title": "联系方式", - "contacts_noContacts": "目前还没有联系人", - "contacts_contactsWillAppear": "当设备发布广告时,联系方式会显示。", + "appSettings_appDebugLoggingDisabled": "应用调试日志已禁用", + "contacts_title": " ", + "contacts_noContacts": "暂无联系人", + "contacts_contactsWillAppear": "当设备发送广播时,联系人将显示。", "contacts_searchContacts": "搜索联系人...", - "contacts_noUnreadContacts": "没有未读通讯", - "contacts_noContactsFound": "未找到任何联系人或群组", + "contacts_noUnreadContacts": "没有未读内容", + "contacts_noContactsFound": "未找到任何联系人或群聊", "contacts_deleteContact": "删除联系人", - "contacts_removeConfirm": "Remove {contactName} from contacts?", + "contacts_removeConfirm": "从联系人中移除 {contactName}?", "@contacts_removeConfirm": { "placeholders": { "contactName": { @@ -273,13 +273,13 @@ } } }, - "contacts_manageRepeater": "管理重复器", + "contacts_manageRepeater": "管理转发节点", "contacts_manageRoom": "管理房间服务器", "contacts_roomLogin": "服务器登录", - "contacts_openChat": "开放聊天", - "contacts_editGroup": "编辑小组", - "contacts_deleteGroup": "删除群组", - "contacts_deleteGroupConfirm": "删除\"{groupName}\"?", + "contacts_openChat": "打开聊天", + "contacts_editGroup": "编辑群聊", + "contacts_deleteGroup": "删除群聊", + "contacts_deleteGroupConfirm": "删除群聊 \"{groupName}\"?", "@contacts_deleteGroupConfirm": { "placeholders": { "groupName": { @@ -287,10 +287,10 @@ } } }, - "contacts_newGroup": "新的团体", - "contacts_groupName": "团体名称", - "contacts_groupNameRequired": "需要提供组名称", - "contacts_groupAlreadyExists": "名为\"{name}\"的组已经存在", + "contacts_newGroup": "新建群聊", + "contacts_groupName": "群聊名称", + "contacts_groupNameRequired": "请输入群聊名称", + "contacts_groupAlreadyExists": "名为 \"{name}\" 的群聊已存在", "@contacts_groupAlreadyExists": { "placeholders": { "name": { @@ -299,10 +299,10 @@ } }, "contacts_filterContacts": "筛选联系人...", - "contacts_noContactsMatchFilter": "未找到符合您筛选条件的联系人", - "contacts_noMembers": "没有会员", - "contacts_lastSeenNow": "最后一次被看到的时间", - "contacts_lastSeenMinsAgo": "Last seen {minutes} mins ago", + "contacts_noContactsMatchFilter": "没有符合条件的联系人", + "contacts_noMembers": "暂无成员", + "contacts_lastSeenNow": "刚刚", + "contacts_lastSeenMinsAgo": "最后在线 {minutes} 分钟前", "@contacts_lastSeenMinsAgo": { "placeholders": { "minutes": { @@ -310,8 +310,8 @@ } } }, - "contacts_lastSeenHourAgo": "最后一次被看到的时间:1小时前", - "contacts_lastSeenHoursAgo": "Last seen {hours} hours ago", + "contacts_lastSeenHourAgo": "最后在线 1小时前", + "contacts_lastSeenHoursAgo": "最后在线 {hours} 小时前", "@contacts_lastSeenHoursAgo": { "placeholders": { "hours": { @@ -319,8 +319,8 @@ } } }, - "contacts_lastSeenDayAgo": "最后一次被看到的时间是1天前", - "contacts_lastSeenDaysAgo": "Last seen {days} days ago", + "contacts_lastSeenDayAgo": "最后在线 1天前", + "contacts_lastSeenDaysAgo": "最后在线 {days} 天前", "@contacts_lastSeenDaysAgo": { "placeholders": { "days": { @@ -328,7 +328,7 @@ } } }, - "channels_title": "频道", + "channels_title": " ", "channels_noChannelsConfigured": "未配置任何频道", "channels_addPublicChannel": "添加公共频道", "channels_searchChannels": "搜索频道...", @@ -341,14 +341,14 @@ } } }, - "channels_hashtagChannel": "话题标签频道", - "channels_public": "公众", - "channels_private": "私人", + "channels_hashtagChannel": "标签频道", + "channels_public": "公共", + "channels_private": "私有", "channels_publicChannel": "公共频道", - "channels_privateChannel": "私密频道", + "channels_privateChannel": "私有频道", "channels_editChannel": "编辑频道", "channels_deleteChannel": "删除频道", - "channels_deleteChannelConfirm": "Delete \"{name}\"? This cannot be undone.", + "channels_deleteChannelConfirm": "删除频道 \"{name}\"?此操作不可撤销。", "@channels_deleteChannelConfirm": { "placeholders": { "name": { @@ -356,7 +356,7 @@ } } }, - "channels_channelDeleted": "删除频道 \"{name}\"", + "channels_channelDeleted": "已删除频道 \"{name}\"", "@channels_channelDeleted": { "placeholders": { "name": { @@ -368,12 +368,12 @@ "channels_channelIndexLabel": "频道索引", "channels_channelName": "频道名称", "channels_usePublicChannel": "使用公共频道", - "channels_standardPublicPsk": "标准公共PSK", + "channels_standardPublicPsk": "标准公共 PSK", "channels_pskHex": "PSK (十六进制)", - "channels_generateRandomPsk": "生成随机的PSK(正交相移键控)", - "channels_enterChannelName": "请在此处输入频道名称", - "channels_pskMustBe32Hex": "PSK 必须包含 32 个十六进制字符。", - "channels_channelAdded": "添加频道 \"{name}\"", + "channels_generateRandomPsk": "生成随机 PSK", + "channels_enterChannelName": "请输入频道名称", + "channels_pskMustBe32Hex": "PSK 必须为 32 个十六进制字符", + "channels_channelAdded": "已添加频道 \"{name}\"", "@channels_channelAdded": { "placeholders": { "name": { @@ -399,27 +399,27 @@ } }, "channels_publicChannelAdded": "已添加公共频道", - "channels_sortBy": "按排序", - "channels_sortManual": "手册", - "channels_sortAZ": "A 到 Z", + "channels_sortBy": "排序方式", + "channels_sortManual": "手动", + "channels_sortAZ": "A-Z", "channels_sortLatestMessages": "最新消息", "channels_sortUnread": "未读", - "channels_createPrivateChannel": "创建私密频道", - "channels_createPrivateChannelDesc": "使用秘密密钥进行保护。", - "channels_joinPrivateChannel": "加入私密频道", + "channels_createPrivateChannel": "创建私有频道", + "channels_createPrivateChannelDesc": "使用密钥保护。", + "channels_joinPrivateChannel": "加入私有频道", "channels_joinPrivateChannelDesc": "手动输入密钥。", "channels_joinPublicChannel": "加入公共频道", - "channels_joinPublicChannelDesc": "任何人都可以加入这个频道。", - "channels_joinHashtagChannel": "加入一个带有特定标签的频道", - "channels_joinHashtagChannelDesc": "任何人都可以加入带有特定标签的频道。", + "channels_joinPublicChannelDesc": "任何人都可以加入。", + "channels_joinHashtagChannel": "加入标签频道", + "channels_joinHashtagChannelDesc": "任何人都可以加入标签频道。", "channels_scanQrCode": "扫描二维码", - "channels_scanQrCodeComingSoon": "即将发布", + "channels_scanQrCodeComingSoon": "即将推出", "channels_enterHashtag": "输入标签", "channels_hashtagHint": "例如:#团队", - "chat_noMessages": "目前还没有收到任何消息。", - "chat_sendMessageToStart": "发送消息以开始", - "chat_originalMessageNotFound": "无法找到原始消息", - "chat_replyingTo": "Replying to {name}", + "chat_noMessages": "暂无消息", + "chat_sendMessageToStart": "发送消息开始对话", + "chat_originalMessageNotFound": "找不到原始消息", + "chat_replyingTo": "正在回复 {name}", "@chat_replyingTo": { "placeholders": { "name": { @@ -427,7 +427,7 @@ } } }, - "chat_replyTo": "Reply to {name}", + "chat_replyTo": "回复 {name}", "@chat_replyTo": { "placeholders": { "name": { @@ -435,8 +435,8 @@ } } }, - "chat_location": "地点", - "chat_sendMessageTo": "Send a message to {contactName}", + "chat_location": "位置", + "chat_sendMessageTo": "发送消息给 {contactName}", "@chat_sendMessageTo": { "placeholders": { "contactName": { @@ -445,7 +445,7 @@ } }, "chat_typeMessage": "输入消息...", - "chat_messageTooLong": "消息内容过长(最大 {maxBytes} 字节)。", + "chat_messageTooLong": "消息过长(最多 {maxBytes} 字节)", "@chat_messageTooLong": { "placeholders": { "maxBytes": { @@ -455,8 +455,8 @@ }, "chat_messageCopied": "消息已复制", "chat_messageDeleted": "消息已删除", - "chat_retryingMessage": "重试消息", - "chat_retryCount": "Retry {current}/{max}", + "chat_retryingMessage": "正在重试消息", + "chat_retryCount": "重试 {current}/{max}", "@chat_retryCount": { "placeholders": { "current": { @@ -467,32 +467,32 @@ } } }, - "chat_sendGif": "发送 GIF 动画", + "chat_sendGif": "发送 GIF", "chat_reply": "回复", - "chat_addReaction": "添加评论", + "chat_addReaction": "添加表情", "chat_me": "我", - "emojiCategorySmileys": "表情符号", + "emojiCategorySmileys": "表情", "emojiCategoryGestures": "手势", - "emojiCategoryHearts": "心脏", - "emojiCategoryObjects": "物体", - "gifPicker_title": "选择一个 GIF 动画", - "gifPicker_searchHint": "搜索 GIF 动画...", - "gifPicker_poweredBy": "由 GIPHY 提供支持", - "gifPicker_noGifsFound": "未找到 GIF 动画", - "gifPicker_failedLoad": "无法加载 GIF 动画", - "gifPicker_failedSearch": "未能搜索 GIF 动画", - "gifPicker_noInternet": "没有互联网连接", - "debugLog_appTitle": "应用程序调试日志", + "emojiCategoryHearts": "爱心", + "emojiCategoryObjects": "物品", + "gifPicker_title": "选择 GIF", + "gifPicker_searchHint": "搜索 GIF...", + "gifPicker_poweredBy": "由 GIPHY 提供", + "gifPicker_noGifsFound": "未找到 GIF", + "gifPicker_failedLoad": "加载 GIF 失败", + "gifPicker_failedSearch": "搜索 GIF 失败", + "gifPicker_noInternet": "无网络连接", + "debugLog_appTitle": "应用调试日志", "debugLog_bleTitle": "BLE 调试日志", "debugLog_copyLog": "复制日志", - "debugLog_clearLog": "清晰的日志", + "debugLog_clearLog": "清除日志", "debugLog_copied": "调试日志已复制", "debugLog_bleCopied": "BLE 日志已复制", - "debugLog_noEntries": "目前还没有调试日志", - "debugLog_enableInSettings": "在设置中启用应用程序调试日志功能。", - "debugLog_frames": "框架", - "debugLog_rawLogRx": "原始日志-RX", - "debugLog_noBleActivity": "目前尚未有蓝牙低功耗(BLE)活动。", + "debugLog_noEntries": "暂无调试日志", + "debugLog_enableInSettings": "请在设置中启用应用调试日志。", + "debugLog_frames": "帧", + "debugLog_rawLogRx": "原始日志 RX", + "debugLog_noBleActivity": "暂无 BLE 活动", "debugFrame_length": "帧长度:{count} 字节", "@debugFrame_length": { "placeholders": { @@ -509,7 +509,7 @@ } } }, - "debugFrame_textMessageHeader": "短信模板:", + "debugFrame_textMessageHeader": "文本消息:", "debugFrame_destinationPubKey": "- 目标公钥:{pubKey}", "@debugFrame_destinationPubKey": { "placeholders": { @@ -518,7 +518,7 @@ } } }, - "debugFrame_timestamp": "- Timestamp: {timestamp}", + "debugFrame_timestamp": "- 时间戳:{timestamp}", "@debugFrame_timestamp": { "placeholders": { "timestamp": { @@ -534,7 +534,7 @@ } } }, - "debugFrame_textType": "- Text Type: {type} ({label})", + "debugFrame_textType": "- 文本类型:{type} ({label})", "@debugFrame_textType": { "placeholders": { "type": { @@ -545,8 +545,8 @@ } } }, - "debugFrame_textTypeCli": "命令行界面", - "debugFrame_textTypePlain": "简单", + "debugFrame_textTypeCli": "命令行", + "debugFrame_textTypePlain": "纯文本", "debugFrame_text": "- 文本:“{text}”", "@debugFrame_text": { "placeholders": { @@ -558,13 +558,13 @@ "debugFrame_hexDump": "十六进制数据:", "chat_pathManagement": "路径管理", "chat_routingMode": "路由模式", - "chat_autoUseSavedPath": "自动(使用已保存的路径)", - "chat_forceFloodMode": "强制洪水模式", + "chat_autoUseSavedPath": "自动(使用保存的路径)", + "chat_forceFloodMode": "强制泛洪模式", "chat_recentAckPaths": "最近使用的 ACK 路径(点击使用):", - "chat_pathHistoryFull": "路径历史已满。删除条目以添加新的条目。", - "chat_hopSingular": "跳跃", - "chat_hopPlural": "啤酒花", - "chat_hopsCount": "{count} {count, plural, =1{hop} other{hops}}", + "chat_pathHistoryFull": "路径历史已满,请删除后再添加。", + "chat_hopSingular": "跳", + "chat_hopPlural": "跳", + "chat_hopsCount": "{count} 跳", "@chat_hopsCount": { "placeholders": { "count": { @@ -573,19 +573,19 @@ } }, "chat_successes": "成功", - "chat_removePath": "删除路径", - "chat_noPathHistoryYet": "目前还没有历史记录。\n发送消息以查找路径。", + "chat_removePath": "移除路径", + "chat_noPathHistoryYet": "暂无路径历史。\n发送消息以探索路径。", "chat_pathActions": "路径操作:", "chat_setCustomPath": "设置自定义路径", "chat_setCustomPathSubtitle": "手动指定路由路径", - "chat_clearPath": "明确的道路", - "chat_clearPathSubtitle": "在下一次发送时,重新尝试。", - "chat_pathCleared": "路径已清理。下一条消息将重新确定路线。", - "chat_floodModeSubtitle": "使用应用程序栏中的路由切换功能", - "chat_floodModeEnabled": "防洪模式已启用。通过应用程序栏中的路由图标进行切换。", + "chat_clearPath": "清除路径", + "chat_clearPathSubtitle": "清除当前路径,下次发送将重新尝试。", + "chat_pathCleared": "路径已清除。下一条消息将重新路由。", + "chat_floodModeSubtitle": "在应用栏中切换路由模式。", + "chat_floodModeEnabled": "泛洪模式已启用。可通过应用栏的路由图标切换。", "chat_fullPath": "完整路径", - "chat_pathDetailsNotAvailable": "路径信息尚未提供。请尝试发送消息以刷新。", - "chat_pathSetHops": "Path set: {hopCount} {hopCount, plural, =1{hop} other{hops}} - {status}", + "chat_pathDetailsNotAvailable": "路径信息暂不可用,请尝试发送消息刷新。", + "chat_pathSetHops": "路径设置:{hopCount} 跳 - {status}", "@chat_pathSetHops": { "placeholders": { "hopCount": { @@ -596,16 +596,16 @@ } } }, - "chat_pathSavedLocally": "已本地保存。连接以进行同步。", + "chat_pathSavedLocally": "已本地保存,连接设备后可同步。", "chat_pathDeviceConfirmed": "设备已确认。", - "chat_pathDeviceNotConfirmed": "该设备尚未得到确认。", + "chat_pathDeviceNotConfirmed": "设备尚未确认。", "chat_type": "类型", "chat_path": "路径", "chat_publicKey": "公钥", "chat_compressOutgoingMessages": "压缩发送的消息", - "chat_floodForced": "洪水(被迫)", - "chat_directForced": "直接(强制性的)", - "chat_hopsForced": "{count} 根啤酒花(人工种植)", + "chat_floodForced": "泛洪(强制)", + "chat_directForced": "直连(强制)", + "chat_hopsForced": "{count} 跳(强制)", "@chat_hopsForced": { "placeholders": { "count": { @@ -613,10 +613,10 @@ } } }, - "chat_floodAuto": "自动洪水", - "chat_direct": "直接", + "chat_floodAuto": "自动泛洪", + "chat_direct": "直连", "chat_poiShared": "共享位置", - "chat_unread": "Unread: {count}", + "chat_unread": "未读:{count}", "@chat_unread": { "placeholders": { "count": { @@ -625,9 +625,9 @@ } }, "chat_openLink": "打开链接?", - "chat_openLinkConfirmation": "您想用浏览器打开这个链接吗?", - "chat_open": "开放", - "chat_couldNotOpenLink": "[保存:{url}]\n无法打开链接:{url}", + "chat_openLinkConfirmation": "是否使用浏览器打开此链接?", + "chat_open": "打开", + "chat_couldNotOpenLink": "无法打开链接:{url}", "@chat_couldNotOpenLink": { "placeholders": { "url": { @@ -636,10 +636,10 @@ } }, "chat_invalidLink": "无效的链接格式", - "map_title": "节点图", + "map_title": " ", "map_noNodesWithLocation": "没有包含位置信息的节点", - "map_nodesNeedGps": "节点需要共享其 GPS 坐标,以便在地图上显示", - "map_nodesCount": "Nodes: {count}", + "map_nodesNeedGps": "节点需要共享 GPS 坐标才能在地图上显示", + "map_nodesCount": "节点:{count}", "@map_nodesCount": { "placeholders": { "count": { @@ -647,7 +647,7 @@ } } }, - "map_pinsCount": "Pins: {count}", + "map_pinsCount": "标记:{count}", "@map_pinsCount": { "placeholders": { "count": { @@ -656,26 +656,26 @@ } }, "map_chat": "聊天", - "map_repeater": "重复器", + "map_repeater": "转发节点", "map_room": "房间", "map_sensor": "传感器", - "map_pinDm": "PIN (直接消息)", - "map_pinPrivate": "私密", - "map_pinPublic": "公开", - "map_lastSeen": "最后一次被看到", - "map_disconnectConfirm": "您确定要断开与此设备的连接吗?", - "map_from": "从", + "map_pinDm": "标记(私信)", + "map_pinPrivate": "私有", + "map_pinPublic": "公共", + "map_lastSeen": "最后在线", + "map_disconnectConfirm": "确定要断开与此设备的连接吗?", + "map_from": "来自", "map_source": "来源", - "map_flags": "旗帜", + "map_flags": "标志", "map_shareMarkerHere": "在此分享标记", "map_pinLabel": "标签", "map_label": "标签", - "map_pointOfInterest": "值得参观的地方", - "map_sendToContact": "发送给联系", + "map_pointOfInterest": "兴趣点", + "map_sendToContact": "发送给联系人", "map_sendToChannel": "发送到频道", "map_noChannelsAvailable": "没有可用的频道", - "map_publicLocationShare": "公共场所共享", - "map_publicLocationShareConfirm": "[保存:{channelLabel}]\n您即将分享一个位置,该位置位于 {channelLabel}。 此频道是公开的,任何拥有 PSK 的人都可以看到它。", + "map_publicLocationShare": "公共位置共享", + "map_publicLocationShareConfirm": "您即将在 {channelLabel} 上分享一个位置。此频道是公开的,任何拥有 PSK 的人都可以看到。", "@map_publicLocationShareConfirm": { "placeholders": { "channelLabel": { @@ -687,22 +687,22 @@ "map_filterNodes": "过滤节点", "map_nodeTypes": "节点类型", "map_chatNodes": "聊天节点", - "map_repeaters": "重复器", + "map_repeaters": "转发节点", "map_otherNodes": "其他节点", - "map_keyPrefix": "关键前缀", - "map_filterByKeyPrefix": "按关键前缀筛选", - "map_publicKeyPrefix": "公钥前缀", + "map_keyPrefix": "关键字前缀", + "map_filterByKeyPrefix": "按关键字前缀筛选", + "map_publicKeyPrefix": "关键字前缀", "map_markers": "标记", "map_showSharedMarkers": "显示共享标记", - "map_lastSeenTime": "最后一次被看到的时间", - "map_sharedPin": "共享密码", + "map_lastSeenTime": "最后在线时间", + "map_sharedPin": "共享标记", "map_joinRoom": "加入房间", - "map_manageRepeater": "管理重复器", + "map_manageRepeater": "管理转发节点", "mapCache_title": "离线地图缓存", - "mapCache_selectAreaFirst": "选择一个用于缓存的区域", - "mapCache_noTilesToDownload": "此区域没有可下载的瓦片。", - "mapCache_downloadTilesTitle": "下载瓷砖", - "mapCache_downloadTilesPrompt": "[保存:{count}]\n下载 {count} 个图片用于离线使用?", + "mapCache_selectAreaFirst": "请先选择要缓存的区域", + "mapCache_noTilesToDownload": "此区域没有可下载的瓦片", + "mapCache_downloadTilesTitle": "下载瓦片", + "mapCache_downloadTilesPrompt": "这需要下载 {count} 个瓦片", "@mapCache_downloadTilesPrompt": { "placeholders": { "count": { @@ -711,7 +711,7 @@ } }, "mapCache_downloadAction": "下载", - "mapCache_cachedTiles": "缓存 {count} 个瓦片", + "mapCache_cachedTiles": "已缓存 {count} 个瓦片", "@mapCache_cachedTiles": { "placeholders": { "count": { @@ -719,7 +719,7 @@ } } }, - "mapCache_cachedTilesWithFailed": "Cached {downloaded} tiles ({failed} failed)", + "mapCache_cachedTilesWithFailed": "已缓存 {downloaded} 个瓦片({failed} 个失败)", "@mapCache_cachedTilesWithFailed": { "placeholders": { "downloaded": { @@ -733,11 +733,11 @@ "mapCache_clearOfflineCacheTitle": "清除离线缓存", "mapCache_clearOfflineCachePrompt": "清除所有缓存的地图瓦片", "mapCache_offlineCacheCleared": "离线缓存已清除", - "mapCache_noAreaSelected": "未选择任何区域", + "mapCache_noAreaSelected": "未选择区域", "mapCache_cacheArea": "缓存区域", "mapCache_useCurrentView": "使用当前视图", - "mapCache_zoomRange": "变焦范围", - "mapCache_estimatedTiles": "Estimated tiles: {count}", + "mapCache_zoomRange": "缩放范围", + "mapCache_estimatedTiles": "估计瓦片数:{count}", "@mapCache_estimatedTiles": { "placeholders": { "count": { @@ -745,7 +745,7 @@ } } }, - "mapCache_downloadedTiles": "Downloaded {completed} / {total}", + "mapCache_downloadedTiles": "已下载 {completed}/{total}", "@mapCache_downloadedTiles": { "placeholders": { "completed": { @@ -756,9 +756,9 @@ } } }, - "mapCache_downloadTilesButton": "下载瓷砖", + "mapCache_downloadTilesButton": "下载瓦片", "mapCache_clearCacheButton": "清除缓存", - "mapCache_failedDownloads": "Failed downloads: {count}", + "mapCache_failedDownloads": "下载失败:{count}", "@mapCache_failedDownloads": { "placeholders": { "count": { @@ -766,7 +766,7 @@ } } }, - "mapCache_boundsLabel": "N {north}, S {south}, E {east}, W {west}", + "mapCache_boundsLabel": "北 {north}, 南 {south}, 东 {east}, 西 {west}", "@mapCache_boundsLabel": { "placeholders": { "north": { @@ -784,7 +784,7 @@ } }, "time_justNow": "刚才", - "time_minutesAgo": "{minutes}m ago", + "time_minutesAgo": "{minutes}分钟前", "@time_minutesAgo": { "placeholders": { "minutes": { @@ -792,7 +792,7 @@ } } }, - "time_hoursAgo": "{hours}h ago", + "time_hoursAgo": "{hours}小时前", "@time_hoursAgo": { "placeholders": { "hours": { @@ -810,31 +810,31 @@ }, "time_hour": "小时", "time_hours": "小时", - "time_day": "一天", + "time_day": "天", "time_days": "天", - "time_week": "一周", + "time_week": "周", "time_weeks": "周", - "time_month": "月份", - "time_months": "月份", + "time_month": "月", + "time_months": "月", "time_minutes": "分钟", "time_allTime": "所有时间", "dialog_disconnect": "断开", - "dialog_disconnectConfirm": "您确定要断开与此设备的连接吗?", - "login_repeaterLogin": "重复登录", - "login_roomLogin": "服务器登录", + "dialog_disconnectConfirm": "确定要断开与此设备的连接吗?", + "login_repeaterLogin": "转发节点登录", + "login_roomLogin": "房间服务器登录", "login_password": "密码", "login_enterPassword": "请输入密码", "login_savePassword": "保存密码", - "login_savePasswordSubtitle": "密码将安全地存储在 данном设备上", - "login_repeaterDescription": "输入重复器密码,即可访问设置和状态。", - "login_roomDescription": "输入密码进入房间,即可访问设置和状态。", + "login_savePasswordSubtitle": "密码将安全地存储在此设备上", + "login_repeaterDescription": "输入转发节点密码以访问设置和状态。", + "login_roomDescription": "输入房间服务器密码以访问设置和状态。", "login_routing": "路由", "login_routingMode": "路由模式", - "login_autoUseSavedPath": "自动(使用已保存的路径)", - "login_forceFloodMode": "强制洪水模式", + "login_autoUseSavedPath": "自动(使用保存的路径)", + "login_forceFloodMode": "强制泛洪模式", "login_managePaths": "管理路径", "login_login": "登录", - "login_attempt": "Attempt {current}/{max}", + "login_attempt": "尝试 {current}/{max}", "@login_attempt": { "placeholders": { "current": { @@ -845,7 +845,7 @@ } } }, - "login_failed": "Login failed: {error}", + "login_failed": "登录失败:{error}", "@login_failed": { "placeholders": { "error": { @@ -853,10 +853,10 @@ } } }, - "login_failedMessage": "登录失败。可能是密码错误,也可能是无法连接到服务器。", + "login_failedMessage": "登录失败。可能是密码错误或无法连接到服务器。", "common_reload": "重新加载", - "common_clear": "清晰", - "path_currentPath": "Current path: {path}", + "common_clear": "清除", + "path_currentPath": "当前路径:{path}", "@path_currentPath": { "placeholders": { "path": { @@ -864,7 +864,7 @@ } } }, - "path_usingHopsPath": "使用 {count} {count, plural, =1{hop} other{hops}} 条路径", + "path_usingHopsPath": "使用 {count} 跳路径", "@path_usingHopsPath": { "placeholders": { "count": { @@ -874,14 +874,14 @@ }, "path_enterCustomPath": "输入自定义路径", "path_currentPathLabel": "当前路径", - "path_hexPrefixInstructions": "请输入每个跳跃步骤的 2 个字符的十六进制前缀,用逗号分隔。", - "path_hexPrefixExample": "例如:A1, F2, 3C (每个节点使用其公钥的第一字节)", + "path_hexPrefixInstructions": "请输入每个中继节点的2字符十六进制前缀,用逗号分隔。", + "path_hexPrefixExample": "例如:A1, F2, 3C(每个节点使用其公钥的第一字节)", "path_labelHexPrefixes": "路径(十六进制前缀)", - "path_helperMaxHops": "最大 64 个“hop”(跳跃)。每个前缀由 2 个十六进制字符(1 字节)组成。", - "path_selectFromContacts": "或者从联系人列表中选择:", - "path_noRepeatersFound": "未找到任何重复设备或房间服务器。", - "path_customPathsRequire": "自定义路径需要中间节点,这些节点可以转发消息。", - "path_invalidHexPrefixes": "Invalid hex prefixes: {prefixes}", + "path_helperMaxHops": "最多 64 跳。每个前缀由 2 个十六进制字符(1 字节)组成。", + "path_selectFromContacts": "或从联系人列表中选择:", + "path_noRepeatersFound": "未找到任何转发节点或房间服务器。", + "path_customPathsRequire": "自定义路径需要中间节点转发消息。", + "path_invalidHexPrefixes": "无效的十六进制前缀:{prefixes}", "@path_invalidHexPrefixes": { "placeholders": { "prefixes": { @@ -889,29 +889,29 @@ } } }, - "path_tooLong": "路径太长。允许的最大跳跃次数为 64 次。", + "path_tooLong": "路径过长,最多允许 64 跳。", "path_setPath": "设置路径", - "repeater_management": "重复器管理", - "room_management": "服务器管理", + "repeater_management": "转发节点管理", + "room_management": "房间服务器管理", "repeater_managementTools": "管理工具", "repeater_status": "状态", - "repeater_statusSubtitle": "查看重复器状态、统计信息和邻居", - "repeater_telemetry": "远程监控", - "repeater_telemetrySubtitle": "查看传感器和系统状态的数据。", - "repeater_cli": "命令行界面", - "repeater_cliSubtitle": "向复用器发送指令", + "repeater_statusSubtitle": "查看转发节点状态、统计和邻居", + "repeater_telemetry": "遥测", + "repeater_telemetrySubtitle": "查看传感器和系统状态数据", + "repeater_cli": "命令行", + "repeater_cliSubtitle": "向转发节点发送命令", "repeater_neighbours": "邻居", - "repeater_neighboursSubtitle": "查看邻居节点(无需中间节点)。", + "repeater_neighboursSubtitle": "查看邻居节点(零跳)", "repeater_settings": "设置", - "repeater_settingsSubtitle": "配置重复器参数", - "repeater_statusTitle": "重复器状态", + "repeater_settingsSubtitle": "配置转发节点参数", + "repeater_statusTitle": "转发节点状态", "repeater_routingMode": "路由模式", - "repeater_autoUseSavedPath": "自动(使用已保存的路径)", - "repeater_forceFloodMode": "强制洪水模式", + "repeater_autoUseSavedPath": "自动(使用保存的路径)", + "repeater_forceFloodMode": "强制泛洪模式", "repeater_pathManagement": "路径管理", - "repeater_refresh": "更新", - "repeater_statusRequestTimeout": "状态请求超时。", - "repeater_errorLoadingStatus": "Error loading status: {error}", + "repeater_refresh": "刷新", + "repeater_statusRequestTimeout": "状态请求超时", + "repeater_errorLoadingStatus": "加载状态时出错:{error}", "@repeater_errorLoadingStatus": { "placeholders": { "error": { @@ -921,19 +921,19 @@ }, "repeater_systemInformation": "系统信息", "repeater_battery": "电池", - "repeater_clockAtLogin": "登录时的时间", - "repeater_uptime": "正常运行时间", - "repeater_queueLength": "排队长度", + "repeater_clockAtLogin": "登录时的时钟", + "repeater_uptime": "运行时间", + "repeater_queueLength": "队列长度", "repeater_debugFlags": "调试标志", - "repeater_radioStatistics": "广播统计", - "repeater_lastRssi": "上次的 RSSI 值", - "repeater_lastSnr": "最后一次信噪比", - "repeater_noiseFloor": "噪声水平", - "repeater_txAirtime": "TX 频道预留时间", - "repeater_rxAirtime": "RX 空时", + "repeater_radioStatistics": "无线电统计", + "repeater_lastRssi": "上次 RSSI", + "repeater_lastSnr": "上次 SNR", + "repeater_noiseFloor": "底噪", + "repeater_txAirtime": "发送空中时间", + "repeater_rxAirtime": "接收空中时间", "repeater_packetStatistics": "数据包统计", "repeater_sent": "发送", - "repeater_received": "已收到", + "repeater_received": "接收", "repeater_duplicates": "重复", "repeater_daysHoursMinsSecs": "{days}天 {hours}小时 {minutes}分 {seconds}秒", "@repeater_daysHoursMinsSecs": { @@ -952,7 +952,7 @@ } } }, - "repeater_packetTxTotal": "Total: {total}, Flood: {flood}, Direct: {direct}", + "repeater_packetTxTotal": "总计:{total},泛洪:{flood},直连:{direct}", "@repeater_packetTxTotal": { "placeholders": { "total": { @@ -966,7 +966,7 @@ } } }, - "repeater_packetRxTotal": "Total: {total}, Flood: {flood}, Direct: {direct}", + "repeater_packetRxTotal": "总计:{total},泛洪:{flood},直连:{direct}", "@repeater_packetRxTotal": { "placeholders": { "total": { @@ -980,7 +980,7 @@ } } }, - "repeater_duplicatesFloodDirect": "Flood: {flood}, Direct: {direct}", + "repeater_duplicatesFloodDirect": "泛洪:{flood},直连:{direct}", "@repeater_duplicatesFloodDirect": { "placeholders": { "flood": { @@ -991,7 +991,7 @@ } } }, - "repeater_duplicatesTotal": "Total: {total}", + "repeater_duplicatesTotal": "总计:{total}", "@repeater_duplicatesTotal": { "placeholders": { "total": { @@ -999,37 +999,37 @@ } } }, - "repeater_settingsTitle": "重复器设置", + "repeater_settingsTitle": "转发节点设置", "repeater_basicSettings": "基本设置", - "repeater_repeaterName": "重复器名称", - "repeater_repeaterNameHelper": "此复播器的显示名称", + "repeater_repeaterName": "转发节点名称", + "repeater_repeaterNameHelper": "此转发节点的显示名称", "repeater_adminPassword": "管理员密码", "repeater_adminPasswordHelper": "完整访问密码", "repeater_guestPassword": "访客密码", "repeater_guestPasswordHelper": "只读访问密码", - "repeater_radioSettings": "收音机设置", + "repeater_radioSettings": "无线电设置", "repeater_frequencyMhz": "频率 (MHz)", - "repeater_frequencyHelper": "300-2500 兆赫", + "repeater_frequencyHelper": "300-2500 MHz", "repeater_txPower": "TX 功率", "repeater_txPowerHelper": "1-30 dBm", "repeater_bandwidth": "带宽", - "repeater_spreadingFactor": "传播系数", + "repeater_spreadingFactor": "扩频因子", "repeater_codingRate": "编码速率", "repeater_locationSettings": "位置设置", "repeater_latitude": "纬度", - "repeater_latitudeHelper": "十进制度(例如:37.7749)", + "repeater_latitudeHelper": "十进制,例如 37.7749", "repeater_longitude": "经度", - "repeater_longitudeHelper": "十进制度(例如:-122.4194)", - "repeater_features": "特点", + "repeater_longitudeHelper": "十进制,例如 -122.4194", + "repeater_features": "功能", "repeater_packetForwarding": "数据包转发", - "repeater_packetForwardingSubtitle": "启用重复器,使其能够转发数据包", + "repeater_packetForwardingSubtitle": "启用转发节点转发数据包", "repeater_guestAccess": "访客访问", - "repeater_guestAccessSubtitle": "允许访客仅限读取权限", + "repeater_guestAccessSubtitle": "允许访客只读权限", "repeater_privacyMode": "隐私模式", - "repeater_privacyModeSubtitle": "在广告中隐藏姓名/位置", - "repeater_advertisementSettings": "广告设置", - "repeater_localAdvertInterval": "本地广告投放时间段", - "repeater_localAdvertIntervalMinutes": "{minutes} minutes", + "repeater_privacyModeSubtitle": "在广播中隐藏姓名/位置", + "repeater_advertisementSettings": "广播设置", + "repeater_localAdvertInterval": "本地广播间隔", + "repeater_localAdvertIntervalMinutes": "{minutes} 分钟", "@repeater_localAdvertIntervalMinutes": { "placeholders": { "minutes": { @@ -1037,8 +1037,8 @@ } } }, - "repeater_floodAdvertInterval": "洪水广告播放间隔", - "repeater_floodAdvertIntervalHours": "{hours} hours", + "repeater_floodAdvertInterval": "泛洪广播间隔", + "repeater_floodAdvertIntervalHours": "{hours} 小时", "@repeater_floodAdvertIntervalHours": { "placeholders": { "hours": { @@ -1046,19 +1046,19 @@ } } }, - "repeater_encryptedAdvertInterval": "加密的广告投放时间段", - "repeater_dangerZone": "危险区域", - "repeater_rebootRepeater": "重启重复器", - "repeater_rebootRepeaterSubtitle": "重新启动重复器设备", - "repeater_rebootRepeaterConfirm": "您确定要重新启动这个中继器吗?", + "repeater_encryptedAdvertInterval": "加密广播间隔", + "repeater_dangerZone": "危险设置", + "repeater_rebootRepeater": "重启转发节点", + "repeater_rebootRepeaterSubtitle": "重启转发节点设备", + "repeater_rebootRepeaterConfirm": "确定要重启此转发节点吗?", "repeater_regenerateIdentityKey": "重新生成身份密钥", "repeater_regenerateIdentityKeySubtitle": "生成新的公钥/私钥对", - "repeater_regenerateIdentityKeyConfirm": "这将为复用器生成一个新的身份。继续吗?", - "repeater_eraseFileSystem": "删除文件系统", - "repeater_eraseFileSystemSubtitle": "格式化重复文件系统", - "repeater_eraseFileSystemConfirm": "警告:此操作将清除复用器上的所有数据。 无法恢复!", - "repeater_eraseSerialOnly": "“Erase”功能仅可通过串行控制台使用。", - "repeater_commandSent": "Command sent: {command}", + "repeater_regenerateIdentityKeyConfirm": "这将为转发节点生成新身份,继续吗?", + "repeater_eraseFileSystem": "擦除文件系统", + "repeater_eraseFileSystemSubtitle": "格式化转发节点文件系统", + "repeater_eraseFileSystemConfirm": "警告:此操作将清除转发节点上的所有数据,且无法恢复!", + "repeater_eraseSerialOnly": "擦除功能仅可通过串行控制台使用。", + "repeater_commandSent": "命令已发送:{command}", "@repeater_commandSent": { "placeholders": { "command": { @@ -1066,7 +1066,7 @@ } } }, - "repeater_errorSendingCommand": "Error sending command: {error}", + "repeater_errorSendingCommand": "发送命令时出错:{error}", "@repeater_errorSendingCommand": { "placeholders": { "error": { @@ -1075,8 +1075,8 @@ } }, "repeater_confirm": "确认", - "repeater_settingsSaved": "设置已成功保存", - "repeater_errorSavingSettings": "Error saving settings: {error}", + "repeater_settingsSaved": "设置保存成功", + "repeater_errorSavingSettings": "保存设置时出错:{error}", "@repeater_errorSavingSettings": { "placeholders": { "error": { @@ -1084,15 +1084,15 @@ } } }, - "repeater_refreshBasicSettings": "重置基本设置", - "repeater_refreshRadioSettings": "重置收音机设置", - "repeater_refreshTxPower": "重置 TX 电源", - "repeater_refreshLocationSettings": "重置位置设置", + "repeater_refreshBasicSettings": "刷新基本设置", + "repeater_refreshRadioSettings": "刷新无线电设置", + "repeater_refreshTxPower": "刷新 TX 功率", + "repeater_refreshLocationSettings": "刷新位置设置", "repeater_refreshPacketForwarding": "刷新包转发", - "repeater_refreshGuestAccess": "重新获取访客访问权限", - "repeater_refreshPrivacyMode": "重置隐私模式", - "repeater_refreshAdvertisementSettings": "重置广告设置", - "repeater_refreshed": "{label} refreshed", + "repeater_refreshGuestAccess": "刷新访客权限", + "repeater_refreshPrivacyMode": "刷新隐私模式", + "repeater_refreshAdvertisementSettings": "刷新广播设置", + "repeater_refreshed": "{label} 已刷新", "@repeater_refreshed": { "placeholders": { "label": { @@ -1100,7 +1100,7 @@ } } }, - "repeater_errorRefreshing": "[保存:{label}]\n刷新 {label} 时出错", + "repeater_errorRefreshing": "刷新 {label} 时出错", "@repeater_errorRefreshing": { "placeholders": { "label": { @@ -1108,18 +1108,18 @@ } } }, - "repeater_cliTitle": "重复器命令行界面", + "repeater_cliTitle": "转发节点命令行", "repeater_debugNextCommand": "调试下一条命令", "repeater_commandHelp": "帮助", - "repeater_clearHistory": "清晰的历史", - "repeater_noCommandsSent": "尚未发送任何指令", - "repeater_typeCommandOrUseQuick": "在下方输入命令,或使用快捷命令。", + "repeater_clearHistory": "清除历史", + "repeater_noCommandsSent": "尚未发送命令", + "repeater_typeCommandOrUseQuick": "输入命令或使用快捷命令", "repeater_enterCommandHint": "输入命令...", - "repeater_previousCommand": "之前的命令", - "repeater_nextCommand": "下一个指令", - "repeater_enterCommandFirst": "首先输入一个命令", - "repeater_cliCommandFrameTitle": "CLI 命令框架", - "repeater_cliCommandError": "Error: {error}", + "repeater_previousCommand": "上一条命令", + "repeater_nextCommand": "下一条命令", + "repeater_enterCommandFirst": "请先输入命令", + "repeater_cliCommandFrameTitle": "CLI 命令帧", + "repeater_cliCommandError": "错误:{error}", "@repeater_cliCommandError": { "placeholders": { "error": { @@ -1127,81 +1127,81 @@ } } }, - "repeater_cliQuickGetName": "获取姓名", - "repeater_cliQuickGetRadio": "收听广播", + "repeater_cliQuickGetName": "获取名称", + "repeater_cliQuickGetRadio": "获取无线电设置", "repeater_cliQuickGetTx": "获取 TX", "repeater_cliQuickNeighbors": "邻居", "repeater_cliQuickVersion": "版本", - "repeater_cliQuickAdvertise": "发布广告", + "repeater_cliQuickAdvertise": "发送广播", "repeater_cliQuickClock": "时钟", - "repeater_cliHelpAdvert": "发送广告资料包", - "repeater_cliHelpReboot": "重置设备。 (请注意,您可能会收到“超时”错误,这是正常的现象)", - "repeater_cliHelpClock": "显示每个设备的当前时间。", - "repeater_cliHelpPassword": "为设备设置新的管理员密码。", - "repeater_cliHelpVersion": "显示设备版本和固件构建日期。", - "repeater_cliHelpClearStats": "重置各种统计指标,将其设置为零。", - "repeater_cliHelpSetAf": "设置时间因素。", - "repeater_cliHelpSetTx": "设置 LoRa 传输功率,单位为 dBm (相对于参考值)。 (重启以应用更改)", - "repeater_cliHelpSetRepeat": "启用或禁用此节点的重复器功能。", - "repeater_cliHelpSetAllowReadOnly": "(房间服务器)如果设置为“开启”,则允许使用空密码登录,但无法向房间发送消息(只能进行读取)。", - "repeater_cliHelpSetFloodMax": "设置最大传入数据包的跳数(如果大于或等于最大值,则不进行转发)。", - "repeater_cliHelpSetIntThresh": "设置干扰阈值(以dB为单位)。默认值为14。将设置为0以禁用频道干扰检测。", - "repeater_cliHelpSetAgcResetInterval": "设置间隔时间,用于重置自动增益控制器。设置为 0 以禁用。", - "repeater_cliHelpSetMultiAcks": "启用或禁用“双重确认”功能。", - "repeater_cliHelpSetAdvertInterval": "设置定时器间隔,单位为分钟,用于发送本地(无中继)的广告数据包。 将设置为 0 以禁用。", - "repeater_cliHelpSetFloodAdvertInterval": "设置定时器间隔时间为小时,以便发送广告信息包。将设置为 0 以禁用。", - "repeater_cliHelpSetGuestPassword": "设置/更新访客密码。 (对于访客,登录请求可以发送“获取统计”请求)", - "repeater_cliHelpSetName": "设置广告名称。", - "repeater_cliHelpSetLat": "设置广告地图的纬度。(以十进制表示)", - "repeater_cliHelpSetLon": "设置广告地图的经度。 (十进制度)", - "repeater_cliHelpSetRadio": "完全重新设置无线电参数,并保存到偏好设置。需要执行“重启”命令才能生效。", - "repeater_cliHelpSetRxDelay": "设置(实验性):设置一个基础值(必须大于1才能生效),用于对接收到的数据包进行轻微延迟处理,该延迟值基于信号强度/评分。将该值设置为0以禁用。", - "repeater_cliHelpSetTxDelay": "通过将一个因子与“浮动模式”数据包的时间在空中停留时间相乘,并结合随机的“时隙”系统,来延迟其转发,从而降低数据包冲突的概率。", - "repeater_cliHelpSetDirectTxDelay": "与txdelay相同,但用于对直接模式数据包的转发进行随机延迟。", - "repeater_cliHelpSetBridgeEnabled": "启用/禁用桥接。", - "repeater_cliHelpSetBridgeDelay": "在重新发送数据包之前,设置延迟时间。", - "repeater_cliHelpSetBridgeSource": "选择桥接器是否会转发收到的数据包,还是转发发送的数据包。", - "repeater_cliHelpSetBridgeBaud": "为 RS232 桥接设置串行链路的波特率。", - "repeater_cliHelpSetBridgeSecret": "设置 ESPNOW 桥的秘密。", - "repeater_cliHelpSetAdcMultiplier": "设置自定义因子,用于调整报告的电池电压(仅在特定板上支持)。", - "repeater_cliHelpTempRadio": "设置临时收音机参数,持续指定分钟数,之后恢复到原始收音机参数。(不保存到偏好设置)。", - "repeater_cliHelpSetPerm": "修改 ACL。如果 \"permissions\" 的值为 0,则删除与 pubkey 相关的条目。如果 pubkey-hex 完整且当前不在 ACL 中,则添加新的条目。通过匹配 pubkey 相关的前缀来更新条目。不同固件角色的权限位有所不同,但低 2 位分别对应:0 (访客)、1 (只读)、2 (读写)、3 (管理员)。", - "repeater_cliHelpGetBridgeType": "支持桥接模式、RS232、ESPNOW。", - "repeater_cliHelpLogStart": "开始将数据包记录到文件系统。", - "repeater_cliHelpLogStop": "停止将数据包记录写入文件系统。", - "repeater_cliHelpLogErase": "从文件系统中删除所有已记录的包信息。", - "repeater_cliHelpNeighbors": "显示了通过零跳广告收到的其他复用节点列表。 每行包含:id-前缀-十六进制:时间戳:信噪比(4次)", - "repeater_cliHelpNeighborRemove": "从邻居列表中删除第一个匹配项(通过十六进制的 pubkey 前缀)。", - "repeater_cliHelpRegion": "(仅限序列)列出所有已定义的区域以及当前的防洪许可。", - "repeater_cliHelpRegionLoad": "请注意:这是一个特殊的、包含多个命令的调用方式。 之后的每个命令都是一个区域名称(使用空格进行缩进,以表示父级关系,至少需要一个空格)。 结束方式是通过发送一个空行/命令。", - "repeater_cliHelpRegionGet": "搜索具有指定名称前缀的区域(或使用“*”表示全局范围)。 返回结果为“-> region-name (parent-name) 'F'”", - "repeater_cliHelpRegionPut": "添加或更新一个区域定义,并指定其名称。", - "repeater_cliHelpRegionRemove": "删除具有指定名称的区域定义。 (必须与指定名称完全匹配,且不能有子区域)", - "repeater_cliHelpRegionAllowf": "为指定区域设置“洪水”权限。(“*”表示全局/旧版本范围)", - "repeater_cliHelpRegionDenyf": "移除指定区域的“洪水”权限。(请注意:目前不建议在全局/旧版本中使用此功能!!)", - "repeater_cliHelpRegionHome": "回复当前“主区域”。(此功能尚未应用,仅供未来使用)", - "repeater_cliHelpRegionHomeSet": "设置“主”区域。", - "repeater_cliHelpRegionSave": "将区域列表/地图保存到存储中。", - "repeater_cliHelpGps": "显示 GPS 状态。当 GPS 处于关闭状态时,它只会显示“关闭”;当 GPS 处于开启状态时,它会显示“开启”、“状态”、“定位”、“卫星数量”等信息。", - "repeater_cliHelpGpsOnOff": "切换 GPS 设备的电源状态。", - "repeater_cliHelpGpsSync": "将节点时间与 GPS 钟同步。", - "repeater_cliHelpGpsSetLoc": "将节点的坐标设置为 GPS 坐标,并保存设置。", - "repeater_cliHelpGpsAdvert": "设置节点的位置广告配置:\n- none:不将位置信息包含在广告中\n- share:共享 GPS 位置(从 SensorManager 获取)\n- prefs:在偏好设置中展示的位置", - "repeater_cliHelpGpsAdvertSet": "设置广告的位置配置。", + "repeater_cliHelpAdvert": "发送广播包", + "repeater_cliHelpReboot": "重启设备。(注意:可能会收到超时错误,属于正常现象)", + "repeater_cliHelpClock": "显示设备当前时间", + "repeater_cliHelpPassword": "设置新的管理员密码", + "repeater_cliHelpVersion": "显示设备版本和固件构建日期", + "repeater_cliHelpClearStats": "重置各种统计数据", + "repeater_cliHelpSetAf": "设置时间因子", + "repeater_cliHelpSetTx": "设置 LoRa 发射功率 (dBm)(重启生效)", + "repeater_cliHelpSetRepeat": "启用或禁用此节点的转发功能", + "repeater_cliHelpSetAllowReadOnly": "(房间服务器)设为“开”则允许空密码登录,但只能读(不能发送)", + "repeater_cliHelpSetFloodMax": "设置最大传入数据包跳数(≥该值则不转发)", + "repeater_cliHelpSetIntThresh": "设置干扰阈值 (dB),默认14,设为0禁用", + "repeater_cliHelpSetAgcResetInterval": "设置 AGC 重置间隔(秒),设为0禁用", + "repeater_cliHelpSetMultiAcks": "启用或禁用“多重确认”功能", + "repeater_cliHelpSetAdvertInterval": "设置本地广播间隔(分钟),设为0禁用", + "repeater_cliHelpSetFloodAdvertInterval": "设置泛洪广播间隔(小时),设为0禁用", + "repeater_cliHelpSetGuestPassword": "设置/更新访客密码", + "repeater_cliHelpSetName": "设置广播名称", + "repeater_cliHelpSetLat": "设置广播纬度(十进制)", + "repeater_cliHelpSetLon": "设置广播经度(十进制)", + "repeater_cliHelpSetRadio": "完全重设无线电参数并保存,需重启生效", + "repeater_cliHelpSetRxDelay": "(实验性)设置接收延迟基数,设为0禁用", + "repeater_cliHelpSetTxDelay": "通过因子和随机时隙延迟泛洪数据包转发,降低冲突", + "repeater_cliHelpSetDirectTxDelay": "同 txdelay,用于直连模式数据包", + "repeater_cliHelpSetBridgeEnabled": "启用/禁用桥接", + "repeater_cliHelpSetBridgeDelay": "设置桥接转发延迟", + "repeater_cliHelpSetBridgeSource": "选择桥接器转发接收或发送的数据包", + "repeater_cliHelpSetBridgeBaud": "设置 RS232 桥接串口波特率", + "repeater_cliHelpSetBridgeSecret": "设置 ESPNOW 桥接密钥", + "repeater_cliHelpSetAdcMultiplier": "设置电池电压校正系数(特定板支持)", + "repeater_cliHelpTempRadio": "临时设置无线电参数指定分钟,之后恢复(不保存)", + "repeater_cliHelpSetPerm": "修改 ACL,权限位:0访客、1只读、2读写、3管理员", + "repeater_cliHelpGetBridgeType": "支持桥接模式:RS232、ESPNOW", + "repeater_cliHelpLogStart": "开始记录数据包到文件系统", + "repeater_cliHelpLogStop": "停止记录数据包", + "repeater_cliHelpLogErase": "删除所有记录的数据包", + "repeater_cliHelpNeighbors": "显示零跳广播收到的其他转发节点列表", + "repeater_cliHelpNeighborRemove": "从邻居列表删除第一个匹配项(通过公钥前缀)", + "repeater_cliHelpRegion": "(仅串口)列出所有定义区域及当前泛洪权限", + "repeater_cliHelpRegionLoad": "特殊多命令调用,以空行结束", + "repeater_cliHelpRegionGet": "搜索指定前缀的区域", + "repeater_cliHelpRegionPut": "添加或更新区域定义", + "repeater_cliHelpRegionRemove": "删除指定区域定义", + "repeater_cliHelpRegionAllowf": "为区域设置“泛洪”权限", + "repeater_cliHelpRegionDenyf": "移除区域的“泛洪”权限", + "repeater_cliHelpRegionHome": "返回当前“主区域”(预留)", + "repeater_cliHelpRegionHomeSet": "设置“主”区域", + "repeater_cliHelpRegionSave": "保存区域列表到存储", + "repeater_cliHelpGps": "显示 GPS 状态", + "repeater_cliHelpGpsOnOff": "切换 GPS 电源", + "repeater_cliHelpGpsSync": "将节点时间与 GPS 同步", + "repeater_cliHelpGpsSetLoc": "将节点坐标设为 GPS 坐标并保存", + "repeater_cliHelpGpsAdvert": "设置位置广播配置:none/share/prefs", + "repeater_cliHelpGpsAdvertSet": "设置广播位置配置", "repeater_commandsListTitle": "命令列表", - "repeater_commandsListNote": "请注意:对于各种“set ...”命令,也存在“get ...”命令。", + "repeater_commandsListNote": "注意:多数 set 命令也有对应的 get 命令", "repeater_general": "通用", "repeater_settingsCategory": "设置", - "repeater_bridge": "桥", - "repeater_logging": "记录", - "repeater_neighborsRepeaterOnly": "邻居(仅限重复功能)", - "repeater_regionManagementRepeaterOnly": "区域管理(仅限重复站点)", - "repeater_regionNote": "区域命令已引入,用于管理区域定义和权限。", + "repeater_bridge": "桥接", + "repeater_logging": "日志", + "repeater_neighborsRepeaterOnly": "邻居(仅转发节点)", + "repeater_regionManagementRepeaterOnly": "区域管理(仅转发节点)", + "repeater_regionNote": "区域命令用于管理区域定义和权限", "repeater_gpsManagement": "GPS 管理", - "repeater_gpsNote": "已引入 GPS 命令,用于管理与位置相关的任务。", + "repeater_gpsNote": "GPS 命令用于位置相关任务", "telemetry_receivedData": "接收到的遥测数据", - "telemetry_requestTimeout": "遥测请求超时。", - "telemetry_errorLoading": "Error loading telemetry: {error}", + "telemetry_requestTimeout": "遥测请求超时", + "telemetry_errorLoading": "加载遥测数据时出错:{error}", "@telemetry_errorLoading": { "placeholders": { "error": { @@ -1209,7 +1209,7 @@ } } }, - "telemetry_noData": "没有可用的 telemetry 数据。", + "telemetry_noData": "暂无遥测数据", "telemetry_channelTitle": "频道 {channel}", "@telemetry_channelTitle": { "placeholders": { @@ -1220,9 +1220,9 @@ }, "telemetry_batteryLabel": "电池", "telemetry_voltageLabel": "电压", - "telemetry_mcuTemperatureLabel": "MCU 的温度", + "telemetry_mcuTemperatureLabel": "MCU 温度", "telemetry_temperatureLabel": "温度", - "telemetry_currentLabel": "当前", + "telemetry_currentLabel": "电流", "telemetry_batteryValue": "{percent}% / {volts}V", "@telemetry_batteryValue": { "placeholders": { @@ -1261,9 +1261,9 @@ } } }, - "neighbors_receivedData": "已收到邻居信息", - "neighbors_requestTimedOut": "邻居要求停止干扰。", - "neighbors_errorLoading": "Error loading neighbors: {error}", + "neighbors_receivedData": "已接收邻居信息", + "neighbors_requestTimedOut": "邻居请求超时", + "neighbors_errorLoading": "加载邻居时出错:{error}", "@neighbors_errorLoading": { "placeholders": { "error": { @@ -1271,9 +1271,9 @@ } } }, - "neighbors_repeatersNeighbours": "重复使用的邻居", - "neighbors_noData": "没有可用的邻居信息。", - "neighbors_unknownContact": "Unknown {pubkey}", + "neighbors_repeatersNeighbours": "转发节点的邻居", + "neighbors_noData": "暂无邻居信息", + "neighbors_unknownContact": "未知 {pubkey}", "@neighbors_unknownContact": { "placeholders": { "pubkey": { @@ -1281,7 +1281,7 @@ } } }, - "neighbors_heardAgo": "Heard: {time} ago", + "neighbors_heardAgo": "听到:{time}前", "@neighbors_heardAgo": { "placeholders": { "time": { @@ -1292,15 +1292,15 @@ "channelPath_title": "数据包路径", "channelPath_viewMap": "查看地图", "channelPath_otherObservedPaths": "其他观察到的路径", - "channelPath_repeaterHops": "复用跳跃", - "channelPath_noHopDetails": "对于此包,未提供详细信息。", + "channelPath_repeaterHops": "转发节点跳数", + "channelPath_noHopDetails": "此数据包未提供详细信息", "channelPath_messageDetails": "消息详情", - "channelPath_senderLabel": "发件人", + "channelPath_senderLabel": "发送者", "channelPath_timeLabel": "时间", "channelPath_repeatsLabel": "重复", "channelPath_pathLabel": "路径 {index}", "channelPath_observedLabel": "观察到的", - "channelPath_observedPathTitle": "Observed path {index} • {hops}", + "channelPath_observedPathTitle": "观察到的路径 {index} • {hops}", "@channelPath_observedPathTitle": { "placeholders": { "index": { @@ -1311,7 +1311,7 @@ } } }, - "channelPath_noLocationData": "没有位置信息", + "channelPath_noLocationData": "无位置信息", "channelPath_timeWithDate": "{day}/{month} {time}", "@channelPath_timeWithDate": { "placeholders": { @@ -1335,9 +1335,9 @@ } }, "channelPath_unknownPath": "未知", - "channelPath_floodPath": "洪水", - "channelPath_directPath": "直接", - "channelPath_observedZeroOf": "0 of {total} hops", + "channelPath_floodPath": "泛洪", + "channelPath_directPath": "直连", + "channelPath_observedZeroOf": "0 / {total} 跳", "@channelPath_observedZeroOf": { "placeholders": { "total": { @@ -1345,7 +1345,7 @@ } } }, - "channelPath_observedSomeOf": "{observed} of {total} hops", + "channelPath_observedSomeOf": "{observed} / {total} 跳", "@channelPath_observedSomeOf": { "placeholders": { "observed": { @@ -1356,9 +1356,9 @@ } } }, - "channelPath_mapTitle": "路线图", - "channelPath_noRepeaterLocations": "这条路径上没有可用的中继器位置。", - "channelPath_primaryPath": "路径 {index} (主要路径)", + "channelPath_mapTitle": "路径地图", + "channelPath_noRepeaterLocations": "此路径上没有可用的转发节点位置信息", + "channelPath_primaryPath": "路径 {index}(主要)", "@channelPath_primaryPath": { "placeholders": { "index": { @@ -1374,7 +1374,7 @@ } }, "channelPath_pathLabelTitle": "路径", - "channelPath_observedPathHeader": "观察路径", + "channelPath_observedPathHeader": "观察到的路径", "channelPath_selectedPathLabel": "{label} • {prefixes}", "@channelPath_selectedPathLabel": { "placeholders": { @@ -1386,14 +1386,14 @@ } } }, - "channelPath_noHopDetailsAvailable": "对于此包裹,尚无详细信息。", - "channelPath_unknownRepeater": "未知的重复设备", + "channelPath_noHopDetailsAvailable": "此数据包暂无详细信息", + "channelPath_unknownRepeater": "未知转发节点", "community_title": "社区", - "community_create": "建立社区", - "community_createDesc": "创建一个新的社群,并通过二维码进行分享。", + "community_create": "创建社区", + "community_createDesc": "创建新社区并通过二维码分享。", "community_join": "加入", "community_joinTitle": "加入社区", - "community_joinConfirmation": "Do you want to join the community \"{name}\"?", + "community_joinConfirmation": "是否加入社区 \"{name}\"?", "@community_joinConfirmation": { "placeholders": { "name": { @@ -1402,13 +1402,13 @@ } }, "community_scanQr": "扫描社区二维码", - "community_scanInstructions": "将相机对准社区的二维码。", + "community_scanInstructions": "将摄像头对准社区的二维码", "community_showQr": "显示二维码", - "community_publicChannel": "社区公共", - "community_hashtagChannel": "社区标签", + "community_publicChannel": "社区公共频道", + "community_hashtagChannel": "社区标签频道", "community_name": "社区名称", "community_enterName": "请输入社区名称", - "community_created": "Community \"{name}\" created", + "community_created": "社区 \"{name}\" 已创建", "@community_created": { "placeholders": { "name": { @@ -1416,7 +1416,7 @@ } } }, - "community_joined": "Joined community \"{name}\"", + "community_joined": "已加入社区 \"{name}\"", "@community_joined": { "placeholders": { "name": { @@ -1425,7 +1425,7 @@ } }, "community_qrTitle": "分享社区", - "community_qrInstructions": "Scan this QR code to join \"{name}\"", + "community_qrInstructions": "扫描此二维码加入 \"{name}\"", "@community_qrInstructions": { "placeholders": { "name": { @@ -1433,10 +1433,10 @@ } } }, - "community_hashtagPrivacyHint": "仅社区成员才能加入社区话题标签的频道。", + "community_hashtagPrivacyHint": "仅社区成员可加入社区标签频道。", "community_invalidQrCode": "无效的社区二维码", - "community_alreadyMember": "已经是会员", - "community_alreadyMemberMessage": "You are already a member of \"{name}\".", + "community_alreadyMember": "已是成员", + "community_alreadyMemberMessage": "您已是 \"{name}\" 的成员。", "@community_alreadyMemberMessage": { "placeholders": { "name": { @@ -1445,12 +1445,12 @@ } }, "community_addPublicChannel": "添加公共频道", - "community_addPublicChannelHint": "自动添加该社区的公共频道", - "community_noCommunities": "目前还没有任何社区加入。", - "community_scanOrCreate": "扫描二维码或创建社群,即可开始。", + "community_addPublicChannelHint": "自动添加此社区的公共频道", + "community_noCommunities": "尚未加入任何社区。", + "community_scanOrCreate": "扫描二维码或创建社区以开始。", "community_manageCommunities": "管理社区", "community_delete": "退出社区", - "community_deleteConfirm": "是否要删除\"{name}\"?", + "community_deleteConfirm": "是否退出 \"{name}\"?", "@community_deleteConfirm": { "placeholders": { "name": { @@ -1466,7 +1466,7 @@ } } }, - "community_deleted": "Left community \"{name}\"", + "community_deleted": "已退出社区 \"{name}\"", "@community_deleted": { "placeholders": { "name": { @@ -1474,8 +1474,8 @@ } } }, - "community_regenerateSecret": "恢复秘密", - "community_regenerateSecretConfirm": "[保存:{name}]\n是否需要重新生成\"{name}\"的密钥?所有成员都需要扫描新的二维码才能继续进行通信。", + "community_regenerateSecret": "重新生成密钥", + "community_regenerateSecretConfirm": "是否为 \"{name}\" 重新生成密钥?所有成员需扫描新的二维码才能继续通信。", "@community_regenerateSecretConfirm": { "placeholders": { "name": { @@ -1483,8 +1483,8 @@ } } }, - "community_regenerate": "再生", - "community_secretRegenerated": "[保护对象:{name}]\n秘密已恢复至\"{name}\"", + "community_regenerate": "重新生成", + "community_secretRegenerated": "已为 \"{name}\" 重新生成密钥", "@community_secretRegenerated": { "placeholders": { "name": { @@ -1492,8 +1492,8 @@ } } }, - "community_updateSecret": "更新秘密", - "community_secretUpdated": "“{name}”的秘密已更新", + "community_updateSecret": "更新密钥", + "community_secretUpdated": "“{name}”的密钥已更新", "@community_secretUpdated": { "placeholders": { "name": { @@ -1501,7 +1501,7 @@ } } }, - "community_scanToUpdateSecret": "Scan the new QR code to update the secret for \"{name}\"", + "community_scanToUpdateSecret": "扫描新二维码以更新 \"{name}\" 的密钥", "@community_scanToUpdateSecret": { "placeholders": { "name": { @@ -1509,14 +1509,14 @@ } } }, - "community_addHashtagChannel": "添加社区标签", - "community_addHashtagChannelDesc": "为这个社区创建一个带有话题标签的频道", + "community_addHashtagChannel": "添加标签频道", + "community_addHashtagChannelDesc": "为此社区创建标签频道", "community_selectCommunity": "选择社区", - "community_regularHashtag": "常用标签", - "community_regularHashtagDesc": "公共话题标签(任何人都可以参与)", + "community_regularHashtag": "普通标签", + "community_regularHashtagDesc": "公共标签频道(任何人都可参与)", "community_communityHashtag": "社区标签", "community_communityHashtagDesc": "仅限社区成员", - "community_forCommunity": "For {name}", + "community_forCommunity": "为 {name}", "@community_forCommunity": { "placeholders": { "name": { @@ -1524,30 +1524,30 @@ } } }, - "listFilter_tooltip": "筛选和排序", - "listFilter_sortBy": "按排序", + "listFilter_tooltip": "筛选与排序", + "listFilter_sortBy": "排序方式", "listFilter_latestMessages": "最新消息", - "listFilter_heardRecently": "最近听到的", - "listFilter_az": "A 到 Z", - "listFilter_filters": "过滤器", + "listFilter_heardRecently": "最近听到", + "listFilter_az": "A-Z", + "listFilter_filters": "筛选", "listFilter_all": "全部", "listFilter_users": "用户", - "listFilter_repeaters": "重复器", + "listFilter_repeaters": "转发节点", "listFilter_roomServers": "房间服务器", - "listFilter_unreadOnly": "仅显示未读消息", - "listFilter_newGroup": "新的团体", - "pathTrace_you": "您", + "listFilter_unreadOnly": "仅显示未读", + "listFilter_newGroup": "新建群聊", + "pathTrace_you": "我自己", "pathTrace_failed": "路径追踪失败。", "pathTrace_notAvailable": "无法获取路径信息。", - "pathTrace_refreshTooltip": "重新绘制路径。", + "pathTrace_refreshTooltip": "刷新路径追踪", "contacts_pathTrace": "路径追踪", - "contacts_ping": "乒", - "contacts_repeaterPathTrace": "追踪路径至中继器", - "contacts_repeaterPing": "中继器", - "contacts_roomPathTrace": "追踪到房间服务器", - "contacts_roomPing": "会议室服务器", - "contacts_chatTraceRoute": "路径跟踪路线", - "contacts_pathTraceTo": "追踪路径至 {name}", + "contacts_ping": "Ping", + "contacts_repeaterPathTrace": "Trace 转发节点", + "contacts_repeaterPing": "Ping 转发节点", + "contacts_roomPathTrace": "Trace 房间服务器", + "contacts_roomPing": "Ping 房间服务器", + "contacts_chatTraceRoute": "路由追踪", + "contacts_pathTraceTo": "追踪至 {name} 的路径", "@contacts_pathTraceTo": { "placeholders": { "name": { @@ -1555,48 +1555,48 @@ } } }, - "contacts_clipboardEmpty": "剪贴板为空。", - "contacts_invalidAdvertFormat": "无效的联系信息", - "contacts_contactImported": "已建立联系。", - "contacts_contactImportFailed": "未能导入联系人。", - "contacts_zeroHopAdvert": "零跳广告", - "contacts_floodAdvert": "防洪广告", - "contacts_copyAdvertToClipboard": "复制广告到剪贴板", + "contacts_clipboardEmpty": "剪贴板为空", + "contacts_invalidAdvertFormat": "无效的联系人信息格式", + "contacts_contactImported": "联系人已导入", + "contacts_contactImportFailed": "导入联系人失败。", + "contacts_zeroHopAdvert": "发送零跳广播", + "contacts_floodAdvert": "发送泛洪广播", + "contacts_copyAdvertToClipboard": "复制广播到剪贴板", "contacts_addContactFromClipboard": "从剪贴板添加联系人", - "contacts_ShareContact": "复制联系方式到剪贴板", - "contacts_ShareContactZeroHop": "通过广告分享联系方式", - "contacts_zeroHopContactAdvertSent": "通过广告获取联系方式。", - "contacts_zeroHopContactAdvertFailed": "发送联系方式失败。", - "contacts_contactAdvertCopied": "广告内容已复制到剪贴板。", - "contacts_contactAdvertCopyFailed": "将广告复制到剪贴板操作失败。", + "contacts_ShareContact": "复制联系人信息到剪贴板", + "contacts_ShareContactZeroHop": "通过广播分享联系人", + "contacts_zeroHopContactAdvertSent": "零跳广播已发送", + "contacts_zeroHopContactAdvertFailed": "发送联系人广播失败。", + "contacts_contactAdvertCopied": "广播已复制到剪贴板。", + "contacts_contactAdvertCopyFailed": "复制广播到剪贴板失败。", "notification_activityTitle": "MeshCore 活动", "notification_messagesCount": "{count} 条消息", "notification_channelMessagesCount": "{count} 条频道消息", "notification_newNodesCount": "{count} 个新节点", "notification_newTypeDiscovered": "发现新 {contactType}", "notification_receivedNewMessage": "收到新消息", - "settings_gpxExportRepeaters": "导出重复器/房间服务器到GPX", - "settings_gpxExportRepeatersSubtitle": "导出带有位置的重复器/房间服务器到GPX文件。", - "settings_gpxExportContactsSubtitle": "导出带有位置的伙伴到GPX文件。", + "settings_gpxExportRepeaters": "导出转发节点/房间服务器到 GPX", + "settings_gpxExportRepeatersSubtitle": "导出带位置的转发节点/房间服务器到 GPX 文件", + "settings_gpxExportContactsSubtitle": "导出带位置的伙伴到 GPX 文件", "settings_gpxExportNotAvailable": "您的设备/操作系统不支持", - "settings_gpxExportSuccess": "成功导出GPX文件", - "settings_gpxExportError": "导出时发生错误", - "settings_gpxExportRepeatersRoom": "重复器和房间服务器位置", - "settings_gpxExportChat": "伴侣位置", - "settings_gpxExportAll": "导出所有联系人到GPX", - "settings_gpxExportContacts": "导出伴侣到GPX", - "settings_gpxExportAllSubtitle": "导出所有带有位置的联系人到GPX文件。", + "settings_gpxExportSuccess": "GPX 文件导出成功", + "settings_gpxExportError": "导出时出错", + "settings_gpxExportRepeatersRoom": "转发节点与房间服务器位置", + "settings_gpxExportChat": "伙伴位置", + "settings_gpxExportAll": "导出所有联系人到 GPX", + "settings_gpxExportContacts": "导出伙伴到 GPX", + "settings_gpxExportAllSubtitle": "导出所有带位置的联系人到 GPX 文件", "settings_gpxExportAllContacts": "所有联系人位置", - "settings_gpxExportNoContacts": "没有联系人可导出", - "settings_gpxExportShareText": "来自meshcore-open的导出地图数据", - "settings_gpxExportShareSubject": "meshcore-open GPX 地图数据导出", - "pathTrace_someHopsNoLocation": "其中一个或多个啤酒花缺少位置!", - "map_tapToAdd": "点击节点将其添加到路径中", + "settings_gpxExportNoContacts": "没有可导出的联系人", + "settings_gpxExportShareText": "来自 MeshCore Open 的地图数据导出", + "settings_gpxExportShareSubject": "MeshCore Open GPX 地图数据导出", + "pathTrace_someHopsNoLocation": "某些跳缺少位置信息!", + "map_tapToAdd": "点击节点以添加到路径", "pathTrace_clearTooltip": "清除路径", - "map_pathTraceCancelled": "路径跟踪已取消", - "map_removeLast": "删除最后一个", - "map_runTrace": "运行路径跟踪", - "scanner_bluetoothOffMessage": "请打开蓝牙功能,以便搜索设备。", + "map_pathTraceCancelled": "路径追踪已取消", + "map_removeLast": "移除最后一个", + "map_runTrace": "运行路径追踪", + "scanner_bluetoothOffMessage": "请开启蓝牙以搜索设备", "scanner_bluetoothOff": "蓝牙已关闭", "scanner_enableBluetooth": "启用蓝牙" } From 096e0a4184b5e5e8fb5907ab38cbb13f4e4f4630 Mon Sep 17 00:00:00 2001 From: Ben Allfree Date: Sun, 22 Feb 2026 09:16:07 -0800 Subject: [PATCH 02/10] fix: return cursor to message window after send --- lib/screens/channel_chat_screen.dart | 1 + lib/screens/chat_screen.dart | 1 + lib/screens/repeater_cli_screen.dart | 1 + 3 files changed, 3 insertions(+) diff --git a/lib/screens/channel_chat_screen.dart b/lib/screens/channel_chat_screen.dart index bf05110..9f40684 100644 --- a/lib/screens/channel_chat_screen.dart +++ b/lib/screens/channel_chat_screen.dart @@ -935,6 +935,7 @@ class _ChannelChatScreenState extends State { connector.sendChannelMessage(widget.channel, messageText); _textController.clear(); _cancelReply(); + _textFieldFocusNode.requestFocus(); } String _formatTime(DateTime time) { diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart index ad897a0..ea657ff 100644 --- a/lib/screens/chat_screen.dart +++ b/lib/screens/chat_screen.dart @@ -429,6 +429,7 @@ class _ChatScreenState extends State { connector.sendMessage(widget.contact, text); _textController.clear(); + _textFieldFocusNode.requestFocus(); } void _showPathHistory(BuildContext context) { diff --git a/lib/screens/repeater_cli_screen.dart b/lib/screens/repeater_cli_screen.dart index abfb06a..1c7ff43 100644 --- a/lib/screens/repeater_cli_screen.dart +++ b/lib/screens/repeater_cli_screen.dart @@ -168,6 +168,7 @@ class _RepeaterCliScreenState extends State { _commandController.clear(); _historyIndex = -1; + _commandFocusNode.requestFocus(); // Auto-scroll to bottom Future.delayed(const Duration(milliseconds: 100), () { From 3ca53e967c5d39ef496ec5bbda39ba6ec4ad2784 Mon Sep 17 00:00:00 2001 From: Ben Allfree Date: Sun, 22 Feb 2026 09:20:20 -0800 Subject: [PATCH 03/10] fix: to send giphy --- lib/screens/channel_chat_screen.dart | 59 +++++++++++++++++----------- lib/screens/chat_screen.dart | 55 ++++++++++++++++---------- 2 files changed, 72 insertions(+), 42 deletions(-) diff --git a/lib/screens/channel_chat_screen.dart b/lib/screens/channel_chat_screen.dart index bf05110..9fecdc7 100644 --- a/lib/screens/channel_chat_screen.dart +++ b/lib/screens/channel_chat_screen.dart @@ -849,30 +849,45 @@ class _ChannelChatScreenState extends State { builder: (context, value, child) { final gifId = _parseGifId(value.text); if (gifId != null) { - return Row( - children: [ - Expanded( - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: GifMessage( - url: - 'https://media.giphy.com/media/$gifId/giphy.gif', - backgroundColor: Theme.of( - context, - ).colorScheme.surfaceContainerHighest, - fallbackTextColor: Theme.of( - context, - ).colorScheme.onSurface.withValues(alpha: 0.6), - maxSize: 160, + return Focus( + autofocus: true, + onKeyEvent: (node, event) { + if (event is KeyDownEvent && + (event.logicalKey == LogicalKeyboardKey.enter || + event.logicalKey == LogicalKeyboardKey.numpadEnter)) { + _sendMessage(); + return KeyEventResult.handled; + } + return KeyEventResult.ignored; + }, + child: Row( + children: [ + Expanded( + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: GifMessage( + url: + 'https://media.giphy.com/media/$gifId/giphy.gif', + backgroundColor: Theme.of( + context, + ).colorScheme.surfaceContainerHighest, + fallbackTextColor: Theme.of( + context, + ).colorScheme.onSurface.withValues(alpha: 0.6), + maxSize: 160, + ), ), ), - ), - const SizedBox(width: 8), - IconButton( - icon: const Icon(Icons.close), - onPressed: () => _textController.clear(), - ), - ], + const SizedBox(width: 8), + IconButton( + icon: const Icon(Icons.close), + onPressed: () { + _textController.clear(); + _textFieldFocusNode.requestFocus(); + }, + ), + ], + ), ); } diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart index ad897a0..c5cd4c6 100644 --- a/lib/screens/chat_screen.dart +++ b/lib/screens/chat_screen.dart @@ -340,28 +340,43 @@ class _ChatScreenState extends State { builder: (context, value, child) { final gifId = _parseGifId(value.text); if (gifId != null) { - return Row( - children: [ - Expanded( - child: ClipRRect( - borderRadius: BorderRadius.circular(12), - child: GifMessage( - url: - 'https://media.giphy.com/media/$gifId/giphy.gif', - backgroundColor: - colorScheme.surfaceContainerHighest, - fallbackTextColor: colorScheme.onSurface - .withValues(alpha: 0.6), - maxSize: 160, + return Focus( + autofocus: true, + onKeyEvent: (node, event) { + if (event is KeyDownEvent && + (event.logicalKey == LogicalKeyboardKey.enter || + event.logicalKey == LogicalKeyboardKey.numpadEnter)) { + _sendMessage(connector); + return KeyEventResult.handled; + } + return KeyEventResult.ignored; + }, + child: Row( + children: [ + Expanded( + child: ClipRRect( + borderRadius: BorderRadius.circular(12), + child: GifMessage( + url: + 'https://media.giphy.com/media/$gifId/giphy.gif', + backgroundColor: + colorScheme.surfaceContainerHighest, + fallbackTextColor: colorScheme.onSurface + .withValues(alpha: 0.6), + maxSize: 160, + ), ), ), - ), - const SizedBox(width: 8), - IconButton( - icon: const Icon(Icons.close), - onPressed: () => _textController.clear(), - ), - ], + const SizedBox(width: 8), + IconButton( + icon: const Icon(Icons.close), + onPressed: () { + _textController.clear(); + _textFieldFocusNode.requestFocus(); + }, + ), + ], + ), ); } From d269e181c38d01c017d6bbeb9098bf4e3b6d7164 Mon Sep 17 00:00:00 2001 From: Ben Allfree Date: Sun, 22 Feb 2026 11:34:18 -0800 Subject: [PATCH 04/10] formatting fix --- lib/screens/channel_chat_screen.dart | 10 ++++++---- lib/screens/chat_screen.dart | 3 ++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/lib/screens/channel_chat_screen.dart b/lib/screens/channel_chat_screen.dart index 9fecdc7..5173852 100644 --- a/lib/screens/channel_chat_screen.dart +++ b/lib/screens/channel_chat_screen.dart @@ -854,7 +854,8 @@ class _ChannelChatScreenState extends State { onKeyEvent: (node, event) { if (event is KeyDownEvent && (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.numpadEnter)) { + event.logicalKey == + LogicalKeyboardKey.numpadEnter)) { _sendMessage(); return KeyEventResult.handled; } @@ -871,9 +872,10 @@ class _ChannelChatScreenState extends State { backgroundColor: Theme.of( context, ).colorScheme.surfaceContainerHighest, - fallbackTextColor: Theme.of( - context, - ).colorScheme.onSurface.withValues(alpha: 0.6), + fallbackTextColor: Theme.of(context) + .colorScheme + .onSurface + .withValues(alpha: 0.6), maxSize: 160, ), ), diff --git a/lib/screens/chat_screen.dart b/lib/screens/chat_screen.dart index c5cd4c6..fb31c00 100644 --- a/lib/screens/chat_screen.dart +++ b/lib/screens/chat_screen.dart @@ -345,7 +345,8 @@ class _ChatScreenState extends State { onKeyEvent: (node, event) { if (event is KeyDownEvent && (event.logicalKey == LogicalKeyboardKey.enter || - event.logicalKey == LogicalKeyboardKey.numpadEnter)) { + event.logicalKey == + LogicalKeyboardKey.numpadEnter)) { _sendMessage(connector); return KeyEventResult.handled; } From 5a70ed48cf3e1143f0263140b8320408522a8166 Mon Sep 17 00:00:00 2001 From: ericz Date: Tue, 24 Feb 2026 23:56:30 +0100 Subject: [PATCH 05/10] favorites handling only --- .github/workflows/build.yml | 5 ++ lib/connector/meshcore_connector.dart | 68 +++++++++++++++++++ lib/connector/meshcore_protocol.dart | 1 + lib/l10n/app_de.arb | 1 + lib/l10n/app_en.arb | 3 +- lib/l10n/app_localizations.dart | 6 ++ lib/l10n/app_localizations_bg.dart | 3 + lib/l10n/app_localizations_de.dart | 3 + lib/l10n/app_localizations_en.dart | 3 + lib/l10n/app_localizations_es.dart | 3 + lib/l10n/app_localizations_fr.dart | 3 + lib/l10n/app_localizations_it.dart | 3 + lib/l10n/app_localizations_nl.dart | 3 + lib/l10n/app_localizations_pl.dart | 3 + lib/l10n/app_localizations_pt.dart | 3 + lib/l10n/app_localizations_ru.dart | 3 + lib/l10n/app_localizations_sk.dart | 3 + lib/l10n/app_localizations_sl.dart | 3 + lib/l10n/app_localizations_sv.dart | 3 + lib/l10n/app_localizations_uk.dart | 3 + lib/l10n/app_localizations_zh.dart | 3 + lib/models/contact.dart | 7 ++ lib/screens/contacts_screen.dart | 26 +++++++ lib/storage/contact_store.dart | 2 + lib/widgets/list_filter_widget.dart | 21 ++++-- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + untranslated.json | 54 ++++++++++++++- 27 files changed, 233 insertions(+), 8 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 05c82de..c376a4a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,6 +30,11 @@ jobs: ${{ runner.os }}-gradle- - run: flutter pub get - run: flutter build apk --release --no-pub + - name: Upload Debug APK + uses: actions/upload-artifact@v4 + with: + name: app-debug + path: build/app/outputs/flutter-apk/app-release.apk ios: runs-on: macos-latest diff --git a/lib/connector/meshcore_connector.dart b/lib/connector/meshcore_connector.dart index afd1626..ef19f02 100644 --- a/lib/connector/meshcore_connector.dart +++ b/lib/connector/meshcore_connector.dart @@ -669,6 +669,7 @@ class MeshCoreConnector extends ChangeNotifier { publicKey: contact.publicKey, name: contact.name, type: contact.type, + flags: contact.flags, pathLength: selection.hopCount >= 0 ? selection.hopCount : contact.pathLength, @@ -1185,11 +1186,78 @@ class MeshCoreConnector extends ChangeNotifier { customPath, pathLen, type: contact.type, + flags: contact.flags, name: contact.name, ), ); } + Future setContactFavorite(Contact contact, bool isFavorite) async { + if (!isConnected) return; + final latestContact = + await _fetchContactSnapshotFromDevice(contact.publicKey) ?? contact; + final updatedFlags = isFavorite + ? (latestContact.flags | contactFlagFavorite) + : (latestContact.flags & ~contactFlagFavorite); + + await sendFrame( + buildUpdateContactPathFrame( + latestContact.publicKey, + latestContact.path, + latestContact.pathLength, + type: latestContact.type, + flags: updatedFlags, + name: latestContact.name, + ), + ); + + final index = _contacts.indexWhere( + (c) => c.publicKeyHex == contact.publicKeyHex, + ); + if (index >= 0) { + _contacts[index] = _contacts[index].copyWith( + type: latestContact.type, + name: latestContact.name, + pathLength: latestContact.pathLength, + path: latestContact.path, + flags: updatedFlags, + ); + notifyListeners(); + unawaited(_persistContacts()); + } + } + + Future _fetchContactSnapshotFromDevice( + Uint8List pubKey, { + Duration timeout = const Duration(seconds: 3), + }) async { + if (!isConnected) return null; + final expectedKeyHex = pubKeyToHex(pubKey); + final completer = Completer(); + + void finish(Contact? result) { + if (!completer.isCompleted) { + completer.complete(result); + } + } + + final subscription = receivedFrames.listen((frame) { + if (frame.isEmpty || frame[0] != respCodeContact) return; + final parsed = Contact.fromFrame(frame); + if (parsed == null || parsed.publicKeyHex != expectedKeyHex) return; + finish(parsed); + }); + + final timer = Timer(timeout, () => finish(null)); + try { + await getContactByKey(pubKey); + return await completer.future; + } finally { + timer.cancel(); + await subscription.cancel(); + } + } + /// Set path override for a contact (persists across contact refreshes) /// pathLen: -1 = force flood, null = auto (use device path), >= 0 = specific path Future setPathOverride( diff --git a/lib/connector/meshcore_protocol.dart b/lib/connector/meshcore_protocol.dart index 2933e80..d5ce9ee 100644 --- a/lib/connector/meshcore_protocol.dart +++ b/lib/connector/meshcore_protocol.dart @@ -290,6 +290,7 @@ int _minPositive(int a, int b) { const int contactPubKeyOffset = 1; const int contactTypeOffset = 33; const int contactFlagsOffset = 34; +const int contactFlagFavorite = 0x01; const int contactPathLenOffset = 35; const int contactPathOffset = 36; const int contactNameOffset = 100; diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index a1647fa..f596ae4 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1343,6 +1343,7 @@ "listFilter_az": "A-Z", "listFilter_filters": "Filtere", "listFilter_all": "Alle", + "listFilter_favorites": "Favoriten", "listFilter_users": "Benutzer", "listFilter_repeaters": "Repeater", "listFilter_roomServers": "Raumserver", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index eec03bc..5b15b65 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1555,6 +1555,7 @@ "listFilter_az": "A-Z", "listFilter_filters": "Filters", "listFilter_all": "All", + "listFilter_favorites": "Favorites", "listFilter_users": "Users", "listFilter_repeaters": "Repeaters", "listFilter_roomServers": "Room servers", @@ -1779,4 +1780,4 @@ "settings_gpxExportShareSubject": "meshcore-open GPX map data export", "snrIndicator_nearByRepeaters": "Nearby Repeaters", "snrIndicator_lastSeen": "Last seen" -} \ No newline at end of file +} diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 54e9cdc..5d6a6a2 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -4772,6 +4772,12 @@ abstract class AppLocalizations { /// **'All'** String get listFilter_all; + /// No description provided for @listFilter_favorites. + /// + /// In en, this message translates to: + /// **'Favorites'** + String get listFilter_favorites; + /// No description provided for @listFilter_users. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 21a6e79..513cdc3 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -2728,6 +2728,9 @@ class AppLocalizationsBg extends AppLocalizations { @override String get listFilter_all => 'Всички'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Потребители'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index e5a3a49..bada9f6 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -2733,6 +2733,9 @@ class AppLocalizationsDe extends AppLocalizations { @override String get listFilter_all => 'Alle'; + @override + String get listFilter_favorites => 'Favoriten'; + @override String get listFilter_users => 'Benutzer'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index a56e217..b090c45 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -2686,6 +2686,9 @@ class AppLocalizationsEn extends AppLocalizations { @override String get listFilter_all => 'All'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Users'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index 98cd658..ac51330 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -2726,6 +2726,9 @@ class AppLocalizationsEs extends AppLocalizations { @override String get listFilter_all => 'Todas'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Usuarios'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index a52ff00..3ca86e6 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -2742,6 +2742,9 @@ class AppLocalizationsFr extends AppLocalizations { @override String get listFilter_all => 'Tout'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Utilisateurs'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index aebea2f..c9900c7 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -2726,6 +2726,9 @@ class AppLocalizationsIt extends AppLocalizations { @override String get listFilter_all => 'Tutti'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Utenti'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 5460d29..8c537f2 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -2717,6 +2717,9 @@ class AppLocalizationsNl extends AppLocalizations { @override String get listFilter_all => 'Alles'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Gebruikers'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 7286033..2c11c82 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -2724,6 +2724,9 @@ class AppLocalizationsPl extends AppLocalizations { @override String get listFilter_all => 'Wszystko'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Użytkownicy'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index 025c81c..c2fac6c 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -2727,6 +2727,9 @@ class AppLocalizationsPt extends AppLocalizations { @override String get listFilter_all => 'Tudo'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Usuários'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 399b158..9fde3b8 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -2730,6 +2730,9 @@ class AppLocalizationsRu extends AppLocalizations { @override String get listFilter_all => 'Все'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Пользователи'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 5138311..5d31462 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -2712,6 +2712,9 @@ class AppLocalizationsSk extends AppLocalizations { @override String get listFilter_all => 'Všetko'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Používatelia'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index f42e8e0..19934e8 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -2715,6 +2715,9 @@ class AppLocalizationsSl extends AppLocalizations { @override String get listFilter_all => 'Vse'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Uporabniki'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index ba99455..04ae835 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -2700,6 +2700,9 @@ class AppLocalizationsSv extends AppLocalizations { @override String get listFilter_all => 'Alla'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Användare'; diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index e2bbbe8..1c3442d 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -2737,6 +2737,9 @@ class AppLocalizationsUk extends AppLocalizations { @override String get listFilter_all => 'Все'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => 'Користувачі'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 4da17ea..6a9881e 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -2582,6 +2582,9 @@ class AppLocalizationsZh extends AppLocalizations { @override String get listFilter_all => '全部'; + @override + String get listFilter_favorites => 'Favorites'; + @override String get listFilter_users => '用户'; diff --git a/lib/models/contact.dart b/lib/models/contact.dart index 143a62a..5e532e6 100644 --- a/lib/models/contact.dart +++ b/lib/models/contact.dart @@ -5,6 +5,7 @@ class Contact { final Uint8List publicKey; final String name; final int type; + final int flags; final int pathLength; // -1 = flood, 0+ = direct hops (from device) final Uint8List path; // Path bytes from device final int? @@ -19,6 +20,7 @@ class Contact { required this.publicKey, required this.name, required this.type, + this.flags = 0, required this.pathLength, required this.path, this.pathOverride, @@ -58,11 +60,13 @@ class Contact { } bool get hasLocation => latitude != null && longitude != null; + bool get isFavorite => (flags & contactFlagFavorite) != 0; Contact copyWith({ Uint8List? publicKey, String? name, int? type, + int? flags, int? pathLength, Uint8List? path, int? pathOverride, @@ -77,6 +81,7 @@ class Contact { publicKey: publicKey ?? this.publicKey, name: name ?? this.name, type: type ?? this.type, + flags: flags ?? this.flags, pathLength: pathLength ?? this.pathLength, path: path ?? this.path, pathOverride: clearPathOverride @@ -167,6 +172,7 @@ class Contact { data.sublist(contactPubKeyOffset, contactPubKeyOffset + pubKeySize), ); final type = data[contactTypeOffset]; + final flags = data[contactFlagsOffset]; final pathLen = data[contactPathLenOffset].toSigned(8); final safePathLen = pathLen > 0 ? (pathLen > maxPathSize ? maxPathSize : pathLen) @@ -191,6 +197,7 @@ class Contact { publicKey: pubKey, name: name.isEmpty ? 'Unknown' : name, type: type, + flags: flags, pathLength: pathLen, path: pathBytes, latitude: lat, diff --git a/lib/screens/contacts_screen.dart b/lib/screens/contacts_screen.dart index c3f783c..08e3e14 100644 --- a/lib/screens/contacts_screen.dart +++ b/lib/screens/contacts_screen.dart @@ -13,6 +13,7 @@ import '../connector/meshcore_protocol.dart'; import '../models/contact.dart'; import '../models/contact_group.dart'; import '../storage/contact_group_store.dart'; +import '../storage/contact_settings_store.dart'; import '../utils/contact_search.dart'; import '../utils/dialog_utils.dart'; import '../utils/disconnect_navigation_mixin.dart'; @@ -481,6 +482,7 @@ class _ContactsScreenState extends State contact: contact, lastSeen: _resolveLastSeen(contact), unreadCount: unreadCount, + isFavorite: contact.isFavorite, onTap: () => _openChat(context, contact), onLongPress: () => _showContactOptions(context, connector, contact), @@ -517,6 +519,7 @@ class _ContactsScreenState extends State }) .where((group) { if (_typeFilter == ContactTypeFilter.all) return true; + if (_typeFilter == ContactTypeFilter.favorites) return false; for (final key in group.memberKeys) { final contact = contactsByKey[key]; if (contact != null && _matchesTypeFilter(contact)) return true; @@ -591,6 +594,8 @@ class _ContactsScreenState extends State switch (_typeFilter) { case ContactTypeFilter.all: return true; + case ContactTypeFilter.favorites: + return contact.isFavorite; case ContactTypeFilter.users: return contact.type == advTypeChat; case ContactTypeFilter.repeaters: @@ -981,6 +986,7 @@ class _ContactsScreenState extends State ) { final isRepeater = contact.type == advTypeRepeater; final isRoom = contact.type == advTypeRoom; + final isFavorite = contact.isFavorite; showModalBottomSheet( context: context, @@ -1087,6 +1093,21 @@ class _ContactsScreenState extends State }, ), ], + ListTile( + leading: Icon( + isFavorite ? Icons.star : Icons.star_border, + color: Colors.amber[700], + ), + title: Text( + isFavorite + ? '${context.l10n.common_remove} ${context.l10n.listFilter_favorites}' + : '${context.l10n.common_add} ${context.l10n.listFilter_favorites}', + ), + onTap: () async { + Navigator.pop(sheetContext); + await connector.setContactFavorite(contact, !isFavorite); + }, + ), ListTile( leading: const Icon(Icons.copy), title: Text(context.l10n.contacts_ShareContact), @@ -1155,6 +1176,7 @@ class _ContactTile extends StatelessWidget { final Contact contact; final DateTime lastSeen; final int unreadCount; + final bool isFavorite; final VoidCallback onTap; final VoidCallback onLongPress; @@ -1162,6 +1184,7 @@ class _ContactTile extends StatelessWidget { required this.contact, required this.lastSeen, required this.unreadCount, + required this.isFavorite, required this.onTap, required this.onLongPress, }); @@ -1214,6 +1237,9 @@ class _ContactTile extends StatelessWidget { Row( mainAxisSize: MainAxisSize.min, children: [ + if (isFavorite) + Icon(Icons.star, size: 14, color: Colors.amber[700]), + if (isFavorite && contact.hasLocation) const SizedBox(width: 2), if (contact.hasLocation) Icon(Icons.location_on, size: 14, color: Colors.grey[400]), ], diff --git a/lib/storage/contact_store.dart b/lib/storage/contact_store.dart index 08d158b..504ff16 100644 --- a/lib/storage/contact_store.dart +++ b/lib/storage/contact_store.dart @@ -33,6 +33,7 @@ class ContactStore { 'publicKey': base64Encode(contact.publicKey), 'name': contact.name, 'type': contact.type, + 'flags': contact.flags, 'pathLength': contact.pathLength, 'path': base64Encode(contact.path), 'pathOverride': contact.pathOverride, @@ -53,6 +54,7 @@ class ContactStore { publicKey: Uint8List.fromList(base64Decode(json['publicKey'] as String)), name: json['name'] as String? ?? 'Unknown', type: json['type'] as int? ?? 0, + flags: json['flags'] as int? ?? 0, pathLength: json['pathLength'] as int? ?? -1, path: json['path'] != null ? Uint8List.fromList(base64Decode(json['path'] as String)) diff --git a/lib/widgets/list_filter_widget.dart b/lib/widgets/list_filter_widget.dart index e9c0d9e..473a3df 100644 --- a/lib/widgets/list_filter_widget.dart +++ b/lib/widgets/list_filter_widget.dart @@ -3,7 +3,7 @@ import '../l10n/l10n.dart'; enum ContactSortOption { lastSeen, recentMessages, name } -enum ContactTypeFilter { all, users, repeaters, rooms } +enum ContactTypeFilter { all, favorites, users, repeaters, rooms } class SortFilterMenuOption { final int value; @@ -94,11 +94,12 @@ const int _actionSortRecentMessages = 1; const int _actionSortName = 2; const int _actionSortLastSeen = 3; const int _actionFilterAll = 4; -const int _actionFilterUsers = 5; -const int _actionFilterRepeaters = 6; -const int _actionFilterRooms = 7; -const int _actionToggleUnreadOnly = 8; -const int _actionNewGroup = 9; +const int _actionFilterFavorites = 5; +const int _actionFilterUsers = 6; +const int _actionFilterRepeaters = 7; +const int _actionFilterRooms = 8; +const int _actionToggleUnreadOnly = 9; +const int _actionNewGroup = 10; class ContactsFilterMenu extends StatelessWidget { final ContactSortOption sortOption; @@ -154,6 +155,11 @@ class ContactsFilterMenu extends StatelessWidget { label: l10n.listFilter_all, checked: typeFilter == ContactTypeFilter.all, ), + SortFilterMenuOption( + value: _actionFilterFavorites, + label: l10n.listFilter_favorites, + checked: typeFilter == ContactTypeFilter.favorites, + ), SortFilterMenuOption( value: _actionFilterUsers, label: l10n.listFilter_users, @@ -198,6 +204,9 @@ class ContactsFilterMenu extends StatelessWidget { case _actionFilterUsers: onTypeFilterChanged(ContactTypeFilter.users); break; + case _actionFilterFavorites: + onTypeFilterChanged(ContactTypeFilter.favorites); + break; case _actionFilterRepeaters: onTypeFilterChanged(ContactTypeFilter.repeaters); break; diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index d2ea57e..4084d9b 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,6 +9,7 @@ import flutter_blue_plus_darwin import flutter_local_notifications import mobile_scanner import package_info_plus +import path_provider_foundation import share_plus import shared_preferences_foundation import sqflite_darwin @@ -20,6 +21,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) + PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) diff --git a/untranslated.json b/untranslated.json index 9e26dfe..a6d2937 100644 --- a/untranslated.json +++ b/untranslated.json @@ -1 +1,53 @@ -{} \ No newline at end of file +{ + "bg": [ + "listFilter_favorites" + ], + + "es": [ + "listFilter_favorites" + ], + + "fr": [ + "listFilter_favorites" + ], + + "it": [ + "listFilter_favorites" + ], + + "nl": [ + "listFilter_favorites" + ], + + "pl": [ + "listFilter_favorites" + ], + + "pt": [ + "listFilter_favorites" + ], + + "ru": [ + "listFilter_favorites" + ], + + "sk": [ + "listFilter_favorites" + ], + + "sl": [ + "listFilter_favorites" + ], + + "sv": [ + "listFilter_favorites" + ], + + "uk": [ + "listFilter_favorites" + ], + + "zh": [ + "listFilter_favorites" + ] +} From a26055c93f648a70ae6065033190bd91e94f07da Mon Sep 17 00:00:00 2001 From: ericz Date: Wed, 25 Feb 2026 00:49:41 +0100 Subject: [PATCH 06/10] resolved analyte code failure: unused import --- lib/screens/contacts_screen.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/screens/contacts_screen.dart b/lib/screens/contacts_screen.dart index 08e3e14..28e7aa5 100644 --- a/lib/screens/contacts_screen.dart +++ b/lib/screens/contacts_screen.dart @@ -13,7 +13,6 @@ import '../connector/meshcore_protocol.dart'; import '../models/contact.dart'; import '../models/contact_group.dart'; import '../storage/contact_group_store.dart'; -import '../storage/contact_settings_store.dart'; import '../utils/contact_search.dart'; import '../utils/dialog_utils.dart'; import '../utils/disconnect_navigation_mixin.dart'; From a2d1cb2a998fde7dba403bd727f854d73d637416 Mon Sep 17 00:00:00 2001 From: zjs81 Date: Tue, 24 Feb 2026 19:42:12 -0700 Subject: [PATCH 07/10] add pubspec.lock to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 2d9a3fc..157c7ec 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ migrate_working_dir/ .flutter-plugins-dependencies .pub-cache/ .pub/ +pubspec.lock /build/ /coverage/ From 190fd3b353a5b4594ac1d653fb329095fe16d3b8 Mon Sep 17 00:00:00 2001 From: zjs81 Date: Tue, 24 Feb 2026 19:44:15 -0700 Subject: [PATCH 08/10] Remove pubspec.lock from version control --- pubspec.lock | 1143 -------------------------------------------------- 1 file changed, 1143 deletions(-) delete mode 100644 pubspec.lock diff --git a/pubspec.lock b/pubspec.lock deleted file mode 100644 index fa23b27..0000000 --- a/pubspec.lock +++ /dev/null @@ -1,1143 +0,0 @@ -# Generated by pub -# See https://dart.dev/tools/pub/glossary#lockfile -packages: - archive: - dependency: transitive - description: - name: archive - sha256: a96e8b390886ee8abb49b7bd3ac8df6f451c621619f52a26e815fdcf568959ff - url: "https://pub.dev" - source: hosted - version: "4.0.9" - args: - dependency: transitive - description: - name: args - sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 - url: "https://pub.dev" - source: hosted - version: "2.7.0" - async: - dependency: transitive - description: - name: async - sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb" - url: "https://pub.dev" - source: hosted - version: "2.13.0" - bluez: - dependency: transitive - description: - name: bluez - sha256: "61a7204381925896a374301498f2f5399e59827c6498ae1e924aaa598751b545" - url: "https://pub.dev" - source: hosted - version: "0.8.3" - boolean_selector: - dependency: transitive - description: - name: boolean_selector - sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - cached_network_image: - dependency: "direct main" - description: - name: cached_network_image - sha256: "7c1183e361e5c8b0a0f21a28401eecdbde252441106a9816400dd4c2b2424916" - url: "https://pub.dev" - source: hosted - version: "3.4.1" - cached_network_image_platform_interface: - dependency: transitive - description: - name: cached_network_image_platform_interface - sha256: "35814b016e37fbdc91f7ae18c8caf49ba5c88501813f73ce8a07027a395e2829" - url: "https://pub.dev" - source: hosted - version: "4.1.1" - cached_network_image_web: - dependency: transitive - description: - name: cached_network_image_web - sha256: "980842f4e8e2535b8dbd3d5ca0b1f0ba66bf61d14cc3a17a9b4788a3685ba062" - url: "https://pub.dev" - source: hosted - version: "1.3.1" - characters: - dependency: "direct main" - description: - name: characters - sha256: faf38497bda5ead2a8c7615f4f7939df04333478bf32e4173fcb06d428b5716b - url: "https://pub.dev" - source: hosted - version: "1.4.1" - checked_yaml: - dependency: transitive - description: - name: checked_yaml - sha256: "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f" - url: "https://pub.dev" - source: hosted - version: "2.0.4" - cli_util: - dependency: transitive - description: - name: cli_util - sha256: ff6785f7e9e3c38ac98b2fb035701789de90154024a75b6cb926445e83197d1c - url: "https://pub.dev" - source: hosted - version: "0.4.2" - clock: - dependency: transitive - description: - name: clock - sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b - url: "https://pub.dev" - source: hosted - version: "1.1.2" - code_assets: - dependency: transitive - description: - name: code_assets - sha256: "83ccdaa064c980b5596c35dd64a8d3ecc68620174ab9b90b6343b753aa721687" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - collection: - dependency: transitive - description: - name: collection - sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76" - url: "https://pub.dev" - source: hosted - version: "1.19.1" - convert: - dependency: transitive - description: - name: convert - sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68 - url: "https://pub.dev" - source: hosted - version: "3.1.2" - cross_file: - dependency: transitive - description: - name: cross_file - sha256: "28bb3ae56f117b5aec029d702a90f57d285cd975c3c5c281eaca38dbc47c5937" - url: "https://pub.dev" - source: hosted - version: "0.3.5+2" - crypto: - dependency: "direct main" - description: - name: crypto - sha256: c8ea0233063ba03258fbcf2ca4d6dadfefe14f02fab57702265467a19f27fadf - url: "https://pub.dev" - source: hosted - version: "3.0.7" - cupertino_icons: - dependency: "direct main" - description: - name: cupertino_icons - sha256: ba631d1c7f7bef6b729a622b7b752645a2d076dba9976925b8f25725a30e1ee6 - url: "https://pub.dev" - source: hosted - version: "1.0.8" - dart_earcut: - dependency: transitive - description: - name: dart_earcut - sha256: e485001bfc05dcbc437d7bfb666316182e3522d4c3f9668048e004d0eb2ce43b - url: "https://pub.dev" - source: hosted - version: "1.2.0" - dart_polylabel2: - dependency: transitive - description: - name: dart_polylabel2 - sha256: "7eeab15ce72894e4bdba6a8765712231fc81be0bd95247de4ad9966abc57adc6" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - dbus: - dependency: transitive - description: - name: dbus - sha256: d0c98dcd4f5169878b6cf8f6e0a52403a9dff371a3e2f019697accbf6f44a270 - url: "https://pub.dev" - source: hosted - version: "0.7.12" - fake_async: - dependency: transitive - description: - name: fake_async - sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44" - url: "https://pub.dev" - source: hosted - version: "1.3.3" - ffi: - dependency: transitive - description: - name: ffi - sha256: "6d7fd89431262d8f3125e81b50d3847a091d846eafcd4fdb88dd06f36d705a45" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - file: - dependency: transitive - description: - name: file - sha256: a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4 - url: "https://pub.dev" - source: hosted - version: "7.0.1" - fixnum: - dependency: transitive - description: - name: fixnum - sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be - url: "https://pub.dev" - source: hosted - version: "1.1.1" - flutter: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_blue_plus: - dependency: "direct main" - description: - name: flutter_blue_plus - sha256: "88a65ead7dea67ddcc03e6ca846163c6b6cc09a2dcebdb8bb601fcd654ea9382" - url: "https://pub.dev" - source: hosted - version: "2.1.1" - flutter_blue_plus_android: - dependency: transitive - description: - name: flutter_blue_plus_android - sha256: "5010b0960cce533a8fa71401573f044362c3e2e111dc6eb4898c92e85f85f50c" - url: "https://pub.dev" - source: hosted - version: "8.1.0" - flutter_blue_plus_darwin: - dependency: transitive - description: - name: flutter_blue_plus_darwin - sha256: "52b155d868e17c1c8ad85520a0912d447d92aedccb5a5e234d3edc98ebd1307a" - url: "https://pub.dev" - source: hosted - version: "8.1.1" - flutter_blue_plus_linux: - dependency: transitive - description: - name: flutter_blue_plus_linux - sha256: f5b02244d89465ba82c8c512686c66362fbb01f52fa03d645ed353ebf3883242 - url: "https://pub.dev" - source: hosted - version: "8.1.0" - flutter_blue_plus_platform_interface: - dependency: transitive - description: - name: flutter_blue_plus_platform_interface - sha256: "6e0fc04b77491dbfdbcd46c1a021b12f2f5fc5d6e01777f93a38a8431989b7f0" - url: "https://pub.dev" - source: hosted - version: "8.1.0" - flutter_blue_plus_web: - dependency: transitive - description: - name: flutter_blue_plus_web - sha256: "376aad9595ee389c7cd56e0c373e78abcaa790c821ece9cb81f0969ec94c5bca" - url: "https://pub.dev" - source: hosted - version: "8.1.0" - flutter_blue_plus_winrt: - dependency: transitive - description: - name: flutter_blue_plus_winrt - sha256: ed894f0ab341f4cece8fa33edc381d46424a7c5bfd0e841d933d0f8c34c86521 - url: "https://pub.dev" - source: hosted - version: "0.0.18" - flutter_cache_manager: - dependency: "direct main" - description: - name: flutter_cache_manager - sha256: "400b6592f16a4409a7f2bb929a9a7e38c72cceb8ffb99ee57bbf2cb2cecf8386" - url: "https://pub.dev" - source: hosted - version: "3.4.1" - flutter_foreground_task: - dependency: "direct main" - description: - name: flutter_foreground_task - sha256: "48ea45056155a99fb30b15f14f4039a044d925bc85f381ed0b2d3b00a60b99de" - url: "https://pub.dev" - source: hosted - version: "9.2.0" - flutter_launcher_icons: - dependency: "direct dev" - description: - name: flutter_launcher_icons - sha256: "10f13781741a2e3972126fae08393d3c4e01fa4cd7473326b94b72cf594195e7" - url: "https://pub.dev" - source: hosted - version: "0.14.4" - flutter_linkify: - dependency: "direct main" - description: - name: flutter_linkify - sha256: "74669e06a8f358fee4512b4320c0b80e51cffc496607931de68d28f099254073" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - flutter_lints: - dependency: "direct dev" - description: - name: flutter_lints - sha256: "3105dc8492f6183fb076ccf1f351ac3d60564bff92e20bfc4af9cc1651f4e7e1" - url: "https://pub.dev" - source: hosted - version: "6.0.0" - flutter_local_notifications: - dependency: "direct main" - description: - name: flutter_local_notifications - sha256: "2b50e938a275e1ad77352d6a25e25770f4130baa61eaf02de7a9a884680954ad" - url: "https://pub.dev" - source: hosted - version: "20.1.0" - flutter_local_notifications_linux: - dependency: transitive - description: - name: flutter_local_notifications_linux - sha256: dce0116868cedd2cdf768af0365fc37ff1cbef7c02c4f51d0587482e625868d0 - url: "https://pub.dev" - source: hosted - version: "7.0.0" - flutter_local_notifications_platform_interface: - dependency: transitive - description: - name: flutter_local_notifications_platform_interface - sha256: "23de31678a48c084169d7ae95866df9de5c9d2a44be3e5915a2ff067aeeba899" - url: "https://pub.dev" - source: hosted - version: "10.0.0" - flutter_local_notifications_windows: - dependency: transitive - description: - name: flutter_local_notifications_windows - sha256: e97a1a3016512437d9c0b12fae7d1491c3c7b9aa7f03a69b974308840656b02a - url: "https://pub.dev" - source: hosted - version: "2.0.1" - flutter_localizations: - dependency: "direct main" - description: flutter - source: sdk - version: "0.0.0" - flutter_map: - dependency: "direct main" - description: - name: flutter_map - sha256: "391e7dc95cc3f5190748210a69d4cfeb5d8f84dcdfa9c3235d0a9d7742ccb3f8" - url: "https://pub.dev" - source: hosted - version: "8.2.2" - flutter_svg: - dependency: "direct main" - description: - name: flutter_svg - sha256: "87fbd7c534435b6c5d9d98b01e1fd527812b82e68ddd8bd35fc45ed0fa8f0a95" - url: "https://pub.dev" - source: hosted - version: "2.2.3" - flutter_test: - dependency: "direct dev" - description: flutter - source: sdk - version: "0.0.0" - flutter_web_plugins: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - glob: - dependency: transitive - description: - name: glob - sha256: c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de - url: "https://pub.dev" - source: hosted - version: "2.1.3" - gpx: - dependency: "direct main" - description: - name: gpx - sha256: f5b12b86402c639079243600ee2b3afd85cd08d26117fc8885cf48efce471d8e - url: "https://pub.dev" - source: hosted - version: "2.3.0" - hooks: - dependency: transitive - description: - name: hooks - sha256: "7a08a0d684cb3b8fb604b78455d5d352f502b68079f7b80b831c62220ab0a4f6" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - http: - dependency: "direct main" - description: - name: http - sha256: "87721a4a50b19c7f1d49001e51409bddc46303966ce89a65af4f4e6004896412" - url: "https://pub.dev" - source: hosted - version: "1.6.0" - http_parser: - dependency: transitive - description: - name: http_parser - sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571" - url: "https://pub.dev" - source: hosted - version: "4.1.2" - image: - dependency: transitive - description: - name: image - sha256: f9881ff4998044947ec38d098bc7c8316ae1186fa786eddffdb867b9bc94dfce - url: "https://pub.dev" - source: hosted - version: "4.8.0" - intl: - dependency: "direct main" - description: - name: intl - sha256: "3df61194eb431efc39c4ceba583b95633a403f46c9fd341e550ce0bfa50e9aa5" - url: "https://pub.dev" - source: hosted - version: "0.20.2" - json_annotation: - dependency: transitive - description: - name: json_annotation - sha256: cb09e7dac6210041fad964ed7fbee004f14258b4eca4040f72d1234062ace4c8 - url: "https://pub.dev" - source: hosted - version: "4.11.0" - latlong2: - dependency: "direct main" - description: - name: latlong2 - sha256: "98227922caf49e6056f91b6c56945ea1c7b166f28ffcd5fb8e72fc0b453cc8fe" - url: "https://pub.dev" - source: hosted - version: "0.9.1" - leak_tracker: - dependency: transitive - description: - name: leak_tracker - sha256: "33e2e26bdd85a0112ec15400c8cbffea70d0f9c3407491f672a2fad47915e2de" - url: "https://pub.dev" - source: hosted - version: "11.0.2" - leak_tracker_flutter_testing: - dependency: transitive - description: - name: leak_tracker_flutter_testing - sha256: "1dbc140bb5a23c75ea9c4811222756104fbcd1a27173f0c34ca01e16bea473c1" - url: "https://pub.dev" - source: hosted - version: "3.0.10" - leak_tracker_testing: - dependency: transitive - description: - name: leak_tracker_testing - sha256: "8d5a2d49f4a66b49744b23b018848400d23e54caf9463f4eb20df3eb8acb2eb1" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - linkify: - dependency: transitive - description: - name: linkify - sha256: "4139ea77f4651ab9c315b577da2dd108d9aa0bd84b5d03d33323f1970c645832" - url: "https://pub.dev" - source: hosted - version: "5.0.0" - lints: - dependency: transitive - description: - name: lints - sha256: "12f842a479589fea194fe5c5a3095abc7be0c1f2ddfa9a0e76aed1dbd26a87df" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - lists: - dependency: transitive - description: - name: lists - sha256: "4ca5c19ae4350de036a7e996cdd1ee39c93ac0a2b840f4915459b7d0a7d4ab27" - url: "https://pub.dev" - source: hosted - version: "1.0.1" - logger: - dependency: transitive - description: - name: logger - sha256: a7967e31b703831a893bbc3c3dd11db08126fe5f369b5c648a36f821979f5be3 - url: "https://pub.dev" - source: hosted - version: "2.6.2" - logging: - dependency: transitive - description: - name: logging - sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61 - url: "https://pub.dev" - source: hosted - version: "1.3.0" - matcher: - dependency: transitive - description: - name: matcher - sha256: "12956d0ad8390bbcc63ca2e1469c0619946ccb52809807067a7020d57e647aa6" - url: "https://pub.dev" - source: hosted - version: "0.12.18" - material_color_utilities: - dependency: transitive - description: - name: material_color_utilities - sha256: "9c337007e82b1889149c82ed242ed1cb24a66044e30979c44912381e9be4c48b" - url: "https://pub.dev" - source: hosted - version: "0.13.0" - material_symbols_icons: - dependency: "direct main" - description: - name: material_symbols_icons - sha256: c62b15f2b3de98d72cbff0148812f5ef5159f05e61fc9f9a089ec2bb234df082 - url: "https://pub.dev" - source: hosted - version: "4.2906.0" - meta: - dependency: transitive - description: - name: meta - sha256: "1741988757a65eb6b36abe716829688cf01910bbf91c34354ff7ec1c3de2b349" - url: "https://pub.dev" - source: hosted - version: "1.18.0" - mgrs_dart: - dependency: transitive - description: - name: mgrs_dart - sha256: fb89ae62f05fa0bb90f70c31fc870bcbcfd516c843fb554452ab3396f78586f7 - url: "https://pub.dev" - source: hosted - version: "2.0.0" - mime: - dependency: transitive - description: - name: mime - sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - mobile_scanner: - dependency: "direct main" - description: - name: mobile_scanner - sha256: c92c26bf2231695b6d3477c8dcf435f51e28f87b1745966b1fe4c47a286171ce - url: "https://pub.dev" - source: hosted - version: "7.2.0" - native_toolchain_c: - dependency: transitive - description: - name: native_toolchain_c - sha256: "89e83885ba09da5fdf2cdacc8002a712ca238c28b7f717910b34bcd27b0d03ac" - url: "https://pub.dev" - source: hosted - version: "0.17.4" - nested: - dependency: transitive - description: - name: nested - sha256: "03bac4c528c64c95c722ec99280375a6f2fc708eec17c7b3f07253b626cd2a20" - url: "https://pub.dev" - source: hosted - version: "1.0.0" - objective_c: - dependency: transitive - description: - name: objective_c - sha256: "100a1c87616ab6ed41ec263b083c0ef3261ee6cd1dc3b0f35f8ddfa4f996fe52" - url: "https://pub.dev" - source: hosted - version: "9.3.0" - octo_image: - dependency: transitive - description: - name: octo_image - sha256: "34faa6639a78c7e3cbe79be6f9f96535867e879748ade7d17c9b1ae7536293bd" - url: "https://pub.dev" - source: hosted - version: "2.1.0" - package_info_plus: - dependency: "direct main" - description: - name: package_info_plus - sha256: f69da0d3189a4b4ceaeb1a3defb0f329b3b352517f52bed4290f83d4f06bc08d - url: "https://pub.dev" - source: hosted - version: "9.0.0" - package_info_plus_platform_interface: - dependency: transitive - description: - name: package_info_plus_platform_interface - sha256: "202a487f08836a592a6bd4f901ac69b3a8f146af552bbd14407b6b41e1c3f086" - url: "https://pub.dev" - source: hosted - version: "3.2.1" - path: - dependency: transitive - description: - name: path - sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5" - url: "https://pub.dev" - source: hosted - version: "1.9.1" - path_parsing: - dependency: transitive - description: - name: path_parsing - sha256: "883402936929eac138ee0a45da5b0f2c80f89913e6dc3bf77eb65b84b409c6ca" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - path_provider: - dependency: "direct main" - description: - name: path_provider - sha256: "50c5dd5b6e1aaf6fb3a78b33f6aa3afca52bf903a8a5298f53101fdaee55bbcd" - url: "https://pub.dev" - source: hosted - version: "2.1.5" - path_provider_android: - dependency: transitive - description: - name: path_provider_android - sha256: f2c65e21139ce2c3dad46922be8272bb5963516045659e71bb16e151c93b580e - url: "https://pub.dev" - source: hosted - version: "2.2.22" - path_provider_foundation: - dependency: transitive - description: - name: path_provider_foundation - sha256: "2a376b7d6392d80cd3705782d2caa734ca4727776db0b6ec36ef3f1855197699" - url: "https://pub.dev" - source: hosted - version: "2.6.0" - path_provider_linux: - dependency: transitive - description: - name: path_provider_linux - sha256: f7a1fe3a634fe7734c8d3f2766ad746ae2a2884abe22e241a8b301bf5cac3279 - url: "https://pub.dev" - source: hosted - version: "2.2.1" - path_provider_platform_interface: - dependency: transitive - description: - name: path_provider_platform_interface - sha256: "88f5779f72ba699763fa3a3b06aa4bf6de76c8e5de842cf6f29e2e06476c2334" - url: "https://pub.dev" - source: hosted - version: "2.1.2" - path_provider_windows: - dependency: transitive - description: - name: path_provider_windows - sha256: bd6f00dbd873bfb70d0761682da2b3a2c2fccc2b9e84c495821639601d81afe7 - url: "https://pub.dev" - source: hosted - version: "2.3.0" - petitparser: - dependency: transitive - description: - name: petitparser - sha256: "91bd59303e9f769f108f8df05e371341b15d59e995e6806aefab827b58336675" - url: "https://pub.dev" - source: hosted - version: "7.0.2" - platform: - dependency: transitive - description: - name: platform - sha256: "5d6b1b0036a5f331ebc77c850ebc8506cbc1e9416c27e59b439f917a902a4984" - url: "https://pub.dev" - source: hosted - version: "3.1.6" - plugin_platform_interface: - dependency: transitive - description: - name: plugin_platform_interface - sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02" - url: "https://pub.dev" - source: hosted - version: "2.1.8" - pointycastle: - dependency: "direct main" - description: - name: pointycastle - sha256: "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5" - url: "https://pub.dev" - source: hosted - version: "4.0.0" - posix: - dependency: transitive - description: - name: posix - sha256: "185ef7606574f789b40f289c233efa52e96dead518aed988e040a10737febb07" - url: "https://pub.dev" - source: hosted - version: "6.5.0" - proj4dart: - dependency: transitive - description: - name: proj4dart - sha256: c8a659ac9b6864aa47c171e78d41bbe6f5e1d7bd790a5814249e6b68bc44324e - url: "https://pub.dev" - source: hosted - version: "2.1.0" - provider: - dependency: "direct main" - description: - name: provider - sha256: "4e82183fa20e5ca25703ead7e05de9e4cceed1fbd1eadc1ac3cb6f565a09f272" - url: "https://pub.dev" - source: hosted - version: "6.1.5+1" - pub_semver: - dependency: transitive - description: - name: pub_semver - sha256: "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585" - url: "https://pub.dev" - source: hosted - version: "2.2.0" - qr: - dependency: transitive - description: - name: qr - sha256: "5a1d2586170e172b8a8c8470bbbffd5eb0cd38a66c0d77155ea138d3af3a4445" - url: "https://pub.dev" - source: hosted - version: "3.0.2" - qr_flutter: - dependency: "direct main" - description: - name: qr_flutter - sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097" - url: "https://pub.dev" - source: hosted - version: "4.1.0" - quiver: - dependency: transitive - description: - name: quiver - sha256: ea0b925899e64ecdfbf9c7becb60d5b50e706ade44a85b2363be2a22d88117d2 - url: "https://pub.dev" - source: hosted - version: "3.2.2" - rxdart: - dependency: transitive - description: - name: rxdart - sha256: "5c3004a4a8dbb94bd4bf5412a4def4acdaa12e12f269737a5751369e12d1a962" - url: "https://pub.dev" - source: hosted - version: "0.28.0" - share_plus: - dependency: "direct main" - description: - name: share_plus - sha256: "14c8860d4de93d3a7e53af51bff479598c4e999605290756bbbe45cf65b37840" - url: "https://pub.dev" - source: hosted - version: "12.0.1" - share_plus_platform_interface: - dependency: transitive - description: - name: share_plus_platform_interface - sha256: "88023e53a13429bd65d8e85e11a9b484f49d4c190abbd96c7932b74d6927cc9a" - url: "https://pub.dev" - source: hosted - version: "6.1.0" - shared_preferences: - dependency: "direct main" - description: - name: shared_preferences - sha256: "2939ae520c9024cb197fc20dee269cd8cdbf564c8b5746374ec6cacdc5169e64" - url: "https://pub.dev" - source: hosted - version: "2.5.4" - shared_preferences_android: - dependency: transitive - description: - name: shared_preferences_android - sha256: cbc40be9be1c5af4dab4d6e0de4d5d3729e6f3d65b89d21e1815d57705644a6f - url: "https://pub.dev" - source: hosted - version: "2.4.20" - shared_preferences_foundation: - dependency: transitive - description: - name: shared_preferences_foundation - sha256: "4e7eaffc2b17ba398759f1151415869a34771ba11ebbccd1b0145472a619a64f" - url: "https://pub.dev" - source: hosted - version: "2.5.6" - shared_preferences_linux: - dependency: transitive - description: - name: shared_preferences_linux - sha256: "580abfd40f415611503cae30adf626e6656dfb2f0cee8f465ece7b6defb40f2f" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shared_preferences_platform_interface: - dependency: transitive - description: - name: shared_preferences_platform_interface - sha256: "57cbf196c486bc2cf1f02b85784932c6094376284b3ad5779d1b1c6c6a816b80" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - shared_preferences_web: - dependency: transitive - description: - name: shared_preferences_web - sha256: c49bd060261c9a3f0ff445892695d6212ff603ef3115edbb448509d407600019 - url: "https://pub.dev" - source: hosted - version: "2.4.3" - shared_preferences_windows: - dependency: transitive - description: - name: shared_preferences_windows - sha256: "94ef0f72b2d71bc3e700e025db3710911bd51a71cefb65cc609dd0d9a982e3c1" - url: "https://pub.dev" - source: hosted - version: "2.4.1" - sky_engine: - dependency: transitive - description: flutter - source: sdk - version: "0.0.0" - source_span: - dependency: transitive - description: - name: source_span - sha256: "56a02f1f4cd1a2d96303c0144c93bd6d909eea6bee6bf5a0e0b685edbd4c47ab" - url: "https://pub.dev" - source: hosted - version: "1.10.2" - sqflite: - dependency: transitive - description: - name: sqflite - sha256: e2297b1da52f127bc7a3da11439985d9b536f75070f3325e62ada69a5c585d03 - url: "https://pub.dev" - source: hosted - version: "2.4.2" - sqflite_android: - dependency: transitive - description: - name: sqflite_android - sha256: ecd684501ebc2ae9a83536e8b15731642b9570dc8623e0073d227d0ee2bfea88 - url: "https://pub.dev" - source: hosted - version: "2.4.2+2" - sqflite_common: - dependency: transitive - description: - name: sqflite_common - sha256: "6ef422a4525ecc601db6c0a2233ff448c731307906e92cabc9ba292afaae16a6" - url: "https://pub.dev" - source: hosted - version: "2.5.6" - sqflite_darwin: - dependency: transitive - description: - name: sqflite_darwin - sha256: "279832e5cde3fe99e8571879498c9211f3ca6391b0d818df4e17d9fff5c6ccb3" - url: "https://pub.dev" - source: hosted - version: "2.4.2" - sqflite_platform_interface: - dependency: transitive - description: - name: sqflite_platform_interface - sha256: "8dd4515c7bdcae0a785b0062859336de775e8c65db81ae33dd5445f35be61920" - url: "https://pub.dev" - source: hosted - version: "2.4.0" - stack_trace: - dependency: transitive - description: - name: stack_trace - sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1" - url: "https://pub.dev" - source: hosted - version: "1.12.1" - stream_channel: - dependency: transitive - description: - name: stream_channel - sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d" - url: "https://pub.dev" - source: hosted - version: "2.1.4" - string_scanner: - dependency: transitive - description: - name: string_scanner - sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43" - url: "https://pub.dev" - source: hosted - version: "1.4.1" - synchronized: - dependency: transitive - description: - name: synchronized - sha256: c254ade258ec8282947a0acbbc90b9575b4f19673533ee46f2f6e9b3aeefd7c0 - url: "https://pub.dev" - source: hosted - version: "3.4.0" - term_glyph: - dependency: transitive - description: - name: term_glyph - sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e" - url: "https://pub.dev" - source: hosted - version: "1.2.2" - test_api: - dependency: transitive - description: - name: test_api - sha256: "93167629bfc610f71560ab9312acdda4959de4df6fac7492c89ff0d3886f6636" - url: "https://pub.dev" - source: hosted - version: "0.7.9" - timezone: - dependency: transitive - description: - name: timezone - sha256: dd14a3b83cfd7cb19e7888f1cbc20f258b8d71b54c06f79ac585f14093a287d1 - url: "https://pub.dev" - source: hosted - version: "0.10.1" - typed_data: - dependency: transitive - description: - name: typed_data - sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006 - url: "https://pub.dev" - source: hosted - version: "1.4.0" - unicode: - dependency: transitive - description: - name: unicode - sha256: "0f69e46593d65245774d4f17125c6084d2c20b4e473a983f6e21b7d7762218f1" - url: "https://pub.dev" - source: hosted - version: "0.3.1" - url_launcher: - dependency: "direct main" - description: - name: url_launcher - sha256: f6a7e5c4835bb4e3026a04793a4199ca2d14c739ec378fdfe23fc8075d0439f8 - url: "https://pub.dev" - source: hosted - version: "6.3.2" - url_launcher_android: - dependency: transitive - description: - name: url_launcher_android - sha256: "767344bf3063897b5cf0db830e94f904528e6dd50a6dfaf839f0abf509009611" - url: "https://pub.dev" - source: hosted - version: "6.3.28" - url_launcher_ios: - dependency: transitive - description: - name: url_launcher_ios - sha256: "580fe5dfb51671ae38191d316e027f6b76272b026370708c2d898799750a02b0" - url: "https://pub.dev" - source: hosted - version: "6.4.1" - url_launcher_linux: - dependency: transitive - description: - name: url_launcher_linux - sha256: d5e14138b3bc193a0f63c10a53c94b91d399df0512b1f29b94a043db7482384a - url: "https://pub.dev" - source: hosted - version: "3.2.2" - url_launcher_macos: - dependency: transitive - description: - name: url_launcher_macos - sha256: "368adf46f71ad3c21b8f06614adb38346f193f3a59ba8fe9a2fd74133070ba18" - url: "https://pub.dev" - source: hosted - version: "3.2.5" - url_launcher_platform_interface: - dependency: transitive - description: - name: url_launcher_platform_interface - sha256: "552f8a1e663569be95a8190206a38187b531910283c3e982193e4f2733f01029" - url: "https://pub.dev" - source: hosted - version: "2.3.2" - url_launcher_web: - dependency: transitive - description: - name: url_launcher_web - sha256: d0412fcf4c6b31ecfdb7762359b7206ffba3bbffd396c6d9f9c4616ece476c1f - url: "https://pub.dev" - source: hosted - version: "2.4.2" - url_launcher_windows: - dependency: transitive - description: - name: url_launcher_windows - sha256: "712c70ab1b99744ff066053cbe3e80c73332b38d46e5e945c98689b2e66fc15f" - url: "https://pub.dev" - source: hosted - version: "3.1.5" - uuid: - dependency: "direct main" - description: - name: uuid - sha256: "1fef9e8e11e2991bb773070d4656b7bd5d850967a2456cfc83cf47925ba79489" - url: "https://pub.dev" - source: hosted - version: "4.5.3" - vector_graphics: - dependency: transitive - description: - name: vector_graphics - sha256: a4f059dc26fc8295b5921376600a194c4ec7d55e72f2fe4c7d2831e103d461e6 - url: "https://pub.dev" - source: hosted - version: "1.1.19" - vector_graphics_codec: - dependency: transitive - description: - name: vector_graphics_codec - sha256: "99fd9fbd34d9f9a32efd7b6a6aae14125d8237b10403b422a6a6dfeac2806146" - url: "https://pub.dev" - source: hosted - version: "1.1.13" - vector_graphics_compiler: - dependency: transitive - description: - name: vector_graphics_compiler - sha256: "5a88dd14c0954a5398af544651c7fb51b457a2a556949bfb25369b210ef73a74" - url: "https://pub.dev" - source: hosted - version: "1.2.0" - vector_math: - dependency: transitive - description: - name: vector_math - sha256: d530bd74fea330e6e364cda7a85019c434070188383e1cd8d9777ee586914c5b - url: "https://pub.dev" - source: hosted - version: "2.2.0" - vm_service: - dependency: transitive - description: - name: vm_service - sha256: "45caa6c5917fa127b5dbcfbd1fa60b14e583afdc08bfc96dda38886ca252eb60" - url: "https://pub.dev" - source: hosted - version: "15.0.2" - wakelock_plus: - dependency: "direct main" - description: - name: wakelock_plus - sha256: "9296d40c9adbedaba95d1e704f4e0b434be446e2792948d0e4aa977048104228" - url: "https://pub.dev" - source: hosted - version: "1.4.0" - wakelock_plus_platform_interface: - dependency: transitive - description: - name: wakelock_plus_platform_interface - sha256: "036deb14cd62f558ca3b73006d52ce049fabcdcb2eddfe0bf0fe4e8a943b5cf2" - url: "https://pub.dev" - source: hosted - version: "1.3.0" - web: - dependency: "direct main" - description: - name: web - sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a" - url: "https://pub.dev" - source: hosted - version: "1.1.1" - win32: - dependency: transitive - description: - name: win32 - sha256: d7cb55e04cd34096cd3a79b3330245f54cb96a370a1c27adb3c84b917de8b08e - url: "https://pub.dev" - source: hosted - version: "5.15.0" - wkt_parser: - dependency: transitive - description: - name: wkt_parser - sha256: "8a555fc60de3116c00aad67891bcab20f81a958e4219cc106e3c037aa3937f13" - url: "https://pub.dev" - source: hosted - version: "2.0.0" - xdg_directories: - dependency: transitive - description: - name: xdg_directories - sha256: "7a3f37b05d989967cdddcbb571f1ea834867ae2faa29725fd085180e0883aa15" - url: "https://pub.dev" - source: hosted - version: "1.1.0" - xml: - dependency: transitive - description: - name: xml - sha256: "971043b3a0d3da28727e40ed3e0b5d18b742fa5a68665cca88e74b7876d5e025" - url: "https://pub.dev" - source: hosted - version: "6.6.1" - yaml: - dependency: transitive - description: - name: yaml - sha256: b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce - url: "https://pub.dev" - source: hosted - version: "3.1.3" -sdks: - dart: ">=3.10.3 <4.0.0" - flutter: ">=3.38.4" From 50af2e0bc9c2ddedc4bdbafcc8709071e055b886 Mon Sep 17 00:00:00 2001 From: zjs81 Date: Tue, 24 Feb 2026 20:07:15 -0700 Subject: [PATCH 09/10] Fix review issues: dedicated l10n keys, remove unrelated CI/macOS changes, translate all locales - Replace concatenated favorite toggle strings with dedicated listFilter_addToFavorites/removeFromFavorites keys - Remove unrelated CI artifact upload step from build.yml - Revert unrelated macOS GeneratedPluginRegistrant.swift change - Add comment explaining groups hidden under favorites filter - Translate new keys across all 14 locales --- .github/workflows/build.yml | 5 -- lib/l10n/app_bg.arb | 13 ++++- lib/l10n/app_de.arb | 2 + lib/l10n/app_en.arb | 2 + lib/l10n/app_es.arb | 13 ++++- lib/l10n/app_fr.arb | 13 ++++- lib/l10n/app_it.arb | 13 ++++- lib/l10n/app_localizations.dart | 12 +++++ lib/l10n/app_localizations_bg.dart | 8 ++- lib/l10n/app_localizations_de.dart | 6 +++ lib/l10n/app_localizations_en.dart | 6 +++ lib/l10n/app_localizations_es.dart | 8 ++- lib/l10n/app_localizations_fr.dart | 8 ++- lib/l10n/app_localizations_it.dart | 8 ++- lib/l10n/app_localizations_nl.dart | 8 ++- lib/l10n/app_localizations_pl.dart | 8 ++- lib/l10n/app_localizations_pt.dart | 8 ++- lib/l10n/app_localizations_ru.dart | 8 ++- lib/l10n/app_localizations_sk.dart | 8 ++- lib/l10n/app_localizations_sl.dart | 8 ++- lib/l10n/app_localizations_sv.dart | 8 ++- lib/l10n/app_localizations_uk.dart | 8 ++- lib/l10n/app_localizations_zh.dart | 8 ++- lib/l10n/app_nl.arb | 13 ++++- lib/l10n/app_pl.arb | 13 ++++- lib/l10n/app_pt.arb | 13 ++++- lib/l10n/app_ru.arb | 13 ++++- lib/l10n/app_sk.arb | 13 ++++- lib/l10n/app_sl.arb | 13 ++++- lib/l10n/app_sv.arb | 13 ++++- lib/l10n/app_uk.arb | 13 ++++- lib/l10n/app_zh.arb | 13 ++++- lib/screens/contacts_screen.dart | 5 +- macos/Flutter/GeneratedPluginRegistrant.swift | 2 - untranslated.json | 54 +------------------ 35 files changed, 266 insertions(+), 101 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c376a4a..05c82de 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,11 +30,6 @@ jobs: ${{ runner.os }}-gradle- - run: flutter pub get - run: flutter build apk --release --no-pub - - name: Upload Debug APK - uses: actions/upload-artifact@v4 - with: - name: app-debug - path: build/app/outputs/flutter-apk/app-release.apk ios: runs-on: macos-latest diff --git a/lib/l10n/app_bg.arb b/lib/l10n/app_bg.arb index b88e3ba..3613e85 100644 --- a/lib/l10n/app_bg.arb +++ b/lib/l10n/app_bg.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "Неуспешно изтриване на канала \"{name}\"", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "bg", "appTitle": "MeshCore Open", "nav_contacts": "Контакти", @@ -1744,5 +1750,8 @@ "type": "double" } } - } + }, + "listFilter_removeFromFavorites": "Премахване от списъка с любими", + "listFilter_addToFavorites": "Добави към любими", + "listFilter_favorites": "Любими" } diff --git a/lib/l10n/app_de.arb b/lib/l10n/app_de.arb index f596ae4..64e8cd3 100644 --- a/lib/l10n/app_de.arb +++ b/lib/l10n/app_de.arb @@ -1344,6 +1344,8 @@ "listFilter_filters": "Filtere", "listFilter_all": "Alle", "listFilter_favorites": "Favoriten", + "listFilter_addToFavorites": "Zu Favoriten hinzufügen", + "listFilter_removeFromFavorites": "Aus Favoriten entfernen", "listFilter_users": "Benutzer", "listFilter_repeaters": "Repeater", "listFilter_roomServers": "Raumserver", diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 5b15b65..8d9f385 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -1556,6 +1556,8 @@ "listFilter_filters": "Filters", "listFilter_all": "All", "listFilter_favorites": "Favorites", + "listFilter_addToFavorites": "Add to favorites", + "listFilter_removeFromFavorites": "Remove from favorites", "listFilter_users": "Users", "listFilter_repeaters": "Repeaters", "listFilter_roomServers": "Room servers", diff --git a/lib/l10n/app_es.arb b/lib/l10n/app_es.arb index 2f62b54..dd8ce6c 100644 --- a/lib/l10n/app_es.arb +++ b/lib/l10n/app_es.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "No se pudo eliminar el canal \"{name}\"", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "es", "appTitle": "MeshCore Open", "nav_contacts": "Contactos", @@ -1772,5 +1778,8 @@ "type": "double" } } - } + }, + "listFilter_favorites": "Favoritos", + "listFilter_removeFromFavorites": "Eliminar de las favoritas", + "listFilter_addToFavorites": "Añadir a favoritos" } diff --git a/lib/l10n/app_fr.arb b/lib/l10n/app_fr.arb index 9eb66e7..fe738f7 100644 --- a/lib/l10n/app_fr.arb +++ b/lib/l10n/app_fr.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "Échec de la suppression de la chaîne \"{name}\"", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "fr", "appTitle": "MeshCore Open", "nav_contacts": "Contacts", @@ -1744,5 +1750,8 @@ "type": "double" } } - } + }, + "listFilter_addToFavorites": "Ajouter à mes favoris", + "listFilter_removeFromFavorites": "Supprimer des favoris", + "listFilter_favorites": "Préférences" } diff --git a/lib/l10n/app_it.arb b/lib/l10n/app_it.arb index e08dd67..d6c02f0 100644 --- a/lib/l10n/app_it.arb +++ b/lib/l10n/app_it.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "Impossibile eliminare il canale \"{name}\"", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "it", "appTitle": "MeshCore Open", "nav_contacts": "Contatti", @@ -1744,5 +1750,8 @@ "type": "double" } } - } + }, + "listFilter_addToFavorites": "Aggiungi ai preferiti", + "listFilter_removeFromFavorites": "Rimuovi dai preferiti", + "listFilter_favorites": "Preferiti" } diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index 5d6a6a2..d64cdb0 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -4778,6 +4778,18 @@ abstract class AppLocalizations { /// **'Favorites'** String get listFilter_favorites; + /// No description provided for @listFilter_addToFavorites. + /// + /// In en, this message translates to: + /// **'Add to favorites'** + String get listFilter_addToFavorites; + + /// No description provided for @listFilter_removeFromFavorites. + /// + /// In en, this message translates to: + /// **'Remove from favorites'** + String get listFilter_removeFromFavorites; + /// No description provided for @listFilter_users. /// /// In en, this message translates to: diff --git a/lib/l10n/app_localizations_bg.dart b/lib/l10n/app_localizations_bg.dart index 513cdc3..f9637aa 100644 --- a/lib/l10n/app_localizations_bg.dart +++ b/lib/l10n/app_localizations_bg.dart @@ -2729,7 +2729,13 @@ class AppLocalizationsBg extends AppLocalizations { String get listFilter_all => 'Всички'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Любими'; + + @override + String get listFilter_addToFavorites => 'Добави към любими'; + + @override + String get listFilter_removeFromFavorites => 'Премахване от списъка с любими'; @override String get listFilter_users => 'Потребители'; diff --git a/lib/l10n/app_localizations_de.dart b/lib/l10n/app_localizations_de.dart index bada9f6..1574281 100644 --- a/lib/l10n/app_localizations_de.dart +++ b/lib/l10n/app_localizations_de.dart @@ -2736,6 +2736,12 @@ class AppLocalizationsDe extends AppLocalizations { @override String get listFilter_favorites => 'Favoriten'; + @override + String get listFilter_addToFavorites => 'Zu Favoriten hinzufügen'; + + @override + String get listFilter_removeFromFavorites => 'Aus Favoriten entfernen'; + @override String get listFilter_users => 'Benutzer'; diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index b090c45..039ad22 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -2689,6 +2689,12 @@ class AppLocalizationsEn extends AppLocalizations { @override String get listFilter_favorites => 'Favorites'; + @override + String get listFilter_addToFavorites => 'Add to favorites'; + + @override + String get listFilter_removeFromFavorites => 'Remove from favorites'; + @override String get listFilter_users => 'Users'; diff --git a/lib/l10n/app_localizations_es.dart b/lib/l10n/app_localizations_es.dart index ac51330..8961b18 100644 --- a/lib/l10n/app_localizations_es.dart +++ b/lib/l10n/app_localizations_es.dart @@ -2727,7 +2727,13 @@ class AppLocalizationsEs extends AppLocalizations { String get listFilter_all => 'Todas'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Favoritos'; + + @override + String get listFilter_addToFavorites => 'Añadir a favoritos'; + + @override + String get listFilter_removeFromFavorites => 'Eliminar de las favoritas'; @override String get listFilter_users => 'Usuarios'; diff --git a/lib/l10n/app_localizations_fr.dart b/lib/l10n/app_localizations_fr.dart index 3ca86e6..3737f46 100644 --- a/lib/l10n/app_localizations_fr.dart +++ b/lib/l10n/app_localizations_fr.dart @@ -2743,7 +2743,13 @@ class AppLocalizationsFr extends AppLocalizations { String get listFilter_all => 'Tout'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Préférences'; + + @override + String get listFilter_addToFavorites => 'Ajouter à mes favoris'; + + @override + String get listFilter_removeFromFavorites => 'Supprimer des favoris'; @override String get listFilter_users => 'Utilisateurs'; diff --git a/lib/l10n/app_localizations_it.dart b/lib/l10n/app_localizations_it.dart index c9900c7..b64ec6d 100644 --- a/lib/l10n/app_localizations_it.dart +++ b/lib/l10n/app_localizations_it.dart @@ -2727,7 +2727,13 @@ class AppLocalizationsIt extends AppLocalizations { String get listFilter_all => 'Tutti'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Preferiti'; + + @override + String get listFilter_addToFavorites => 'Aggiungi ai preferiti'; + + @override + String get listFilter_removeFromFavorites => 'Rimuovi dai preferiti'; @override String get listFilter_users => 'Utenti'; diff --git a/lib/l10n/app_localizations_nl.dart b/lib/l10n/app_localizations_nl.dart index 8c537f2..523cd6e 100644 --- a/lib/l10n/app_localizations_nl.dart +++ b/lib/l10n/app_localizations_nl.dart @@ -2718,7 +2718,13 @@ class AppLocalizationsNl extends AppLocalizations { String get listFilter_all => 'Alles'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Favorieten'; + + @override + String get listFilter_addToFavorites => 'Toevoegen aan favorieten'; + + @override + String get listFilter_removeFromFavorites => 'Verwijderen uit favorieten'; @override String get listFilter_users => 'Gebruikers'; diff --git a/lib/l10n/app_localizations_pl.dart b/lib/l10n/app_localizations_pl.dart index 2c11c82..1639600 100644 --- a/lib/l10n/app_localizations_pl.dart +++ b/lib/l10n/app_localizations_pl.dart @@ -2725,7 +2725,13 @@ class AppLocalizationsPl extends AppLocalizations { String get listFilter_all => 'Wszystko'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Ulubione'; + + @override + String get listFilter_addToFavorites => 'Dodaj do ulubionych'; + + @override + String get listFilter_removeFromFavorites => 'Usuń z ulubionych'; @override String get listFilter_users => 'Użytkownicy'; diff --git a/lib/l10n/app_localizations_pt.dart b/lib/l10n/app_localizations_pt.dart index c2fac6c..c59a4f5 100644 --- a/lib/l10n/app_localizations_pt.dart +++ b/lib/l10n/app_localizations_pt.dart @@ -2728,7 +2728,13 @@ class AppLocalizationsPt extends AppLocalizations { String get listFilter_all => 'Tudo'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Favoritos'; + + @override + String get listFilter_addToFavorites => 'Adicionar aos favoritos'; + + @override + String get listFilter_removeFromFavorites => 'Remover da lista de favoritos'; @override String get listFilter_users => 'Usuários'; diff --git a/lib/l10n/app_localizations_ru.dart b/lib/l10n/app_localizations_ru.dart index 9fde3b8..69d6044 100644 --- a/lib/l10n/app_localizations_ru.dart +++ b/lib/l10n/app_localizations_ru.dart @@ -2731,7 +2731,13 @@ class AppLocalizationsRu extends AppLocalizations { String get listFilter_all => 'Все'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Избранное'; + + @override + String get listFilter_addToFavorites => 'Добавить в избранное'; + + @override + String get listFilter_removeFromFavorites => 'Удалить из избранного'; @override String get listFilter_users => 'Пользователи'; diff --git a/lib/l10n/app_localizations_sk.dart b/lib/l10n/app_localizations_sk.dart index 5d31462..17cbd7b 100644 --- a/lib/l10n/app_localizations_sk.dart +++ b/lib/l10n/app_localizations_sk.dart @@ -2713,7 +2713,13 @@ class AppLocalizationsSk extends AppLocalizations { String get listFilter_all => 'Všetko'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Obľúbené'; + + @override + String get listFilter_addToFavorites => 'Pridaj do obľúbených'; + + @override + String get listFilter_removeFromFavorites => 'Odstrániť z označení'; @override String get listFilter_users => 'Používatelia'; diff --git a/lib/l10n/app_localizations_sl.dart b/lib/l10n/app_localizations_sl.dart index 19934e8..6478b2b 100644 --- a/lib/l10n/app_localizations_sl.dart +++ b/lib/l10n/app_localizations_sl.dart @@ -2716,7 +2716,13 @@ class AppLocalizationsSl extends AppLocalizations { String get listFilter_all => 'Vse'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Priljubljene'; + + @override + String get listFilter_addToFavorites => 'Dodaj v priljubljene'; + + @override + String get listFilter_removeFromFavorites => 'Odstrani iz priljubljenih'; @override String get listFilter_users => 'Uporabniki'; diff --git a/lib/l10n/app_localizations_sv.dart b/lib/l10n/app_localizations_sv.dart index 04ae835..54b998d 100644 --- a/lib/l10n/app_localizations_sv.dart +++ b/lib/l10n/app_localizations_sv.dart @@ -2701,7 +2701,13 @@ class AppLocalizationsSv extends AppLocalizations { String get listFilter_all => 'Alla'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Favoriter'; + + @override + String get listFilter_addToFavorites => 'Lägg till i favoriter'; + + @override + String get listFilter_removeFromFavorites => 'Ta bort från favoriter'; @override String get listFilter_users => 'Användare'; diff --git a/lib/l10n/app_localizations_uk.dart b/lib/l10n/app_localizations_uk.dart index 1c3442d..e3564f1 100644 --- a/lib/l10n/app_localizations_uk.dart +++ b/lib/l10n/app_localizations_uk.dart @@ -2738,7 +2738,13 @@ class AppLocalizationsUk extends AppLocalizations { String get listFilter_all => 'Все'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => 'Улюблені'; + + @override + String get listFilter_addToFavorites => 'Додати до улюблених'; + + @override + String get listFilter_removeFromFavorites => 'Видалити зі списку улюблених'; @override String get listFilter_users => 'Користувачі'; diff --git a/lib/l10n/app_localizations_zh.dart b/lib/l10n/app_localizations_zh.dart index 6a9881e..42f9130 100644 --- a/lib/l10n/app_localizations_zh.dart +++ b/lib/l10n/app_localizations_zh.dart @@ -2583,7 +2583,13 @@ class AppLocalizationsZh extends AppLocalizations { String get listFilter_all => '全部'; @override - String get listFilter_favorites => 'Favorites'; + String get listFilter_favorites => '收藏'; + + @override + String get listFilter_addToFavorites => '添加到收藏'; + + @override + String get listFilter_removeFromFavorites => '从收藏中移除'; @override String get listFilter_users => '用户'; diff --git a/lib/l10n/app_nl.arb b/lib/l10n/app_nl.arb index cb690fb..fee1f22 100644 --- a/lib/l10n/app_nl.arb +++ b/lib/l10n/app_nl.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "Kan kanaal {name} niet verwijderen", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "nl", "appTitle": "MeshCore Open", "nav_contacts": "Contacten", @@ -1744,5 +1750,8 @@ "type": "double" } } - } + }, + "listFilter_removeFromFavorites": "Verwijderen uit favorieten", + "listFilter_favorites": "Favorieten", + "listFilter_addToFavorites": "Toevoegen aan favorieten" } diff --git a/lib/l10n/app_pl.arb b/lib/l10n/app_pl.arb index 2161983..8096bb4 100644 --- a/lib/l10n/app_pl.arb +++ b/lib/l10n/app_pl.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "Nie udało się usunąć kanału \"{name}\"", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "pl", "appTitle": "MeshCore Open", "nav_contacts": "Kontakty", @@ -1744,5 +1750,8 @@ "type": "double" } } - } + }, + "listFilter_removeFromFavorites": "Usuń z ulubionych", + "listFilter_addToFavorites": "Dodaj do ulubionych", + "listFilter_favorites": "Ulubione" } diff --git a/lib/l10n/app_pt.arb b/lib/l10n/app_pt.arb index 8a02a4d..53f8f93 100644 --- a/lib/l10n/app_pt.arb +++ b/lib/l10n/app_pt.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "Falha ao excluir o canal \"{name}\"", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "pt", "appTitle": "MeshCore Open", "nav_contacts": "Contactos", @@ -1744,5 +1750,8 @@ "type": "double" } } - } + }, + "listFilter_addToFavorites": "Adicionar aos favoritos", + "listFilter_removeFromFavorites": "Remover da lista de favoritos", + "listFilter_favorites": "Favoritos" } diff --git a/lib/l10n/app_ru.arb b/lib/l10n/app_ru.arb index ab2ed36..b4d7b59 100644 --- a/lib/l10n/app_ru.arb +++ b/lib/l10n/app_ru.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "Не удалось удалить канал {name}.", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "ru", "appTitle": "MeshCore Open", "nav_contacts": "Контакты", @@ -984,5 +990,8 @@ "type": "double" } } - } + }, + "listFilter_addToFavorites": "Добавить в избранное", + "listFilter_favorites": "Избранное", + "listFilter_removeFromFavorites": "Удалить из избранного" } diff --git a/lib/l10n/app_sk.arb b/lib/l10n/app_sk.arb index ff95897..23a0aea 100644 --- a/lib/l10n/app_sk.arb +++ b/lib/l10n/app_sk.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "Kanál \"{name}\" sa nepodarilo odstrániť", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "sk", "appTitle": "MeshCore Open", "nav_contacts": "Kontakty", @@ -1744,5 +1750,8 @@ "type": "double" } } - } + }, + "listFilter_removeFromFavorites": "Odstrániť z označení", + "listFilter_addToFavorites": "Pridaj do obľúbených", + "listFilter_favorites": "Obľúbené" } diff --git a/lib/l10n/app_sl.arb b/lib/l10n/app_sl.arb index bd431d4..6b64f68 100644 --- a/lib/l10n/app_sl.arb +++ b/lib/l10n/app_sl.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "Kanala {name} ni bilo mogoče izbrisati", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "sl", "appTitle": "MeshCore Open", "nav_contacts": "Stiki", @@ -1744,5 +1750,8 @@ "type": "double" } } - } + }, + "listFilter_favorites": "Priljubljene", + "listFilter_removeFromFavorites": "Odstrani iz priljubljenih", + "listFilter_addToFavorites": "Dodaj v priljubljene" } diff --git a/lib/l10n/app_sv.arb b/lib/l10n/app_sv.arb index 86da858..3b96df7 100644 --- a/lib/l10n/app_sv.arb +++ b/lib/l10n/app_sv.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "Det gick inte att ta bort kanalen \"{name}\"", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "sv", "appTitle": "MeshCore Open", "nav_contacts": "Kontakter", @@ -1744,5 +1750,8 @@ "type": "double" } } - } + }, + "listFilter_removeFromFavorites": "Ta bort från favoriter", + "listFilter_addToFavorites": "Lägg till i favoriter", + "listFilter_favorites": "Favoriter" } diff --git a/lib/l10n/app_uk.arb b/lib/l10n/app_uk.arb index 691aa8d..78b4a90 100644 --- a/lib/l10n/app_uk.arb +++ b/lib/l10n/app_uk.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "Не вдалося видалити канал \"{name}\"", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "uk", "appTitle": "MeshCore Open", "nav_contacts": "Контакти", @@ -1744,5 +1750,8 @@ "type": "double" } } - } + }, + "listFilter_removeFromFavorites": "Видалити зі списку улюблених", + "listFilter_addToFavorites": "Додати до улюблених", + "listFilter_favorites": "Улюблені" } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index f6bb526..259e29b 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -1,6 +1,12 @@ { "channels_channelDeleteFailed": "无法删除频道 \"{name}\"", - "@channels_channelDeleteFailed": { "placeholders": { "name": { "type": "String" } } }, + "@channels_channelDeleteFailed": { + "placeholders": { + "name": { + "type": "String" + } + } + }, "@@locale": "zh", "appTitle": "MeshCore Open", "nav_contacts": "联系方式", @@ -1744,5 +1750,8 @@ "type": "double" } } - } + }, + "listFilter_favorites": "收藏", + "listFilter_addToFavorites": "添加到收藏", + "listFilter_removeFromFavorites": "从收藏中移除" } diff --git a/lib/screens/contacts_screen.dart b/lib/screens/contacts_screen.dart index 28e7aa5..e9018a7 100644 --- a/lib/screens/contacts_screen.dart +++ b/lib/screens/contacts_screen.dart @@ -518,6 +518,7 @@ class _ContactsScreenState extends State }) .where((group) { if (_typeFilter == ContactTypeFilter.all) return true; + // Groups don't have a favorite flag, so hide them under favorites filter if (_typeFilter == ContactTypeFilter.favorites) return false; for (final key in group.memberKeys) { final contact = contactsByKey[key]; @@ -1099,8 +1100,8 @@ class _ContactsScreenState extends State ), title: Text( isFavorite - ? '${context.l10n.common_remove} ${context.l10n.listFilter_favorites}' - : '${context.l10n.common_add} ${context.l10n.listFilter_favorites}', + ? context.l10n.listFilter_removeFromFavorites + : context.l10n.listFilter_addToFavorites, ), onTap: () async { Navigator.pop(sheetContext); diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 4084d9b..d2ea57e 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -9,7 +9,6 @@ import flutter_blue_plus_darwin import flutter_local_notifications import mobile_scanner import package_info_plus -import path_provider_foundation import share_plus import shared_preferences_foundation import sqflite_darwin @@ -21,7 +20,6 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { FlutterLocalNotificationsPlugin.register(with: registry.registrar(forPlugin: "FlutterLocalNotificationsPlugin")) MobileScannerPlugin.register(with: registry.registrar(forPlugin: "MobileScannerPlugin")) FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) - PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) SharePlusMacosPlugin.register(with: registry.registrar(forPlugin: "SharePlusMacosPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) SqflitePlugin.register(with: registry.registrar(forPlugin: "SqflitePlugin")) diff --git a/untranslated.json b/untranslated.json index a6d2937..9e26dfe 100644 --- a/untranslated.json +++ b/untranslated.json @@ -1,53 +1 @@ -{ - "bg": [ - "listFilter_favorites" - ], - - "es": [ - "listFilter_favorites" - ], - - "fr": [ - "listFilter_favorites" - ], - - "it": [ - "listFilter_favorites" - ], - - "nl": [ - "listFilter_favorites" - ], - - "pl": [ - "listFilter_favorites" - ], - - "pt": [ - "listFilter_favorites" - ], - - "ru": [ - "listFilter_favorites" - ], - - "sk": [ - "listFilter_favorites" - ], - - "sl": [ - "listFilter_favorites" - ], - - "sv": [ - "listFilter_favorites" - ], - - "uk": [ - "listFilter_favorites" - ], - - "zh": [ - "listFilter_favorites" - ] -} +{} \ No newline at end of file From ea379ce50b3fd98341d4b39710536603569c4200 Mon Sep 17 00:00:00 2001 From: zjs81 Date: Tue, 24 Feb 2026 20:11:56 -0700 Subject: [PATCH 10/10] Fix dart format line length in contacts_screen.dart --- lib/screens/contacts_screen.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/screens/contacts_screen.dart b/lib/screens/contacts_screen.dart index e9018a7..6c683cc 100644 --- a/lib/screens/contacts_screen.dart +++ b/lib/screens/contacts_screen.dart @@ -1239,7 +1239,8 @@ class _ContactTile extends StatelessWidget { children: [ if (isFavorite) Icon(Icons.star, size: 14, color: Colors.amber[700]), - if (isFavorite && contact.hasLocation) const SizedBox(width: 2), + if (isFavorite && contact.hasLocation) + const SizedBox(width: 2), if (contact.hasLocation) Icon(Icons.location_on, size: 14, color: Colors.grey[400]), ],