diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index eb21ac821..48323d5fa 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -1077,7 +1077,7 @@ Color str2color(String str, [alpha = 0xFF]) { return Color((hash & 0xFF7FFF) | (alpha << 24)); } -Color str2color2(String str, [alpha = 0xFF]) { +Color str2color2(String str, {List existing = const []}) { Map colorMap = { "red": Colors.red, "green": Colors.green, @@ -1094,10 +1094,10 @@ Color str2color2(String str, [alpha = 0xFF]) { }; final color = colorMap[str.toLowerCase()]; if (color != null) { - return color.withAlpha(alpha); + return color.withAlpha(0xFF); } if (str.toLowerCase() == 'yellow') { - return Colors.yellow.withAlpha(alpha); + return Colors.yellow.withAlpha(0xFF); } var hash = 0; for (var i = 0; i < str.length; i++) { @@ -1105,7 +1105,15 @@ Color str2color2(String str, [alpha = 0xFF]) { } List colorList = colorMap.values.toList(); hash = hash % colorList.length; - return colorList[hash].withAlpha(alpha); + var result = colorList[hash].withAlpha(0xFF); + if (existing.contains(result.value)) { + Color? notUsed = + colorList.firstWhereOrNull((e) => !existing.contains(e.value)); + if (notUsed != null) { + result = notUsed; + } + } + return result; } const K = 1024; diff --git a/flutter/lib/common/widgets/address_book.dart b/flutter/lib/common/widgets/address_book.dart index 86a5b2c55..292266ae7 100644 --- a/flutter/lib/common/widgets/address_book.dart +++ b/flutter/lib/common/widgets/address_book.dart @@ -7,6 +7,7 @@ import 'package:flutter_hbb/models/ab_model.dart'; import 'package:flutter_hbb/models/platform_model.dart'; import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu; import 'package:get/get.dart'; +import 'package:flex_color_picker/flex_color_picker.dart'; import '../../common.dart'; import 'dialog.dart'; @@ -513,7 +514,7 @@ class AddressBookTag extends StatelessWidget { child: Obx(() => Container( decoration: BoxDecoration( color: tags.contains(name) - ? str2color2(name, 0xFF) + ? gFFI.abModel.getTagColor(name) : Theme.of(context).colorScheme.background, borderRadius: BorderRadius.circular(4)), margin: const EdgeInsets.symmetric(horizontal: 4.0, vertical: 4.0), @@ -528,7 +529,7 @@ class AddressBookTag extends StatelessWidget { shape: BoxShape.circle, color: tags.contains(name) ? Colors.white - : str2color2(name)), + : gFFI.abModel.getTagColor(name)), ).marginOnly(right: radius / 2), Expanded( child: Text(name, @@ -568,6 +569,23 @@ class AddressBookTag extends StatelessWidget { Future.delayed(Duration.zero, () => Get.back()); }); }), + getEntry(translate(translate('Change Color')), () async { + final model = gFFI.abModel; + Color oldColor = model.getTagColor(name); + Color newColor = await showColorPickerDialog( + context, + oldColor, + pickersEnabled: { + ColorPickerType.accent: false, + ColorPickerType.wheel: true, + }, + showColorCode: true, + ); + if (oldColor != newColor) { + model.setTagColor(name, newColor); + model.pushAb(); + } + }), getEntry(translate("Delete"), () { gFFI.abModel.deleteTag(name); gFFI.abModel.pushAb(); diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index 8bb4fdfdb..74f0dcb31 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -201,7 +201,8 @@ class _PeerCardState extends State<_PeerCard> ) ], ); - final colors = _frontN(peer.tags, 25).map((e) => str2color2(e)).toList(); + final colors = + _frontN(peer.tags, 25).map((e) => gFFI.abModel.getTagColor(e)).toList(); return Tooltip( message: isMobile ? '' @@ -311,7 +312,8 @@ class _PeerCardState extends State<_PeerCard> ), ); - final colors = _frontN(peer.tags, 25).map((e) => str2color2(e)).toList(); + final colors = + _frontN(peer.tags, 25).map((e) => gFFI.abModel.getTagColor(e)).toList(); return Tooltip( message: peer.tags.isNotEmpty ? '${translate('Tags')}: ${peer.tags.join(', ')}' diff --git a/flutter/lib/models/ab_model.dart b/flutter/lib/models/ab_model.dart index f5e217472..e91e42ef9 100644 --- a/flutter/lib/models/ab_model.dart +++ b/flutter/lib/models/ab_model.dart @@ -28,6 +28,7 @@ class AbModel { final pullError = "".obs; final pushError = "".obs; final tags = [].obs; + final RxMap tagColors = Map.fromEntries([]).obs; final peers = List.empty(growable: true).obs; final sortTags = shouldSortTags().obs; final retrying = false.obs; @@ -80,10 +81,11 @@ class AbModel { if (resp.body.toLowerCase() == "null") { // normal reply, emtpy ab return null tags.clear(); + tagColors.clear(); peers.clear(); } else if (resp.body.isNotEmpty) { Map json = - _jsonDecode(utf8.decode(resp.bodyBytes), resp.statusCode); + _jsonDecodeResp(utf8.decode(resp.bodyBytes), resp.statusCode); if (json.containsKey('error')) { throw json['error']; } else if (json.containsKey('data')) { @@ -93,26 +95,7 @@ class AbModel { } catch (e) {} final data = jsonDecode(json['data']); if (data != null) { - final oldOnlineIDs = - peers.where((e) => e.online).map((e) => e.id).toList(); - tags.clear(); - peers.clear(); - if (data['tags'] is List) { - tags.value = data['tags']; - } - if (data['peers'] is List) { - for (final peer in data['peers']) { - peers.add(Peer.fromJson(peer)); - } - } - if (isFull(false)) { - peers.removeRange(licensedDevices, peers.length); - } - // restore online - peers - .where((e) => oldOnlineIDs.contains(e.id)) - .map((e) => e.online = true) - .toList(); + _deserialize(data); _saveCache(); // save on success } } @@ -242,10 +225,7 @@ class AbModel { final api = "${await bind.mainGetApiServer()}/api/ab"; var authHeaders = getHttpHeaders(); authHeaders['Content-Type'] = "application/json"; - final peersJsonData = peers.map((e) => e.toAbUploadJson()).toList(); - final body = jsonEncode({ - "data": jsonEncode({"tags": tags, "peers": peersJsonData}) - }); + final body = jsonEncode(_serialize()); http.Response resp; // support compression if (licensedDevices > 0 && body.length > 1024) { @@ -261,7 +241,7 @@ class AbModel { ret = true; _saveCache(); } else { - Map json = _jsonDecode(resp.body, resp.statusCode); + Map json = _jsonDecodeResp(resp.body, resp.statusCode); if (json.containsKey('error')) { throw json['error']; } else if (resp.statusCode == 200) { @@ -318,6 +298,7 @@ class AbModel { void deleteTag(String tag) { gFFI.abModel.selectedTags.remove(tag); tags.removeWhere((element) => element == tag); + tagColors.remove(tag); for (var peer in peers) { if (peer.tags.isEmpty) { continue; @@ -353,6 +334,11 @@ class AbModel { } }).toList(); } + int? oldColor = tagColors[oldTag]; + if (oldColor != null) { + tagColors.remove(oldTag); + tagColors.addAll({newTag: oldColor}); + } } void unsetSelectedTags() { @@ -368,6 +354,20 @@ class AbModel { } } + Color getTagColor(String tag) { + int? colorValue = tagColors[tag]; + if (colorValue != null) { + return Color(colorValue); + } + return str2color2(tag, existing: tagColors.values.toList()); + } + + setTagColor(String tag, Color color) { + if (tags.contains(tag)) { + tagColors[tag] = color.value; + } + } + void merge(Peer r, Peer p) { p.hash = r.hash.isEmpty ? p.hash : r.hash; p.username = r.username.isEmpty ? p.username : r.username; @@ -467,12 +467,10 @@ class AbModel { _saveCache() { try { - final peersJsonData = peers.map((e) => e.toAbUploadJson()).toList(); - final m = { + var m = _serialize(); + m.addAll({ "access_token": bind.mainGetLocalOption(key: 'access_token'), - "peers": peersJsonData, - "tags": tags.map((e) => e.toString()).toList(), - }; + }); bind.mainSaveAb(json: jsonEncode(m)); } catch (e) { debugPrint('ab save:$e'); @@ -488,22 +486,13 @@ class AbModel { final cache = await bind.mainLoadAb(); final data = jsonDecode(cache); if (data == null || data['access_token'] != access_token) return; - tags.clear(); - peers.clear(); - if (data['tags'] is List) { - tags.value = data['tags']; - } - if (data['peers'] is List) { - for (final peer in data['peers']) { - peers.add(Peer.fromJson(peer)); - } - } + _deserialize(data); } catch (e) { debugPrint("load ab cache: $e"); } } - Map _jsonDecode(String body, int statusCode) { + Map _jsonDecodeResp(String body, int statusCode) { try { Map json = jsonDecode(body); return json; @@ -516,6 +505,50 @@ class AbModel { } } + Map _serialize() { + final peersJsonData = peers.map((e) => e.toAbUploadJson()).toList(); + final tagColorJsonData = jsonEncode(tagColors); + return { + "tags": tags, + "peers": peersJsonData, + "tag_colors": tagColorJsonData + }; + } + + _deserialize(dynamic data) { + if (data == null) return; + final oldOnlineIDs = peers.where((e) => e.online).map((e) => e.id).toList(); + tags.clear(); + tagColors.clear(); + peers.clear(); + if (data['tags'] is List) { + tags.value = data['tags']; + } + if (data['peers'] is List) { + for (final peer in data['peers']) { + peers.add(Peer.fromJson(peer)); + } + } + if (isFull(false)) { + peers.removeRange(licensedDevices, peers.length); + } + // restore online + peers + .where((e) => oldOnlineIDs.contains(e.id)) + .map((e) => e.online = true) + .toList(); + if (data['tag_colors'] is String) { + Map map = jsonDecode(data['tag_colors']); + tagColors.value = Map.from(map); + } + // add color to tag + final tagsWithoutColor = + tags.toList().where((e) => !tagColors.containsKey(e)).toList(); + for (var t in tagsWithoutColor) { + tagColors[t] = str2color2(t, existing: tagColors.values.toList()).value; + } + } + reSyncToast(Future future) { if (!shouldSyncAb()) return; Future.delayed(Duration.zero, () async { diff --git a/flutter/pubspec.yaml b/flutter/pubspec.yaml index fc0be7018..04af8f92f 100644 --- a/flutter/pubspec.yaml +++ b/flutter/pubspec.yaml @@ -97,6 +97,7 @@ dependencies: dropdown_button2: ^2.0.0 uuid: ^3.0.7 auto_size_text_field: ^2.2.1 + flex_color_picker: ^3.3.0 dev_dependencies: icons_launcher: ^2.0.4 diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 2cb0072c5..f40ff1463 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -1525,6 +1525,12 @@ pub struct Ab { pub peers: Vec, #[serde(default, deserialize_with = "deserialize_vec_string")] pub tags: Vec, + #[serde( + default, + deserialize_with = "deserialize_string", + skip_serializing_if = "String::is_empty" + )] + pub tag_colors: String, } impl Ab { diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 739d5646b..4801abcae 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index 34ecdb276..3313537d1 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", "未成功获取地址簿"), ("push_ab_failed_tip", "未成功上传地址簿"), ("synced_peer_readded_tip", "最近会话中存在的设备将会被重新同步到地址簿。"), + ("Change Color", "更改颜色"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index e32246da7..3d913b0d6 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", "Nepodařilo se obnovit adresář"), ("push_ab_failed_tip", "Nepodařilo se synchronizovat adresář se serverem"), ("synced_peer_readded_tip", "Zařízení, která byla přítomna v posledních relacích, budou synchronizována zpět do adresáře."), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index 830cb0c45..afaf98386 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 53a898a6a..8eb066f30 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", "Aktualisierung des Adressbuchs fehlgeschlagen"), ("push_ab_failed_tip", "Synchronisierung des Adressbuchs mit dem Server fehlgeschlagen"), ("synced_peer_readded_tip", "Die Geräte, die in den letzten Sitzungen vorhanden waren, werden erneut zum Adressbuch hinzugefügt."), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/el.rs b/src/lang/el.rs index 46f816677..56805e574 100644 --- a/src/lang/el.rs +++ b/src/lang/el.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 8d7f1c873..bcb467839 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index aabbbfd27..5384dfead 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", "No se ha podido refrescar el directorio"), ("push_ab_failed_tip", "No se ha podido sincronizar el directorio con el servidor"), ("synced_peer_readded_tip", "Los dispositivos presentes en sesiones recientes se sincronizarán con el directorio."), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index eeb36af3b..fab82f661 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index fdf9cdf51..24cc268ee 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", "Impossible d'actualiser le carnet d'adresses"), ("push_ab_failed_tip", "Échec de la synchronisation du carnet d'adresses"), ("synced_peer_readded_tip", "Les appareils qui étaient présents dans les sessions récentes seront synchronisés avec le carnet d'adresses."), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 2da6bd72e..aaf888d23 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 45cb3f1c8..a7b12f2ed 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", "Gagal memuat ulang buku alamat"), ("push_ab_failed_tip", "Gagal menyinkronkan buku alamat ke server"), ("synced_peer_readded_tip", "Perangkat yang terdaftar dalam sesi-sesi terbaru akan di-sinkronkan kembali ke buku alamat."), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 4febb9e00..3b8bd8416 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", "Impossibile aggiornare la rubrica"), ("push_ab_failed_tip", "Impossibile sincronizzare la rubrica con il server"), ("synced_peer_readded_tip", "I dispositivi presenti nelle sessioni recenti saranno sincronizzati di nuovo nella rubrica."), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 4c4d6e141..1a9e8da4f 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index 91e49be3a..28c34f7e2 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 807b74ba4..2fb2b8b92 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/lt.rs b/src/lang/lt.rs index 0cd258b9e..6a8c7e9f5 100644 --- a/src/lang/lt.rs +++ b/src/lang/lt.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/nl.rs b/src/lang/nl.rs index c37e95c89..3b08427df 100644 --- a/src/lang/nl.rs +++ b/src/lang/nl.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index 923dadc22..67b9d188a 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 3eb850227..416600eeb 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index 40360be5a..98e469f7e 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ro.rs b/src/lang/ro.rs index 50ae39902..f4d44b3ae 100644 --- a/src/lang/ro.rs +++ b/src/lang/ro.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index 5830525d9..37fdb2060 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", "Невозможно обновить адресную книгу"), ("push_ab_failed_tip", "Невозможно синхронизировать адресную книгу с сервером"), ("synced_peer_readded_tip", "Устройства, присутствовавшие в последних сеансах, будут синхронизированы с адресной книгой."), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index 4b7ced046..8421bd2b0 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sl.rs b/src/lang/sl.rs index 6b356a238..f4c5ff385 100755 --- a/src/lang/sl.rs +++ b/src/lang/sl.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index 5eb5c0fb4..11e3e1ccb 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sr.rs b/src/lang/sr.rs index f642bc124..494999475 100644 --- a/src/lang/sr.rs +++ b/src/lang/sr.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index 76ea47cd4..4c0f73f5a 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index 06591d147..ee7fb0d46 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/th.rs b/src/lang/th.rs index 6e21420fa..e6f12d85e 100644 --- a/src/lang/th.rs +++ b/src/lang/th.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 15aaac5f7..bb3ab5de6 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index 6d9d8089c..8f28395d3 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", "未成功獲取地址簿"), ("push_ab_failed_tip", "未成功上傳地址簿"), ("synced_peer_readded_tip", "最近會話中存在的設備將會被重新同步到地址簿。"), + ("Change Color", "更改顏色"), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index acdf8f106..69ca7c2da 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index 8aeafd930..7a0cce355 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -538,5 +538,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("pull_ab_failed_tip", ""), ("push_ab_failed_tip", ""), ("synced_peer_readded_tip", ""), + ("Change Color", ""), ].iter().cloned().collect(); }