ab: read respectively and sync when set

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2022-11-28 18:16:29 +08:00
parent 5616b20879
commit 6f7eb17c48
6 changed files with 165 additions and 112 deletions

View File

@ -923,7 +923,8 @@ bool option2bool(String option, String value) {
} else if (option.startsWith("allow-") || } else if (option.startsWith("allow-") ||
option == "stop-service" || option == "stop-service" ||
option == "direct-server" || option == "direct-server" ||
option == "stop-rendezvous-service") { option == "stop-rendezvous-service" ||
option == "force-always-relay") {
res = value == "Y"; res = value == "Y";
} else { } else {
assert(false); assert(false);
@ -939,7 +940,8 @@ String bool2option(String option, bool b) {
} else if (option.startsWith('allow-') || } else if (option.startsWith('allow-') ||
option == "stop-service" || option == "stop-service" ||
option == "direct-server" || option == "direct-server" ||
option == "stop-rendezvous-service") { option == "stop-rendezvous-service" ||
option == "force-always-relay") {
res = b ? 'Y' : ''; res = b ? 'Y' : '';
} else { } else {
assert(false); assert(false);

View File

@ -56,6 +56,9 @@ class _PeerCardState extends State<_PeerCard>
Widget _buildMobile() { Widget _buildMobile() {
final peer = super.widget.peer; final peer = super.widget.peer;
final name =
'${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}';
return Card( return Card(
margin: EdgeInsets.symmetric(horizontal: 2), margin: EdgeInsets.symmetric(horizontal: 2),
child: GestureDetector( child: GestureDetector(
@ -90,7 +93,7 @@ class _PeerCardState extends State<_PeerCard>
? formatID(peer.id) ? formatID(peer.id)
: peer.alias) : peer.alias)
]), ]),
Text('${peer.username}@${peer.hostname}') Text(name)
], ],
).paddingOnly(left: 8.0), ).paddingOnly(left: 8.0),
), ),
@ -145,6 +148,8 @@ class _PeerCardState extends State<_PeerCard>
Widget _buildPeerTile( Widget _buildPeerTile(
BuildContext context, Peer peer, Rx<BoxDecoration?> deco) { BuildContext context, Peer peer, Rx<BoxDecoration?> deco) {
final name =
'${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}';
final greyStyle = TextStyle( final greyStyle = TextStyle(
fontSize: 11, fontSize: 11,
color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6)); color: Theme.of(context).textTheme.titleLarge?.color?.withOpacity(0.6));
@ -184,7 +189,7 @@ class _PeerCardState extends State<_PeerCard>
Align( Align(
alignment: Alignment.centerLeft, alignment: Alignment.centerLeft,
child: Text( child: Text(
'${peer.username}@${peer.hostname}', name,
style: greyStyle, style: greyStyle,
textAlign: TextAlign.start, textAlign: TextAlign.start,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@ -206,7 +211,8 @@ class _PeerCardState extends State<_PeerCard>
Widget _buildPeerCard( Widget _buildPeerCard(
BuildContext context, Peer peer, Rx<BoxDecoration?> deco) { BuildContext context, Peer peer, Rx<BoxDecoration?> deco) {
final name = '${peer.username}@${peer.hostname}'; final name =
'${peer.username}${peer.username.isNotEmpty && peer.hostname.isNotEmpty ? '@' : ''}${peer.hostname}';
return Card( return Card(
color: Colors.transparent, color: Colors.transparent,
elevation: 0, elevation: 0,
@ -310,11 +316,20 @@ class _PeerCardState extends State<_PeerCard>
bool get wantKeepAlive => true; bool get wantKeepAlive => true;
} }
enum CardType {
recent,
fav,
lan,
ab,
}
abstract class BasePeerCard extends StatelessWidget { abstract class BasePeerCard extends StatelessWidget {
final Peer peer; final Peer peer;
final EdgeInsets? menuPadding; 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); : super(key: key);
@override @override
@ -419,7 +434,7 @@ abstract class BasePeerCard extends StatelessWidget {
if (Navigator.canPop(context)) { if (Navigator.canPop(context)) {
Navigator.pop(context); Navigator.pop(context);
} }
_rdpDialog(id); _rdpDialog(id, cardType);
}, },
)), )),
)) ))
@ -471,17 +486,16 @@ abstract class BasePeerCard extends StatelessWidget {
switchType: SwitchType.scheckbox, switchType: SwitchType.scheckbox,
text: translate('Always connect via relay'), text: translate('Always connect via relay'),
getter: () async { 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 { setter: (bool v) async {
String value; gFFI.abModel.setPeerForceAlwaysRelay(id, v);
String oldValue = await bind.mainGetPeerOption(id: id, key: option); await bind.mainSetPeerOption(
if (oldValue.isEmpty) { id: id, key: option, value: bool2option('force-always-relay', v));
value = 'Y';
} else {
value = '';
}
await bind.mainSetPeerOption(id: id, key: option, value: value);
}, },
padding: menuPadding, padding: menuPadding,
dismissOnClicked: true, dismissOnClicked: true,
@ -489,14 +503,14 @@ abstract class BasePeerCard extends StatelessWidget {
} }
@protected @protected
MenuEntryBase<String> _renameAction(String id, bool isAddressBook) { MenuEntryBase<String> _renameAction(String id) {
return MenuEntryButton<String>( return MenuEntryButton<String>(
childBuilder: (TextStyle? style) => Text( childBuilder: (TextStyle? style) => Text(
translate('Rename'), translate('Rename'),
style: style, style: style,
), ),
proc: () { proc: () {
_rename(id, isAddressBook); _rename(id);
}, },
padding: menuPadding, padding: menuPadding,
dismissOnClicked: true, 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; RxBool isInProgress = false.obs;
var name = peer.alias; String name;
var controller = TextEditingController(text: name); if (cardType == CardType.ab) {
if (isAddressBook) { name = gFFI.abModel.find(id)?.alias ?? "";
final peer = gFFI.abModel.peers.firstWhereOrNull((p) => id == p.id); } else {
if (peer == null) { name = await bind.mainGetPeerOption(id: id, key: 'alias');
// this should not happen
} else {
name = peer.alias;
}
} }
var controller = TextEditingController(text: name);
gFFI.dialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
submit() async { submit() async {
isInProgress.value = true; isInProgress.value = true;
name = controller.text; String name = controller.text.trim();
await bind.mainSetPeerAlias(id: id, alias: name); await bind.mainSetPeerAlias(id: id, alias: name);
if (isAddressBook) { gFFI.abModel.setPeerAlias(id, name);
gFFI.abModel.setPeerAlias(id, name); update();
await gFFI.abModel.pushAb();
}
if (isAddressBook) {
gFFI.abModel.pullAb();
} else {
bind.mainLoadRecentPeers();
bind.mainLoadFavPeers();
}
close(); close();
isInProgress.value = false; 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 { class RecentPeerCard extends BasePeerCard {
RecentPeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) 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 @override
Future<List<MenuEntryBase<String>>> _buildMenuItems( Future<List<MenuEntryBase<String>>> _buildMenuItems(
@ -691,7 +715,7 @@ class RecentPeerCard extends BasePeerCard {
menuItems.add(_createShortCutAction(peer.id)); menuItems.add(_createShortCutAction(peer.id));
} }
menuItems.add(MenuEntryDivider()); menuItems.add(MenuEntryDivider());
menuItems.add(_renameAction(peer.id, false)); menuItems.add(_renameAction(peer.id));
menuItems.add(_removeAction(peer.id, () async { menuItems.add(_removeAction(peer.id, () async {
await bind.mainLoadRecentPeers(); await bind.mainLoadRecentPeers();
})); }));
@ -708,7 +732,11 @@ class RecentPeerCard extends BasePeerCard {
class FavoritePeerCard extends BasePeerCard { class FavoritePeerCard extends BasePeerCard {
FavoritePeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) 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 @override
Future<List<MenuEntryBase<String>>> _buildMenuItems( Future<List<MenuEntryBase<String>>> _buildMenuItems(
@ -729,7 +757,7 @@ class FavoritePeerCard extends BasePeerCard {
menuItems.add(_createShortCutAction(peer.id)); menuItems.add(_createShortCutAction(peer.id));
} }
menuItems.add(MenuEntryDivider()); menuItems.add(MenuEntryDivider());
menuItems.add(_renameAction(peer.id, false)); menuItems.add(_renameAction(peer.id));
menuItems.add(_removeAction(peer.id, () async { menuItems.add(_removeAction(peer.id, () async {
await bind.mainLoadFavPeers(); await bind.mainLoadFavPeers();
})); }));
@ -748,7 +776,11 @@ class FavoritePeerCard extends BasePeerCard {
class DiscoveredPeerCard extends BasePeerCard { class DiscoveredPeerCard extends BasePeerCard {
DiscoveredPeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) 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 @override
Future<List<MenuEntryBase<String>>> _buildMenuItems( Future<List<MenuEntryBase<String>>> _buildMenuItems(
@ -779,7 +811,11 @@ class DiscoveredPeerCard extends BasePeerCard {
class AddressBookPeerCard extends BasePeerCard { class AddressBookPeerCard extends BasePeerCard {
AddressBookPeerCard({required Peer peer, EdgeInsets? menuPadding, Key? key}) 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 @override
Future<List<MenuEntryBase<String>>> _buildMenuItems( Future<List<MenuEntryBase<String>>> _buildMenuItems(
@ -800,7 +836,7 @@ class AddressBookPeerCard extends BasePeerCard {
menuItems.add(_createShortCutAction(peer.id)); menuItems.add(_createShortCutAction(peer.id));
} }
menuItems.add(MenuEntryDivider()); menuItems.add(MenuEntryDivider());
menuItems.add(_renameAction(peer.id, false)); menuItems.add(_renameAction(peer.id));
menuItems.add(_removeAction(peer.id, () async {})); menuItems.add(_removeAction(peer.id, () async {}));
if (await bind.mainPeerHasPassword(id: peer.id)) { if (await bind.mainPeerHasPassword(id: peer.id)) {
menuItems.add(_unrememberPasswordAction(peer.id)); menuItems.add(_unrememberPasswordAction(peer.id));
@ -901,23 +937,33 @@ class AddressBookPeerCard extends BasePeerCard {
} }
} }
void _rdpDialog(String id) async { void _rdpDialog(String id, CardType card) async {
final portController = TextEditingController( String port, username;
text: await bind.mainGetPeerOption(id: id, key: 'rdp_port')); if (card == CardType.ab) {
final userController = TextEditingController( port = gFFI.abModel.find(id)?.rdpPort ?? '';
text: await bind.mainGetPeerOption(id: id, key: 'rdp_username')); 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( final passwordController = TextEditingController(
text: await bind.mainGetPeerOption(id: id, key: 'rdp_password')); text: await bind.mainGetPeerOption(id: id, key: 'rdp_password'));
RxBool secure = true.obs; RxBool secure = true.obs;
gFFI.dialogManager.show((setState, close) { gFFI.dialogManager.show((setState, close) {
submit() async { 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( await bind.mainSetPeerOption(
id: id, key: 'rdp_port', value: portController.text.trim()); id: id, key: 'rdp_username', value: username);
await bind.mainSetPeerOption( await bind.mainSetPeerOption(
id: id, key: 'rdp_username', value: userController.text); id: id, key: 'rdp_password', value: password);
await bind.mainSetPeerOption( gFFI.abModel.setRdp(id, port, username);
id: id, key: 'rdp_password', value: passwordController.text);
close(); close();
} }

View File

@ -122,6 +122,10 @@ class AbModel {
} }
} }
Peer? find(String id) {
return peers.firstWhereOrNull((e) => e.id == id);
}
bool idContainBy(String id) { bool idContainBy(String id) {
return peers.where((element) => element.id == id).isNotEmpty; return peers.where((element) => element.id == id).isNotEmpty;
} }
@ -160,13 +164,28 @@ class AbModel {
} }
} }
void setPeerAlias(String id, String value) { Future<void> setPeerAlias(String id, String value) async {
final it = peers.where((p0) => p0.id == id); final it = peers.where((p0) => p0.id == id);
if (it.isEmpty) { if (it.isNotEmpty) {
debugPrint("$id is not exists");
return;
} else {
it.first.alias = value; it.first.alias = value;
await pushAb();
}
}
Future<void> setPeerForceAlwaysRelay(String id, bool value) async {
final it = peers.where((p0) => p0.id == id);
if (it.isNotEmpty) {
it.first.forceAlwaysRelay = value;
await pushAb();
}
}
Future<void> 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();
} }
} }

View File

@ -9,6 +9,9 @@ class Peer {
final String platform; final String platform;
String alias; String alias;
List<dynamic> tags; List<dynamic> tags;
bool forceAlwaysRelay = false;
String rdpPort;
String rdpUsername;
bool online = false; bool online = false;
Peer.fromJson(Map<String, dynamic> json) Peer.fromJson(Map<String, dynamic> json)
@ -17,7 +20,10 @@ class Peer {
hostname = json['hostname'] ?? '', hostname = json['hostname'] ?? '',
platform = json['platform'] ?? '', platform = json['platform'] ?? '',
alias = json['alias'] ?? '', alias = json['alias'] ?? '',
tags = json['tags'] ?? []; tags = json['tags'] ?? [],
forceAlwaysRelay = json['forceAlwaysRelay'] == 'true',
rdpPort = json['rdpPort'] ?? '',
rdpUsername = json['rdpUsername'] ?? '';
Map<String, dynamic> toJson() { Map<String, dynamic> toJson() {
return <String, dynamic>{ return <String, dynamic>{
@ -27,6 +33,9 @@ class Peer {
"platform": platform, "platform": platform,
"alias": alias, "alias": alias,
"tags": tags, "tags": tags,
"forceAlwaysRelay": forceAlwaysRelay.toString(),
"rdpPort": rdpPort,
"rdpUsername": rdpUsername,
}; };
} }
@ -37,16 +46,23 @@ class Peer {
required this.platform, required this.platform,
required this.alias, required this.alias,
required this.tags, required this.tags,
required this.forceAlwaysRelay,
required this.rdpPort,
required this.rdpUsername,
}); });
Peer.loading() Peer.loading()
: this( : this(
id: '...', id: '...',
username: '...', username: '...',
hostname: '...', hostname: '...',
platform: '...', platform: '...',
alias: '', alias: '',
tags: []); tags: [],
forceAlwaysRelay: false,
rdpPort: '',
rdpUsername: '',
);
} }
class Peers extends ChangeNotifier { class Peers extends ChangeNotifier {

View File

@ -641,45 +641,11 @@ pub fn main_peer_has_password(id: String) -> bool {
peer_has_password(id) peer_has_password(id)
} }
pub fn main_get_recent_peers() -> String {
if !config::APP_DIR.read().unwrap().is_empty() {
let peers: Vec<HashMap<&str, String>> = 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() { pub fn main_load_recent_peers() {
if !config::APP_DIR.read().unwrap().is_empty() { if !config::APP_DIR.read().unwrap().is_empty() {
let peers: Vec<HashMap<&str, String>> = PeerConfig::peers() let peers: Vec<HashMap<&str, String>> = PeerConfig::peers()
.drain(..) .drain(..)
.map(|(id, _, p)| { .map(|(id, _, p)| peer_to_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(); .collect();
if let Some(s) = flutter::GLOBAL_EVENT_STREAM if let Some(s) = flutter::GLOBAL_EVENT_STREAM
.read() .read()
@ -705,16 +671,7 @@ pub fn main_load_fav_peers() {
.into_iter() .into_iter()
.filter_map(|(id, _, p)| { .filter_map(|(id, _, p)| {
if favs.contains(&id) { if favs.contains(&id) {
Some(HashMap::<&str, String>::from_iter([ Some(peer_to_map(id, p))
("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(),
),
]))
} else { } else {
None None
} }

View File

@ -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] #[inline]
pub fn get_lan_peers() -> Vec<HashMap<&'static str, String>> { pub fn get_lan_peers() -> Vec<HashMap<&'static str, String>> {
config::LanPeers::load() config::LanPeers::load()