persist cm chat page if chat unanswered

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2022-10-08 20:15:02 +08:00
parent c4c13bfbeb
commit ca9ca19fa7
32 changed files with 259 additions and 125 deletions

View File

@ -158,40 +158,26 @@ class ConnectionManagerState extends State<ConnectionManager> {
),
);
}
Widget buildTab(Client client) {
return Tab(
child: Row(
children: [
SizedBox(
width: 80,
child: Text(
client.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
textAlign: TextAlign.center,
)),
],
),
);
}
}
Widget buildConnectionCard(Client client) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
key: ValueKey(client.id),
children: [
_CmHeader(client: client),
client.isFileTransfer ? Offstage() : _PrivilegeBoard(client: client),
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: _CmControlPanel(client: client),
))
],
).paddingSymmetric(vertical: 8.0, horizontal: 8.0);
return Consumer<ServerModel>(
builder: (context, value, child) => Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
key: ValueKey(client.id),
children: [
_CmHeader(client: client),
client.isFileTransfer || client.disconnected
? Offstage()
: _PrivilegeBoard(client: client),
Expanded(
child: Align(
alignment: Alignment.bottomCenter,
child: _CmControlPanel(client: client),
))
],
).paddingSymmetric(vertical: 8.0, horizontal: 8.0));
}
class _AppIcon extends StatelessWidget {
@ -249,7 +235,7 @@ class _CmHeaderState extends State<_CmHeader>
void initState() {
super.initState();
_timer = Timer.periodic(Duration(seconds: 1), (_) {
_time.value = _time.value + 1;
if (!client.disconnected) _time.value = _time.value + 1;
});
}
@ -303,7 +289,10 @@ class _CmHeaderState extends State<_CmHeader>
FittedBox(
child: Row(
children: [
Text(translate("Connected")).marginOnly(right: 8.0),
Text(client.disconnected
? translate("Disconnected")
: translate("Connected"))
.marginOnly(right: 8.0),
Obx(() => Text(
formatDurationToTime(Duration(seconds: _time.value))))
],
@ -311,15 +300,14 @@ class _CmHeaderState extends State<_CmHeader>
],
),
),
Consumer<ServerModel>(
builder: (_, model, child) => Offstage(
offstage: !client.authorized || client.isFileTransfer,
child: IconButton(
onPressed: () => checkClickTime(client.id,
() => gFFI.chatModel.toggleCMChatPage(client.id)),
icon: Icon(Icons.message_outlined),
),
))
Offstage(
offstage: !client.authorized || client.isFileTransfer,
child: IconButton(
onPressed: () => checkClickTime(
client.id, () => gFFI.chatModel.toggleCMChatPage(client.id)),
icon: Icon(Icons.message_outlined),
),
)
],
);
}
@ -435,11 +423,11 @@ class _CmControlPanel extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Consumer<ServerModel>(builder: (_, model, child) {
return client.authorized
? buildAuthorized(context)
: buildUnAuthorized(context);
});
return client.authorized
? client.disconnected
? buildDisconnected(context)
: buildAuthorized(context)
: buildUnAuthorized(context);
}
buildAuthorized(BuildContext context) {
@ -468,6 +456,31 @@ class _CmControlPanel extends StatelessWidget {
);
}
buildDisconnected(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Ink(
width: 200,
height: 40,
decoration: BoxDecoration(
color: MyTheme.accent, borderRadius: BorderRadius.circular(10)),
child: InkWell(
onTap: () => handleClose(context),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
translate("Close"),
style: TextStyle(color: Colors.white),
),
],
)),
)
],
);
}
buildUnAuthorized(BuildContext context) {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
@ -527,6 +540,13 @@ class _CmControlPanel extends StatelessWidget {
final model = Provider.of<ServerModel>(context, listen: false);
model.sendLoginResponse(client, true);
}
void handleClose(BuildContext context) async {
await bind.cmRemoveDisconnectedConnection(connId: client.id);
if (await bind.cmGetClientsLength() == 0) {
windowManager.close();
}
}
}
void checkClickTime(int id, Function() callback) async {

View File

@ -376,29 +376,29 @@ class ServerModel with ChangeNotifier {
} else {
_clients[index].authorized = true;
}
tabController.add(
TabInfo(
key: client.id.toString(),
label: client.name,
closable: false,
page: Desktop.buildConnectionCard(client)),
authorized: true);
scrollToBottom();
notifyListeners();
} else {
if (_clients.any((c) => c.id == client.id)) {
return;
}
_clients.add(client);
tabController.add(TabInfo(
key: client.id.toString(),
label: client.name,
closable: false,
page: Desktop.buildConnectionCard(client)));
scrollToBottom();
notifyListeners();
if (isAndroid) showLoginDialog(client);
}
tabController.add(
TabInfo(
key: client.id.toString(),
label: client.name,
closable: false,
page: Desktop.buildConnectionCard(client)),
authorized: client.authorized);
// remove disconnected
final index_disconnected = _clients
.indexWhere((c) => c.disconnected && c.peerId == client.peerId);
if (index_disconnected >= 0) {
_clients.removeAt(index_disconnected);
tabController.remove(index_disconnected);
}
scrollToBottom();
notifyListeners();
if (isAndroid && !client.authorized) showLoginDialog(client);
} catch (e) {
debugPrint("Failed to call loginRequest,error:$e");
}
@ -477,38 +477,19 @@ class ServerModel with ChangeNotifier {
}
}
void onClientAuthorized(Map<String, dynamic> evt) {
try {
final client = Client.fromJson(jsonDecode(evt['client']));
parent.target?.dialogManager.dismissByTag(getLoginDialogTag(client.id));
final index = _clients.indexWhere((c) => c.id == client.id);
if (index < 0) {
_clients.add(client);
} else {
_clients[index].authorized = true;
}
tabController.add(
TabInfo(
key: client.id.toString(),
label: client.name,
closable: false,
page: Desktop.buildConnectionCard(client)),
authorized: true);
scrollToBottom();
notifyListeners();
} catch (e) {
debugPrint("onClientAuthorized:$e");
}
}
void onClientRemove(Map<String, dynamic> evt) {
try {
final id = int.parse(evt['id'] as String);
final close = (evt['close'] as String) == 'true';
if (_clients.any((c) => c.id == id)) {
final index = _clients.indexWhere((client) => client.id == id);
if (index >= 0) {
_clients.removeAt(index);
tabController.remove(index);
if (close) {
_clients.removeAt(index);
tabController.remove(index);
} else {
_clients[index].disconnected = true;
}
}
parent.target?.dialogManager.dismissByTag(getLoginDialogTag(id));
parent.target?.invokeMethod("cancel_notification", id);
@ -545,6 +526,7 @@ class Client {
bool file = false;
bool restart = false;
bool recording = false;
bool disconnected = false;
Client(this.id, this.authorized, this.isFileTransfer, this.name, this.peerId,
this.keyboard, this.clipboard, this.audio);
@ -561,18 +543,20 @@ class Client {
file = json['file'];
restart = json['restart'];
recording = json['recording'];
disconnected = json['disconnected'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['id'] = this.id;
data['is_start'] = this.authorized;
data['is_file_transfer'] = this.isFileTransfer;
data['name'] = this.name;
data['peer_id'] = this.peerId;
data['keyboard'] = this.keyboard;
data['clipboard'] = this.clipboard;
data['audio'] = this.audio;
data['id'] = id;
data['is_start'] = authorized;
data['is_file_transfer'] = isFileTransfer;
data['name'] = name;
data['peer_id'] = peerId;
data['keyboard'] = keyboard;
data['clipboard'] = clipboard;
data['audio'] = audio;
data['disconnected'] = disconnected;
return data;
}
}

View File

@ -368,8 +368,11 @@ pub mod connection_manager {
self.push_event("add_connection", vec![("client", &client_json)]);
}
fn remove_connection(&self, id: i32) {
self.push_event("on_client_remove", vec![("id", &id.to_string())]);
fn remove_connection(&self, id: i32, close: bool) {
self.push_event(
"on_client_remove",
vec![("id", &id.to_string()), ("close", &close.to_string())],
);
}
fn new_message(&self, id: i32, text: String) {

View File

@ -779,6 +779,10 @@ pub fn cm_check_clients_length(length: usize) -> Option<String> {
}
}
pub fn cm_get_clients_length() -> usize {
crate::ui_cm_interface::get_clients_length()
}
pub fn main_init(app_dir: String) {
initialize(&app_dir);
}
@ -941,6 +945,10 @@ pub fn cm_close_connection(conn_id: i32) {
crate::ui_cm_interface::close(conn_id);
}
pub fn cm_remove_disconnected_connection(conn_id: i32) {
crate::ui_cm_interface::remove(conn_id);
}
pub fn cm_check_click_time(conn_id: i32) {
crate::ui_cm_interface::check_click_time(conn_id)
}

View File

@ -186,6 +186,7 @@ pub enum Data {
Theme(String),
Language(String),
Empty,
Disconnected,
}
#[tokio::main(flavor = "current_thread")]

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", "以当前用户权限运行软件,可能导致远端在访问本机时,没有足够的权限来操作部分窗口。"),
("uac_warning", "暂时无法访问远端设备因为远端设备正在请求用户账户权限请等待对方关闭UAC窗口。为避免这个问题建议在远端设备上安装或者以管理员权限运行本软件。"),
("elevated_foreground_window_warning", "暂时无法使用鼠标键盘,因为远端桌面的当前窗口需要更高的权限才能操作, 可以请求对方最小化当前窗口。为避免这个问题,建议在远端设备上安装或者以管理员权限运行本软件。"),
("Disconnected", "会话已结束"),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", "Monit o podwyższeniu uprawnień"),
("uac_warning", "Ostrzeżenie UAC"),
("elevated_foreground_window_warning", "Pierwszoplanowe okno ostrzeżenia o podwyższeniu uprawnień"),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", "以當前用戶權限運行軟件,可能導致遠端在訪問本機時,沒有足夠的權限來操作部分窗口。"),
("uac_warning", "暂时无法访问远端设备因为远端设备正在请求用户账户权限请等待对方关闭UAC窗口。为避免这个问题建议在远端设备上安装或者以管理员权限运行本软件。"),
("elevated_foreground_window_warning", "暫時無法使用鼠標鍵盤,因為遠端桌面的當前窗口需要更高的權限才能操作, 可以請求對方最小化當前窗口。為避免這個問題,建議在遠端設備上安裝或者以管理員權限運行本軟件。"),
("Disconnected", "會話已結束"),
].iter().cloned().collect();
}

View File

@ -362,5 +362,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Enable LAN Discovery", "Увімкнути пошук локальної мережі"),
("Deny LAN Discovery", "Заборонити виявлення локальної мережі"),
("Write a message", "Написати повідомлення"),
("Prompt", ""),
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -366,5 +366,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("elevation_prompt", ""),
("uac_warning", ""),
("elevated_foreground_window_warning", ""),
("Disconnected", ""),
].iter().cloned().collect();
}

View File

@ -95,6 +95,8 @@ pub struct Connection {
api_server: String,
lr: LoginRequest,
last_recv_time: Arc<Mutex<Instant>>,
chat_unanswered: bool,
close_manually: bool,
}
impl Subscriber for ConnInner {
@ -184,6 +186,8 @@ impl Connection {
api_server: "".to_owned(),
lr: Default::default(),
last_recv_time: Arc::new(Mutex::new(Instant::now())),
chat_unanswered: false,
close_manually: false,
};
#[cfg(not(any(target_os = "android", target_os = "ios")))]
tokio::spawn(async move {
@ -246,6 +250,7 @@ impl Connection {
}
}
ipc::Data::Close => {
conn.close_manually = true;
let mut misc = Misc::new();
misc.set_close_reason("Closed manually by the peer".into());
let mut msg_out = Message::new();
@ -264,6 +269,7 @@ impl Connection {
let mut msg_out = Message::new();
msg_out.set_misc(misc);
conn.send(msg_out).await;
conn.chat_unanswered = false;
}
ipc::Data::SwitchPermission{name, enabled} => {
log::info!("Change permission {} -> {}", name, enabled);
@ -1245,6 +1251,7 @@ impl Connection {
}
Some(misc::Union::ChatMessage(c)) => {
self.send_to_cm(ipc::Data::ChatMessage { text: c.text });
self.chat_unanswered = true;
}
Some(misc::Union::Option(o)) => {
self.update_option(&o).await;
@ -1445,7 +1452,15 @@ impl Connection {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
lock_screen().await;
}
self.tx_to_cm.send(ipc::Data::Close).ok();
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let data = if self.chat_unanswered && !self.close_manually {
ipc::Data::Disconnected
} else {
ipc::Data::Close
};
#[cfg(any(target_os = "android", target_os = "ios"))]
let data = ipc::Data::Close;
self.tx_to_cm.send(data).ok();
self.port_forward_socket.take();
}

View File

@ -38,8 +38,8 @@ impl InvokeUiCM for SciterHandler {
);
}
fn remove_connection(&self, id: i32) {
self.call("removeConnection", &make_args!(id));
fn remove_connection(&self, id: i32, close: bool) {
self.call("removeConnection", &make_args!(id, close));
if crate::ui_cm_interface::get_clients_length().eq(&0) {
crate::platform::quit_gui();
}
@ -109,6 +109,14 @@ impl SciterConnectionManager {
crate::ui_cm_interface::close(id);
}
fn remove_disconnected_connection(&self, id: i32) {
crate::ui_cm_interface::remove(id);
}
fn quit(&self) {
crate::platform::quit_gui();
}
fn authorize(&self, id: i32) {
crate::ui_cm_interface::authorize(id);
}
@ -133,6 +141,8 @@ impl sciter::EventHandler for SciterConnectionManager {
fn get_click_time();
fn get_icon();
fn close(i32);
fn remove_disconnected_connection(i32);
fn quit();
fn authorize(i32);
fn switch_permission(i32, String, bool);
fn send_msg(i32, String);

View File

@ -26,6 +26,7 @@ class Body: Reactor.Component
me.sendMsg(msg);
};
var right_style = show_chat ? "" : "display: none";
var disconnected = c.disconnected;
// below size:* is work around for Linux, it alreayd set in css, but not work, shit sciter
return <div .content style="size:*">
<div .left-panel>
@ -36,12 +37,12 @@ class Body: Reactor.Component
<div>
<div .id style="font-weight: bold; font-size: 1.2em;">{c.name}</div>
<div .id>({c.peer_id})</div>
<div style="margin-top: 1.2em">{translate('Connected')} {" "} <span #time>{getElaspsed(c.time)}</span></div>
<div style="margin-top: 1.2em">{disconnected ? translate('Disconnected') : translate('Connected')} {" "} <span #time>{getElaspsed(c.time, c.now)}</span></div>
</div>
</div>
<div />
{c.is_file_transfer || c.port_forward ? "" : <div>{translate('Permissions')}</div>}
{c.is_file_transfer || c.port_forward ? "" : <div> <div .permissions>
{c.is_file_transfer || c.port_forward || disconnected ? "" : <div>{translate('Permissions')}</div>}
{c.is_file_transfer || c.port_forward || disconnected ? "" : <div> <div .permissions>
<div class={!c.keyboard ? "disabled" : ""} title={translate('Allow using keyboard and mouse')}><icon .keyboard /></div>
<div class={!c.clipboard ? "disabled" : ""} title={translate('Allow using clipboard')}><icon .clipboard /></div>
<div class={!c.audio ? "disabled" : ""} title={translate('Allow hearing sound')}><icon .audio /></div>
@ -56,7 +57,8 @@ class Body: Reactor.Component
<div .buttons>
{auth ? "" : <button .button tabindex="-1" #accept>{translate('Accept')}</button>}
{auth ? "" : <button .button tabindex="-1" .outline #dismiss>{translate('Dismiss')}</button>}
{auth ? <button .button tabindex="-1" #disconnect>{translate('Disconnect')}</button> : ""}
{auth && !disconnected ? <button .button tabindex="-1" #disconnect>{translate('Disconnect')}</button> : ""}
{auth && disconnected ? <button .button tabindex="-1" #close>{translate('Close')}</button> : ""}
</div>
{c.is_file_transfer || c.port_forward ? "" : <div .chaticon>{svg_chat}</div>}
</div>
@ -155,6 +157,25 @@ class Body: Reactor.Component
handler.close(cid);
});
}
event click $(button#close) {
var cid = this.cid;
if (this.cur >= 0 && this.cur < connections.length){
handler.remove_disconnected_connection(cid);
connections.splice(this.cur, 1);
if (connections.length > 0) {
if (this.cur > 0)
this.cur -= 1;
else
this.cur = connections.length - 1;
header.update();
body.update();
} else {
handler.quit();
}
}
}
}
$(body).content(<Body />);
@ -299,15 +320,26 @@ handler.addConnection = function(id, is_file_transfer, port_forward, peer_id, na
update();
return;
}
var idx = -1;
connections.map(function(c, i) {
if (c.disconnected && c.peer_id == peer_id) idx = i;
});
if (!name) name = "NA";
connections.push({
conn = {
id: id, is_file_transfer: is_file_transfer, peer_id: peer_id,
port_forward: port_forward,
name: name, authorized: authorized, time: new Date(),
name: name, authorized: authorized, time: new Date(), now: new Date(),
keyboard: keyboard, clipboard: clipboard, msgs: [], unreaded: 0,
audio: audio, file: file, restart: restart, recording: recording
});
body.cur = connections.length - 1;
audio: audio, file: file, restart: restart, recording: recording,
disconnected: false
};
if (idx < 0) {
connections.push(conn);
body.cur = connections.length - 1;
} else {
connections[idx] = conn;
body.cur = idx;
}
bring_to_top();
update();
self.timer(1ms, adjustHeader);
@ -318,15 +350,20 @@ handler.addConnection = function(id, is_file_transfer, port_forward, peer_id, na
}
}
handler.removeConnection = function(id) {
handler.removeConnection = function(id, close) {
var i = -1;
connections.map(function(c, idx) {
if (c.id == id) i = idx;
});
if (i < 0) return;
connections.splice(i, 1);
if (close) {
connections.splice(i, 1);
} else {
var conn = connections[i];
conn.disconnected = true;
}
if (connections.length > 0) {
if (body.cur >= i && body.cur > 0) body.cur -= 1;
if (body.cur >= i && body.cur > 0 && close) body.cur -= 1;
update();
}
}
@ -361,8 +398,7 @@ function self.ready() {
view.move(sw - w, 0, w, h);
}
function getElaspsed(time) {
var now = new Date();
function getElaspsed(time, now) {
var seconds = Date.diff(time, now, #seconds);
var hours = seconds / 3600;
var days = hours / 24;
@ -378,11 +414,15 @@ function getElaspsed(time) {
function updateTime() {
self.timer(1s, function() {
var now = new Date();
connections.map(function(c) {
if (!c.disconnected) c.now = now;
});
var el = $(#time);
if (el) {
var c = connections[body.cur];
if (c) {
el.text = getElaspsed(c.time);
if (c && !c.disconnected) {
el.text = getElaspsed(c.time, c.now);
}
}
updateTime();

View File

@ -31,6 +31,7 @@ use hbb_common::{
pub struct Client {
pub id: i32,
pub authorized: bool,
pub disconnected: bool,
pub is_file_transfer: bool,
pub port_forward: String,
pub name: String,
@ -58,7 +59,7 @@ pub struct ConnectionManager<T: InvokeUiCM> {
pub trait InvokeUiCM: Send + Clone + 'static + Sized {
fn add_connection(&self, client: &Client);
fn remove_connection(&self, id: i32);
fn remove_connection(&self, id: i32, close: bool);
fn new_message(&self, id: i32, text: String);
@ -101,6 +102,7 @@ impl<T: InvokeUiCM> ConnectionManager<T> {
let client = Client {
id,
authorized,
disconnected: false,
is_file_transfer,
port_forward,
name: name.clone(),
@ -113,12 +115,24 @@ impl<T: InvokeUiCM> ConnectionManager<T> {
recording,
tx,
};
CLIENTS
.write()
.unwrap()
.retain(|_, c| !(c.disconnected && c.peer_id == client.peer_id));
CLIENTS.write().unwrap().insert(id, client.clone());
self.ui_handler.add_connection(&client);
CLIENTS.write().unwrap().insert(id, client);
}
fn remove_connection(&self, id: i32) {
CLIENTS.write().unwrap().remove(&id);
fn remove_connection(&self, id: i32, close: bool) {
if close {
CLIENTS.write().unwrap().remove(&id);
} else {
CLIENTS
.write()
.unwrap()
.get_mut(&id)
.map(|c| c.disconnected = true);
}
#[cfg(any(target_os = "android"))]
if CLIENTS
@ -136,7 +150,7 @@ impl<T: InvokeUiCM> ConnectionManager<T> {
}
}
self.ui_handler.remove_connection(id);
self.ui_handler.remove_connection(id, close);
}
}
@ -167,6 +181,11 @@ pub fn close(id: i32) {
};
}
#[inline]
pub fn remove(id: i32) {
CLIENTS.write().unwrap().remove(&id);
}
// server mode send chat to peer
#[inline]
pub fn send_chat(id: i32, text: String) {
@ -243,6 +262,7 @@ pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
let mut conn_id: i32 = 0;
let (tx, mut rx) = mpsc::unbounded_channel::<Data>();
let mut write_jobs: Vec<fs::TransferJob> = Vec::new();
let mut close = true;
loop {
tokio::select! {
res = stream.next() => {
@ -264,6 +284,12 @@ pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
log::info!("cm ipc connection closed from connection request");
break;
}
Data::Disconnected => {
close = false;
tx_file.send(ClipboardFileData::Enable((conn_id, false))).ok();
log::info!("cm ipc connection disconnect");
break;
}
Data::PrivacyModeState((id, _)) => {
conn_id = conn_id_tmp;
allow_err!(tx.send(data));
@ -312,7 +338,7 @@ pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
}
}
if conn_id != conn_id_tmp {
cm.remove_connection(conn_id);
cm.remove_connection(conn_id, close);
}
});
}