From 5616b20879fc6ec5e97e06296606b605b43ff71f Mon Sep 17 00:00:00 2001 From: 21pages Date: Sun, 27 Nov 2022 12:16:45 +0800 Subject: [PATCH 1/3] opt add ab id Signed-off-by: 21pages --- flutter/lib/common/widgets/address_book.dart | 105 ++++++++++++++----- flutter/lib/common/widgets/peer_card.dart | 29 +++++ flutter/lib/models/ab_model.dart | 14 ++- src/lang/ca.rs | 1 + src/lang/cn.rs | 1 + src/lang/cs.rs | 1 + src/lang/da.rs | 1 + src/lang/de.rs | 1 + src/lang/eo.rs | 1 + src/lang/es.rs | 1 + src/lang/fa.rs | 1 + src/lang/fr.rs | 1 + src/lang/gr.rs | 1 + src/lang/hu.rs | 1 + src/lang/id.rs | 1 + src/lang/it.rs | 1 + src/lang/ja.rs | 1 + src/lang/ko.rs | 1 + src/lang/kz.rs | 1 + src/lang/pl.rs | 1 + src/lang/pt_PT.rs | 1 + src/lang/ptbr.rs | 1 + src/lang/ru.rs | 1 + src/lang/sk.rs | 1 + src/lang/sq.rs | 1 + src/lang/sv.rs | 1 + src/lang/template.rs | 1 + src/lang/tr.rs | 1 + src/lang/tw.rs | 1 + src/lang/ua.rs | 1 + src/lang/vn.rs | 1 + 31 files changed, 148 insertions(+), 28 deletions(-) diff --git a/flutter/lib/common/widgets/address_book.dart b/flutter/lib/common/widgets/address_book.dart index 5b3527fa0..799b0be67 100644 --- a/flutter/lib/common/widgets/address_book.dart +++ b/flutter/lib/common/widgets/address_book.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:flutter_hbb/common/formatter/id_formatter.dart'; import 'package:flutter_hbb/common/widgets/peer_card.dart'; import 'package:flutter_hbb/common/widgets/peers_view.dart'; import 'package:flutter_hbb/desktop/widgets/popup_menu.dart'; @@ -237,29 +238,32 @@ class _AddressBookState extends State { } void abAddId() async { - var field = ""; - var msg = ""; var isInProgress = false; - TextEditingController controller = TextEditingController(text: field); + IDTextEditingController idController = IDTextEditingController(text: ''); + TextEditingController aliasController = TextEditingController(text: ''); + final tags = List.of(gFFI.abModel.tags); + var selectedTag = List.empty(growable: true).obs; + final style = TextStyle(fontSize: 14.0); + String? errorMsg; gFFI.dialogManager.show((setState, close) { submit() async { setState(() { - msg = ""; isInProgress = true; + errorMsg = null; }); - field = controller.text.trim(); - if (field.isEmpty) { + String id = idController.id; + if (id.isEmpty) { // pass } else { - final ids = field.trim().split(RegExp(r"[\s,;\n]+")); - field = ids.join(','); - for (final newId in ids) { - if (gFFI.abModel.idContainBy(newId)) { - continue; - } - gFFI.abModel.addId(newId); + if (gFFI.abModel.idContainBy(id)) { + setState(() { + isInProgress = false; + errorMsg = translate('ID already exists'); + }); + return; } + gFFI.abModel.addId(id, aliasController.text.trim(), selectedTag); await gFFI.abModel.pushAb(); this.setState(() {}); // final currentPeers @@ -272,21 +276,70 @@ class _AddressBookState extends State { content: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - Text(translate("whitelist_sep")), - const SizedBox( - height: 8.0, - ), - Row( + Column( children: [ - Expanded( - child: TextField( - maxLines: null, - decoration: InputDecoration( - border: const OutlineInputBorder(), - errorText: msg.isEmpty ? null : translate(msg), + Align( + alignment: Alignment.centerLeft, + child: Row( + children: [ + Text( + '*', + style: TextStyle(color: Colors.red, fontSize: 14), ), - controller: controller, - focusNode: FocusNode()..requestFocus()), + Text( + 'ID', + style: style, + ), + ], + ), + ), + TextField( + controller: idController, + inputFormatters: [IDTextInputFormatter()], + decoration: InputDecoration( + isDense: true, + border: OutlineInputBorder(), + errorText: errorMsg), + style: style, + ), + Align( + alignment: Alignment.centerLeft, + child: Text( + translate('Alias'), + style: style, + ), + ).marginOnly(top: 8, bottom: 2), + TextField( + controller: aliasController, + decoration: InputDecoration( + border: OutlineInputBorder(), + isDense: true, + ), + style: style, + ), + Align( + alignment: Alignment.centerLeft, + child: Text( + translate('Tags'), + style: style, + ), + ).marginOnly(top: 8), + Container( + child: Wrap( + children: tags + .map((e) => AddressBookTag( + name: e, + tags: selectedTag, + onTap: () { + if (selectedTag.contains(e)) { + selectedTag.remove(e); + } else { + selectedTag.add(e); + } + }, + showActionMenu: false)) + .toList(growable: false), + ), ), ], ), diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index 8df84af6c..4486a6e27 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -586,6 +586,26 @@ abstract class BasePeerCard extends StatelessWidget { ); } + @protected + MenuEntryBase _addToAb(Peer peer) { + return MenuEntryButton( + childBuilder: (TextStyle? style) => Text( + translate('Add to Address Book'), + style: style, + ), + proc: () { + () async { + if (!gFFI.abModel.idContainBy(peer.id)) { + gFFI.abModel.addPeer(peer); + await gFFI.abModel.pushAb(); + } + }(); + }, + padding: menuPadding, + dismissOnClicked: true, + ); + } + void _rename(String id, bool isAddressBook) async { RxBool isInProgress = false.obs; var name = peer.alias; @@ -679,6 +699,9 @@ class RecentPeerCard extends BasePeerCard { menuItems.add(_unrememberPasswordAction(peer.id)); } menuItems.add(_addFavAction(peer.id)); + if (!gFFI.abModel.idContainBy(peer.id)) { + menuItems.add(_addToAb(peer)); + } return menuItems; } } @@ -716,6 +739,9 @@ class FavoritePeerCard extends BasePeerCard { menuItems.add(_rmFavAction(peer.id, () async { await bind.mainLoadFavPeers(); })); + if (!gFFI.abModel.idContainBy(peer.id)) { + menuItems.add(_addToAb(peer)); + } return menuItems; } } @@ -744,6 +770,9 @@ class DiscoveredPeerCard extends BasePeerCard { } menuItems.add(MenuEntryDivider()); menuItems.add(_removeAction(peer.id, () async {})); + if (!gFFI.abModel.idContainBy(peer.id)) { + menuItems.add(_addToAb(peer)); + } return menuItems; } } diff --git a/flutter/lib/models/ab_model.dart b/flutter/lib/models/ab_model.dart index afee97e75..a24c01366 100644 --- a/flutter/lib/models/ab_model.dart +++ b/flutter/lib/models/ab_model.dart @@ -68,11 +68,21 @@ class AbModel { peers.clear(); } - void addId(String id) async { + void addId(String id, String alias, List tags) { if (idContainBy(id)) { return; } - peers.add(Peer.fromJson({"id": id})); + final peer = Peer.fromJson({ + 'id': id, + 'alias': alias, + 'tags': tags, + }); + peers.add(peer); + } + + void addPeer(Peer peer) { + peers.removeWhere((e) => e.id == peer.id); + peers.add(peer); } void addTag(String tag) async { diff --git a/src/lang/ca.rs b/src/lang/ca.rs index 6fc919b8d..70190729c 100644 --- a/src/lang/ca.rs +++ b/src/lang/ca.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/cn.rs b/src/lang/cn.rs index c429d9539..daa2af065 100644 --- a/src/lang/cn.rs +++ b/src/lang/cn.rs @@ -400,5 +400,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("wayland_experiment_tip", ""), ("Right click to select tabs", "右键选择选项卡"), ("Skipped", "已跳过"), + ("Add to Address Book", "添加到地址簿"), ].iter().cloned().collect(); } diff --git a/src/lang/cs.rs b/src/lang/cs.rs index 6455023de..33c6492f7 100644 --- a/src/lang/cs.rs +++ b/src/lang/cs.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/da.rs b/src/lang/da.rs index afd6476ee..1aa53ca57 100644 --- a/src/lang/da.rs +++ b/src/lang/da.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/de.rs b/src/lang/de.rs index 273a607ed..223237def 100644 --- a/src/lang/de.rs +++ b/src/lang/de.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", "Dies ist nur möglich, wenn der Zugriff nur über ein permanentes Passwort erfolgt."), // Sehr unklar. Muss noch angepasst werden. Original: Allow hiding only if accepting sessions via password and using pernament passw"), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/eo.rs b/src/lang/eo.rs index 3a38b6601..c2748a9bc 100644 --- a/src/lang/eo.rs +++ b/src/lang/eo.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/es.rs b/src/lang/es.rs index d8b00b9bf..1069b4905 100644 --- a/src/lang/es.rs +++ b/src/lang/es.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", "Permitir ocultar solo si se aceptan sesiones a través de contraseña y usando contraseña permanente"), ("wayland_experiment_tip", "El soporte para Wayland está en fase experimental, por favor, use X11 si necesita acceso desatendido."), ("Right click to select tabs", "Clic derecho para seleccionar pestañas"), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fa.rs b/src/lang/fa.rs index 7513f84e8..11c17887a 100644 --- a/src/lang/fa.rs +++ b/src/lang/fa.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", "فقط در صورت پذیرفتن جلسات از طریق رمز عبور و استفاده از رمز عبور دائمی، مخفی شدن مجاز است"), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/fr.rs b/src/lang/fr.rs index a4eedfa2a..c3d241bf8 100644 --- a/src/lang/fr.rs +++ b/src/lang/fr.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", "Autoriser le masquage uniquement si vous acceptez des sessions via un mot de passe et utilisez un mot de passe permanent"), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/gr.rs b/src/lang/gr.rs index e4055e16f..ecabd8f31 100644 --- a/src/lang/gr.rs +++ b/src/lang/gr.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", "Να επιτρέπεται η απόκρυψη, μόνο εάν αποδέχεστε συνδέσεις μέσω κωδικού πρόσβασης και χρησιμοποιείτε μόνιμο κωδικό πρόσβασης"), ("wayland_experiment_tip", "Η υποστήριξη Wayland βρίσκεται σε πειραματικό στάδιο, χρησιμοποιήστε το X11 εάν χρειάζεστε πρόσβαση χωρίς επίβλεψη."), ("Right click to select tabs", "Κάντε δεξί κλικ για να επιλέξετε καρτέλες"), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/hu.rs b/src/lang/hu.rs index 941caeac1..d0f2f4412 100644 --- a/src/lang/hu.rs +++ b/src/lang/hu.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/id.rs b/src/lang/id.rs index 7f4a50523..b8f9e392d 100644 --- a/src/lang/id.rs +++ b/src/lang/id.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/it.rs b/src/lang/it.rs index 98ea9366e..f11a06c80 100644 --- a/src/lang/it.rs +++ b/src/lang/it.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", "Permetti di nascondere solo se si accettano sessioni con password permanente"), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ja.rs b/src/lang/ja.rs index 4121dd55c..4ca33e76a 100644 --- a/src/lang/ja.rs +++ b/src/lang/ja.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ko.rs b/src/lang/ko.rs index a1cd730e9..93338165b 100644 --- a/src/lang/ko.rs +++ b/src/lang/ko.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/kz.rs b/src/lang/kz.rs index 1e623c0b6..a7d6f299d 100644 --- a/src/lang/kz.rs +++ b/src/lang/kz.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pl.rs b/src/lang/pl.rs index ed14e3ca2..d3f991d44 100644 --- a/src/lang/pl.rs +++ b/src/lang/pl.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/pt_PT.rs b/src/lang/pt_PT.rs index 65620e3e8..4a457218c 100644 --- a/src/lang/pt_PT.rs +++ b/src/lang/pt_PT.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ptbr.rs b/src/lang/ptbr.rs index cf388a88c..af59e4f2e 100644 --- a/src/lang/ptbr.rs +++ b/src/lang/ptbr.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/ru.rs b/src/lang/ru.rs index e7cc686c2..ff8dfc316 100644 --- a/src/lang/ru.rs +++ b/src/lang/ru.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", "Разрешать скрытие случае, если принимаются сеансы по паролю или используется постоянный пароль"), ("wayland_experiment_tip", "Поддержка Wayland находится на экспериментальной стадии, используйте X11, если вам требуется автоматический доступ."), ("Right click to select tabs", "Выбор вкладок щелчком правой кнопки мыши"), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sk.rs b/src/lang/sk.rs index e7a9b12b5..13672d086 100644 --- a/src/lang/sk.rs +++ b/src/lang/sk.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sq.rs b/src/lang/sq.rs index 1926c849b..5ec59c4be 100644 --- a/src/lang/sq.rs +++ b/src/lang/sq.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", "Kjo është e mundur vetëm nëse aksesi bëhet nëpërmjet një fjalëkalimi të përhershëm"), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/sv.rs b/src/lang/sv.rs index cfef903a7..1feb5d55e 100644 --- a/src/lang/sv.rs +++ b/src/lang/sv.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", "Tillåt att gömma endast om accepterande sessioner med lösenord och permanenta lösenord"), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/template.rs b/src/lang/template.rs index ed7189ce6..6993cb43c 100644 --- a/src/lang/template.rs +++ b/src/lang/template.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tr.rs b/src/lang/tr.rs index 6c518da81..7b66af60e 100644 --- a/src/lang/tr.rs +++ b/src/lang/tr.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/tw.rs b/src/lang/tw.rs index e7c024420..6f0e8806b 100644 --- a/src/lang/tw.rs +++ b/src/lang/tw.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", "在只允許密碼連接並且只用固定密碼的情況下才允許隱藏"), ("wayland_experiment_tip", ""), ("Right click to select tabs", "右鍵選擇選項卡"), + ("Add to Address Book", "添加到地址簿"), ].iter().cloned().collect(); } diff --git a/src/lang/ua.rs b/src/lang/ua.rs index 713d15c69..92fd2db8a 100644 --- a/src/lang/ua.rs +++ b/src/lang/ua.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } diff --git a/src/lang/vn.rs b/src/lang/vn.rs index c59de33fc..1d32aad5e 100644 --- a/src/lang/vn.rs +++ b/src/lang/vn.rs @@ -399,5 +399,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> = ("hide_cm_tip", ""), ("wayland_experiment_tip", ""), ("Right click to select tabs", ""), + ("Add to Address Book", ""), ].iter().cloned().collect(); } From 6f7eb17c48478f1fb058b4401dbd27da424b8ae6 Mon Sep 17 00:00:00 2001 From: 21pages Date: Mon, 28 Nov 2022 18:16:29 +0800 Subject: [PATCH 2/3] ab: read respectively and sync when set Signed-off-by: 21pages --- flutter/lib/common.dart | 6 +- flutter/lib/common/widgets/peer_card.dart | 152 ++++++++++++++-------- flutter/lib/models/ab_model.dart | 29 ++++- flutter/lib/models/peer_model.dart | 30 ++++- src/flutter_ffi.rs | 47 +------ src/ui_interface.rs | 13 ++ 6 files changed, 165 insertions(+), 112 deletions(-) diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart index 4c298d917..b9077b0cb 100644 --- a/flutter/lib/common.dart +++ b/flutter/lib/common.dart @@ -923,7 +923,8 @@ bool option2bool(String option, String value) { } else if (option.startsWith("allow-") || option == "stop-service" || option == "direct-server" || - option == "stop-rendezvous-service") { + option == "stop-rendezvous-service" || + option == "force-always-relay") { res = value == "Y"; } else { assert(false); @@ -939,7 +940,8 @@ String bool2option(String option, bool b) { } else if (option.startsWith('allow-') || option == "stop-service" || option == "direct-server" || - option == "stop-rendezvous-service") { + option == "stop-rendezvous-service" || + option == "force-always-relay") { res = b ? 'Y' : ''; } else { assert(false); diff --git a/flutter/lib/common/widgets/peer_card.dart b/flutter/lib/common/widgets/peer_card.dart index 4486a6e27..449b67092 100644 --- a/flutter/lib/common/widgets/peer_card.dart +++ b/flutter/lib/common/widgets/peer_card.dart @@ -56,6 +56,9 @@ class _PeerCardState extends State<_PeerCard> Widget _buildMobile() { final peer = super.widget.peer; + final name = + '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; + return Card( margin: EdgeInsets.symmetric(horizontal: 2), child: GestureDetector( @@ -90,7 +93,7 @@ class _PeerCardState extends State<_PeerCard> ? formatID(peer.id) : peer.alias) ]), - Text('${peer.username}@${peer.hostname}') + Text(name) ], ).paddingOnly(left: 8.0), ), @@ -145,6 +148,8 @@ class _PeerCardState extends State<_PeerCard> Widget _buildPeerTile( BuildContext context, Peer peer, Rx deco) { + final name = + '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; final greyStyle = TextStyle( fontSize: 11, color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6)); @@ -184,7 +189,7 @@ class _PeerCardState extends State<_PeerCard> Align( alignment: Alignment.centerLeft, child: Text( - '${peer.username}@${peer.hostname}', + name, style: greyStyle, textAlign: TextAlign.start, overflow: TextOverflow.ellipsis, @@ -206,7 +211,8 @@ class _PeerCardState extends State<_PeerCard> Widget _buildPeerCard( BuildContext context, Peer peer, Rx deco) { - final name = '${peer.username}@${peer.hostname}'; + final name = + '${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}'; return Card( color: Colors.transparent, elevation: 0, @@ -310,11 +316,20 @@ class _PeerCardState extends State<_PeerCard> bool get wantKeepAlive => true; } +enum CardType { + recent, + fav, + lan, + ab, +} + abstract class BasePeerCard extends StatelessWidget { final Peer peer; final EdgeInsets? menuPadding; + final CardType cardType; - BasePeerCard({required this.peer, this.menuPadding, Key? key}) + BasePeerCard( + {required this.peer, required this.cardType, this.menuPadding, Key? key}) : super(key: key); @override @@ -419,7 +434,7 @@ abstract class BasePeerCard extends StatelessWidget { if (Navigator.canPop(context)) { Navigator.pop(context); } - _rdpDialog(id); + _rdpDialog(id, cardType); }, )), )) @@ -471,17 +486,16 @@ abstract class BasePeerCard extends StatelessWidget { switchType: SwitchType.scheckbox, text: translate('Always connect via relay'), getter: () async { - return (await bind.mainGetPeerOption(id: id, key: option)).isNotEmpty; + if (cardType == CardType.ab) { + return gFFI.abModel.find(id)?.forceAlwaysRelay ?? false; + } else { + return (await bind.mainGetPeerOption(id: id, key: option)).isNotEmpty; + } }, setter: (bool v) async { - String value; - String oldValue = await bind.mainGetPeerOption(id: id, key: option); - if (oldValue.isEmpty) { - value = 'Y'; - } else { - value = ''; - } - await bind.mainSetPeerOption(id: id, key: option, value: value); + gFFI.abModel.setPeerForceAlwaysRelay(id, v); + await bind.mainSetPeerOption( + id: id, key: option, value: bool2option('force-always-relay', v)); }, padding: menuPadding, dismissOnClicked: true, @@ -489,14 +503,14 @@ abstract class BasePeerCard extends StatelessWidget { } @protected - MenuEntryBase _renameAction(String id, bool isAddressBook) { + MenuEntryBase _renameAction(String id) { return MenuEntryButton( childBuilder: (TextStyle? style) => Text( translate('Rename'), style: style, ), proc: () { - _rename(id, isAddressBook); + _rename(id); }, padding: menuPadding, dismissOnClicked: true, @@ -606,33 +620,22 @@ abstract class BasePeerCard extends StatelessWidget { ); } - void _rename(String id, bool isAddressBook) async { + void _rename(String id) async { RxBool isInProgress = false.obs; - var name = peer.alias; - var controller = TextEditingController(text: name); - if (isAddressBook) { - final peer = gFFI.abModel.peers.firstWhereOrNull((p) => id == p.id); - if (peer == null) { - // this should not happen - } else { - name = peer.alias; - } + String name; + if (cardType == CardType.ab) { + name = gFFI.abModel.find(id)?.alias ?? ""; + } else { + name = await bind.mainGetPeerOption(id: id, key: 'alias'); } + var controller = TextEditingController(text: name); gFFI.dialogManager.show((setState, close) { submit() async { isInProgress.value = true; - name = controller.text; + String name = controller.text.trim(); await bind.mainSetPeerAlias(id: id, alias: name); - if (isAddressBook) { - gFFI.abModel.setPeerAlias(id, name); - await gFFI.abModel.pushAb(); - } - if (isAddressBook) { - gFFI.abModel.pullAb(); - } else { - bind.mainLoadRecentPeers(); - bind.mainLoadFavPeers(); - } + gFFI.abModel.setPeerAlias(id, name); + update(); close(); isInProgress.value = false; } @@ -666,11 +669,32 @@ abstract class BasePeerCard extends StatelessWidget { ); }); } + + void update() { + switch (cardType) { + case CardType.recent: + bind.mainLoadRecentPeers(); + break; + case CardType.fav: + bind.mainLoadFavPeers(); + break; + case CardType.lan: + bind.mainLoadLanPeers(); + break; + case CardType.ab: + gFFI.abModel.pullAb(); + break; + } + } } class RecentPeerCard extends BasePeerCard { RecentPeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) - : super(peer: peer, menuPadding: menuPadding, key: key); + : super( + peer: peer, + cardType: CardType.recent, + menuPadding: menuPadding, + key: key); @override Future>> _buildMenuItems( @@ -691,7 +715,7 @@ class RecentPeerCard extends BasePeerCard { menuItems.add(_createShortCutAction(peer.id)); } menuItems.add(MenuEntryDivider()); - menuItems.add(_renameAction(peer.id, false)); + menuItems.add(_renameAction(peer.id)); menuItems.add(_removeAction(peer.id, () async { await bind.mainLoadRecentPeers(); })); @@ -708,7 +732,11 @@ class RecentPeerCard extends BasePeerCard { class FavoritePeerCard extends BasePeerCard { FavoritePeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) - : super(peer: peer, menuPadding: menuPadding, key: key); + : super( + peer: peer, + cardType: CardType.fav, + menuPadding: menuPadding, + key: key); @override Future>> _buildMenuItems( @@ -729,7 +757,7 @@ class FavoritePeerCard extends BasePeerCard { menuItems.add(_createShortCutAction(peer.id)); } menuItems.add(MenuEntryDivider()); - menuItems.add(_renameAction(peer.id, false)); + menuItems.add(_renameAction(peer.id)); menuItems.add(_removeAction(peer.id, () async { await bind.mainLoadFavPeers(); })); @@ -748,7 +776,11 @@ class FavoritePeerCard extends BasePeerCard { class DiscoveredPeerCard extends BasePeerCard { DiscoveredPeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) - : super(peer: peer, menuPadding: menuPadding, key: key); + : super( + peer: peer, + cardType: CardType.lan, + menuPadding: menuPadding, + key: key); @override Future>> _buildMenuItems( @@ -779,7 +811,11 @@ class DiscoveredPeerCard extends BasePeerCard { class AddressBookPeerCard extends BasePeerCard { AddressBookPeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) - : super(peer: peer, menuPadding: menuPadding, key: key); + : super( + peer: peer, + cardType: CardType.ab, + menuPadding: menuPadding, + key: key); @override Future>> _buildMenuItems( @@ -800,7 +836,7 @@ class AddressBookPeerCard extends BasePeerCard { menuItems.add(_createShortCutAction(peer.id)); } menuItems.add(MenuEntryDivider()); - menuItems.add(_renameAction(peer.id, false)); + menuItems.add(_renameAction(peer.id)); menuItems.add(_removeAction(peer.id, () async {})); if (await bind.mainPeerHasPassword(id: peer.id)) { menuItems.add(_unrememberPasswordAction(peer.id)); @@ -901,23 +937,33 @@ class AddressBookPeerCard extends BasePeerCard { } } -void _rdpDialog(String id) async { - final portController = TextEditingController( - text: await bind.mainGetPeerOption(id: id, key: 'rdp_port')); - final userController = TextEditingController( - text: await bind.mainGetPeerOption(id: id, key: 'rdp_username')); +void _rdpDialog(String id, CardType card) async { + String port, username; + if (card == CardType.ab) { + port = gFFI.abModel.find(id)?.rdpPort ?? ''; + username = gFFI.abModel.find(id)?.rdpUsername ?? ''; + } else { + port = await bind.mainGetPeerOption(id: id, key: 'rdp_port'); + username = await bind.mainGetPeerOption(id: id, key: 'rdp_username'); + } + + final portController = TextEditingController(text: port); + final userController = TextEditingController(text: username); final passwordController = TextEditingController( text: await bind.mainGetPeerOption(id: id, key: 'rdp_password')); RxBool secure = true.obs; gFFI.dialogManager.show((setState, close) { submit() async { + String port = portController.text.trim(); + String username = userController.text; + String password = passwordController.text; + await bind.mainSetPeerOption(id: id, key: 'rdp_port', value: port); await bind.mainSetPeerOption( - id: id, key: 'rdp_port', value: portController.text.trim()); + id: id, key: 'rdp_username', value: username); await bind.mainSetPeerOption( - id: id, key: 'rdp_username', value: userController.text); - await bind.mainSetPeerOption( - id: id, key: 'rdp_password', value: passwordController.text); + id: id, key: 'rdp_password', value: password); + gFFI.abModel.setRdp(id, port, username); close(); } diff --git a/flutter/lib/models/ab_model.dart b/flutter/lib/models/ab_model.dart index a24c01366..ab5a7cb80 100644 --- a/flutter/lib/models/ab_model.dart +++ b/flutter/lib/models/ab_model.dart @@ -122,6 +122,10 @@ class AbModel { } } + Peer? find(String id) { + return peers.firstWhereOrNull((e) => e.id == id); + } + bool idContainBy(String id) { return peers.where((element) => element.id == id).isNotEmpty; } @@ -160,13 +164,28 @@ class AbModel { } } - void setPeerAlias(String id, String value) { + Future setPeerAlias(String id, String value) async { final it = peers.where((p0) => p0.id == id); - if (it.isEmpty) { - debugPrint("$id is not exists"); - return; - } else { + if (it.isNotEmpty) { it.first.alias = value; + await pushAb(); + } + } + + Future setPeerForceAlwaysRelay(String id, bool value) async { + final it = peers.where((p0) => p0.id == id); + if (it.isNotEmpty) { + it.first.forceAlwaysRelay = value; + await pushAb(); + } + } + + Future setRdp(String id, String port, String username) async { + final it = peers.where((p0) => p0.id == id); + if (it.isNotEmpty) { + it.first.rdpPort = port; + it.first.rdpUsername = username; + await pushAb(); } } diff --git a/flutter/lib/models/peer_model.dart b/flutter/lib/models/peer_model.dart index 6dd94bcf4..ad5183ae3 100644 --- a/flutter/lib/models/peer_model.dart +++ b/flutter/lib/models/peer_model.dart @@ -9,6 +9,9 @@ class Peer { final String platform; String alias; List tags; + bool forceAlwaysRelay = false; + String rdpPort; + String rdpUsername; bool online = false; Peer.fromJson(Map json) @@ -17,7 +20,10 @@ class Peer { hostname = json['hostname'] ?? '', platform = json['platform'] ?? '', alias = json['alias'] ?? '', - tags = json['tags'] ?? []; + tags = json['tags'] ?? [], + forceAlwaysRelay = json['forceAlwaysRelay'] == 'true', + rdpPort = json['rdpPort'] ?? '', + rdpUsername = json['rdpUsername'] ?? ''; Map toJson() { return { @@ -27,6 +33,9 @@ class Peer { "platform": platform, "alias": alias, "tags": tags, + "forceAlwaysRelay": forceAlwaysRelay.toString(), + "rdpPort": rdpPort, + "rdpUsername": rdpUsername, }; } @@ -37,16 +46,23 @@ class Peer { required this.platform, required this.alias, required this.tags, + required this.forceAlwaysRelay, + required this.rdpPort, + required this.rdpUsername, }); Peer.loading() : this( - id: '...', - username: '...', - hostname: '...', - platform: '...', - alias: '', - tags: []); + id: '...', + username: '...', + hostname: '...', + platform: '...', + alias: '', + tags: [], + forceAlwaysRelay: false, + rdpPort: '', + rdpUsername: '', + ); } class Peers extends ChangeNotifier { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 23ba4ef4b..1250f7e19 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -641,45 +641,11 @@ pub fn main_peer_has_password(id: String) -> bool { peer_has_password(id) } -pub fn main_get_recent_peers() -> String { - if !config::APP_DIR.read().unwrap().is_empty() { - let peers: Vec> = PeerConfig::peers() - .drain(..) - .map(|(id, _, p)| { - HashMap::<&str, String>::from_iter([ - ("id", id), - ("username", p.info.username.clone()), - ("hostname", p.info.hostname.clone()), - ("platform", p.info.platform.clone()), - ( - "alias", - p.options.get("alias").unwrap_or(&"".to_owned()).to_owned(), - ), - ]) - }) - .collect(); - serde_json::ser::to_string(&peers).unwrap_or("".to_owned()) - } else { - String::new() - } -} - pub fn main_load_recent_peers() { if !config::APP_DIR.read().unwrap().is_empty() { let peers: Vec> = PeerConfig::peers() .drain(..) - .map(|(id, _, p)| { - HashMap::<&str, String>::from_iter([ - ("id", id), - ("username", p.info.username.clone()), - ("hostname", p.info.hostname.clone()), - ("platform", p.info.platform.clone()), - ( - "alias", - p.options.get("alias").unwrap_or(&"".to_owned()).to_owned(), - ), - ]) - }) + .map(|(id, _, p)| peer_to_map(id, p)) .collect(); if let Some(s) = flutter::GLOBAL_EVENT_STREAM .read() @@ -705,16 +671,7 @@ pub fn main_load_fav_peers() { .into_iter() .filter_map(|(id, _, p)| { if favs.contains(&id) { - Some(HashMap::<&str, String>::from_iter([ - ("id", id), - ("username", p.info.username.clone()), - ("hostname", p.info.hostname.clone()), - ("platform", p.info.platform.clone()), - ( - "alias", - p.options.get("alias").unwrap_or(&"".to_owned()).to_owned(), - ), - ])) + Some(peer_to_map(id, p)) } else { None } diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 41f22a563..59082d00d 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -685,6 +685,19 @@ pub fn discover() { }); } +pub fn peer_to_map(id: String, p: PeerConfig) -> HashMap<&'static str, String> { + HashMap::<&str, String>::from_iter([ + ("id", id), + ("username", p.info.username.clone()), + ("hostname", p.info.hostname.clone()), + ("platform", p.info.platform.clone()), + ( + "alias", + p.options.get("alias").unwrap_or(&"".to_owned()).to_owned(), + ), + ]) +} + #[inline] pub fn get_lan_peers() -> Vec> { config::LanPeers::load() From c0443e95d6b41b7b01ee7e29f84595ede570683b Mon Sep 17 00:00:00 2001 From: 21pages Date: Tue, 6 Dec 2022 11:49:07 +0800 Subject: [PATCH 3/3] fix command line password permission Signed-off-by: 21pages --- src/core_main.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/core_main.rs b/src/core_main.rs index f890a9525..d0ce9e0d1 100644 --- a/src/core_main.rs +++ b/src/core_main.rs @@ -214,7 +214,11 @@ pub fn core_main() -> Option> { return None; } else if args[0] == "--password" { if args.len() == 2 { - crate::ipc::set_permanent_password(args[1].to_owned()).unwrap(); + if crate::platform::is_root() { + crate::ipc::set_permanent_password(args[1].to_owned()).unwrap(); + } else { + log::info!("Permission denied!"); + } } return None; } else if args[0] == "--check-hwcodec-config" {