Initial commit: RustDesk 1.4.7 macOS desktop port
- Filled empty libs/hbb_common/ submodule (cloned from rustdesk/hbb_common) - Patched Flutter 3.44 / Dart 3.12 compatibility: * flutter/lib/generated_bridge.dart: asTypedList with cast<>, DartPort=Int64 * flutter/lib/common.dart: DialogTheme->DialogThemeData, TabBarTheme->TabBarThemeData * flutter/pubspec.yaml: extended_text 14.0.0->15.0.2, google_fonts override 5.0.0 * flutter/macos/Runner/Configs/Release.xcconfig: EXCLUDED_ARCHS=x86_64 - Build verified: cargo check + cargo build --features flutter + cargo build --release --features flutter - Verified flutter build macos --debug and --release both produce working .app - Verified .dmg installer (27MB arm64) created via hdiutil - Build deps: Xcode 26.5, CocoaPods 1.16.2, Flutter 3.44, VCPKG arm64-osx
This commit is contained in:
@@ -0,0 +1,287 @@
|
||||
import 'dart:convert';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'platform_model.dart';
|
||||
// ignore: depend_on_referenced_packages
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
class Peer {
|
||||
final String id;
|
||||
String hash; // personal ab hash password
|
||||
String password; // shared ab password
|
||||
String username; // pc username
|
||||
String hostname;
|
||||
String platform;
|
||||
String alias;
|
||||
List<dynamic> tags;
|
||||
bool forceAlwaysRelay = false;
|
||||
String rdpPort;
|
||||
String rdpUsername;
|
||||
bool online = false;
|
||||
String loginName; //login username
|
||||
String device_group_name;
|
||||
String note;
|
||||
bool? sameServer;
|
||||
|
||||
String getId() {
|
||||
if (alias != '') {
|
||||
return alias;
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
Peer.fromJson(Map<String, dynamic> json)
|
||||
: id = json['id'] ?? '',
|
||||
hash = json['hash'] ?? '',
|
||||
password = json['password'] ?? '',
|
||||
username = json['username'] ?? '',
|
||||
hostname = json['hostname'] ?? '',
|
||||
platform = json['platform'] ?? '',
|
||||
alias = json['alias'] ?? '',
|
||||
tags = json['tags'] ?? [],
|
||||
forceAlwaysRelay = json['forceAlwaysRelay'] == 'true',
|
||||
rdpPort = json['rdpPort'] ?? '',
|
||||
rdpUsername = json['rdpUsername'] ?? '',
|
||||
loginName = json['loginName'] ?? '',
|
||||
device_group_name = json['device_group_name'] ?? '',
|
||||
note = json['note'] is String ? json['note'] : '',
|
||||
sameServer = json['same_server'];
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return <String, dynamic>{
|
||||
"id": id,
|
||||
"hash": hash,
|
||||
"password": password,
|
||||
"username": username,
|
||||
"hostname": hostname,
|
||||
"platform": platform,
|
||||
"alias": alias,
|
||||
"tags": tags,
|
||||
"forceAlwaysRelay": forceAlwaysRelay.toString(),
|
||||
"rdpPort": rdpPort,
|
||||
"rdpUsername": rdpUsername,
|
||||
'loginName': loginName,
|
||||
'device_group_name': device_group_name,
|
||||
'note': note,
|
||||
'same_server': sameServer,
|
||||
};
|
||||
}
|
||||
|
||||
Map<String, dynamic> toCustomJson({required bool includingHash}) {
|
||||
var res = <String, dynamic>{
|
||||
"id": id,
|
||||
"username": username,
|
||||
"hostname": hostname,
|
||||
"platform": platform,
|
||||
"alias": alias,
|
||||
"tags": tags,
|
||||
};
|
||||
if (includingHash) {
|
||||
res['hash'] = hash;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
Map<String, dynamic> toGroupCacheJson() {
|
||||
return <String, dynamic>{
|
||||
"id": id,
|
||||
"username": username,
|
||||
"hostname": hostname,
|
||||
"platform": platform,
|
||||
"login_name": loginName,
|
||||
"device_group_name": device_group_name,
|
||||
};
|
||||
}
|
||||
|
||||
Peer({
|
||||
required this.id,
|
||||
required this.hash,
|
||||
required this.password,
|
||||
required this.username,
|
||||
required this.hostname,
|
||||
required this.platform,
|
||||
required this.alias,
|
||||
required this.tags,
|
||||
required this.forceAlwaysRelay,
|
||||
required this.rdpPort,
|
||||
required this.rdpUsername,
|
||||
required this.loginName,
|
||||
required this.device_group_name,
|
||||
required this.note,
|
||||
this.sameServer,
|
||||
});
|
||||
|
||||
Peer.loading()
|
||||
: this(
|
||||
id: '...',
|
||||
hash: '',
|
||||
password: '',
|
||||
username: '...',
|
||||
hostname: '...',
|
||||
platform: '...',
|
||||
alias: '',
|
||||
tags: [],
|
||||
forceAlwaysRelay: false,
|
||||
rdpPort: '',
|
||||
rdpUsername: '',
|
||||
loginName: '',
|
||||
device_group_name: '',
|
||||
note: '',
|
||||
);
|
||||
bool equal(Peer other) {
|
||||
return id == other.id &&
|
||||
hash == other.hash &&
|
||||
password == other.password &&
|
||||
username == other.username &&
|
||||
hostname == other.hostname &&
|
||||
platform == other.platform &&
|
||||
alias == other.alias &&
|
||||
tags.equals(other.tags) &&
|
||||
forceAlwaysRelay == other.forceAlwaysRelay &&
|
||||
rdpPort == other.rdpPort &&
|
||||
rdpUsername == other.rdpUsername &&
|
||||
device_group_name == other.device_group_name &&
|
||||
loginName == other.loginName &&
|
||||
note == other.note;
|
||||
}
|
||||
|
||||
Peer.copy(Peer other)
|
||||
: this(
|
||||
id: other.id,
|
||||
hash: other.hash,
|
||||
password: other.password,
|
||||
username: other.username,
|
||||
hostname: other.hostname,
|
||||
platform: other.platform,
|
||||
alias: other.alias,
|
||||
tags: other.tags.toList(),
|
||||
forceAlwaysRelay: other.forceAlwaysRelay,
|
||||
rdpPort: other.rdpPort,
|
||||
rdpUsername: other.rdpUsername,
|
||||
loginName: other.loginName,
|
||||
device_group_name: other.device_group_name,
|
||||
note: other.note,
|
||||
sameServer: other.sameServer);
|
||||
}
|
||||
|
||||
enum UpdateEvent { online, load }
|
||||
|
||||
typedef GetInitPeers = RxList<Peer> Function();
|
||||
|
||||
class Peers extends ChangeNotifier {
|
||||
final String name;
|
||||
final String loadEvent;
|
||||
List<Peer> peers = List.empty(growable: true);
|
||||
// Part of the peers that are not in the rest peers list.
|
||||
// When there're too many peers, we may want to load the front 100 peers first,
|
||||
// so we can see peers in UI quickly. `restPeerIds` is the rest peers' ids.
|
||||
// And then load all peers later.
|
||||
List<String> restPeerIds = List.empty(growable: true);
|
||||
final GetInitPeers? getInitPeers;
|
||||
UpdateEvent event = UpdateEvent.load;
|
||||
static const _cbQueryOnlines = 'callback_query_onlines';
|
||||
|
||||
Peers(
|
||||
{required this.name,
|
||||
required this.getInitPeers,
|
||||
required this.loadEvent}) {
|
||||
peers = getInitPeers?.call() ?? [];
|
||||
platformFFI.registerEventHandler(_cbQueryOnlines, name, (evt) async {
|
||||
_updateOnlineState(evt);
|
||||
});
|
||||
platformFFI.registerEventHandler(loadEvent, name, (evt) async {
|
||||
_updatePeers(evt);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
platformFFI.unregisterEventHandler(_cbQueryOnlines, name);
|
||||
platformFFI.unregisterEventHandler(loadEvent, name);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Peer getByIndex(int index) {
|
||||
if (index < peers.length) {
|
||||
return peers[index];
|
||||
} else {
|
||||
return Peer.loading();
|
||||
}
|
||||
}
|
||||
|
||||
int getPeersCount() {
|
||||
return peers.length;
|
||||
}
|
||||
|
||||
void _updateOnlineState(Map<String, dynamic> evt) {
|
||||
int changedCount = 0;
|
||||
evt['onlines'].split(',').forEach((online) {
|
||||
for (var i = 0; i < peers.length; i++) {
|
||||
if (peers[i].id == online) {
|
||||
if (!peers[i].online) {
|
||||
changedCount += 1;
|
||||
peers[i].online = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
evt['offlines'].split(',').forEach((offline) {
|
||||
for (var i = 0; i < peers.length; i++) {
|
||||
if (peers[i].id == offline) {
|
||||
if (peers[i].online) {
|
||||
changedCount += 1;
|
||||
peers[i].online = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (changedCount > 0) {
|
||||
event = UpdateEvent.online;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
|
||||
void _updatePeers(Map<String, dynamic> evt) {
|
||||
final onlineStates = _getOnlineStates();
|
||||
if (getInitPeers != null) {
|
||||
peers = getInitPeers?.call() ?? [];
|
||||
} else {
|
||||
peers = _decodePeers(evt['peers']);
|
||||
}
|
||||
|
||||
restPeerIds = [];
|
||||
if (evt['ids'] != null) {
|
||||
restPeerIds = (evt['ids'] as String).split(',');
|
||||
}
|
||||
|
||||
for (var peer in peers) {
|
||||
final state = onlineStates[peer.id];
|
||||
peer.online = state != null && state != false;
|
||||
}
|
||||
event = UpdateEvent.load;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
Map<String, bool> _getOnlineStates() {
|
||||
var onlineStates = <String, bool>{};
|
||||
for (var peer in peers) {
|
||||
onlineStates[peer.id] = peer.online;
|
||||
}
|
||||
return onlineStates;
|
||||
}
|
||||
|
||||
List<Peer> _decodePeers(String peersStr) {
|
||||
try {
|
||||
if (peersStr == "") return [];
|
||||
List<dynamic> peers = json.decode(peersStr);
|
||||
return peers.map((peer) {
|
||||
return Peer.fromJson(peer as Map<String, dynamic>);
|
||||
}).toList();
|
||||
} catch (e) {
|
||||
debugPrint('peers(): $e');
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user