update cm.js

This commit is contained in:
csf 2022-01-04 21:32:41 +08:00 committed by open-trade
parent face49de00
commit de67e7967a
3 changed files with 183 additions and 201 deletions

View File

@ -1,225 +1,216 @@
view.windowFrame = is_osx ? #extended : #solid; import { handler,view,is_osx,string2RGB,adjustBorder,svg_chat,translate,ChatBox,getNowStr,setWindowButontsAndIcon,is_linux } from "./common.js";
import {$,$$} from "@sciter";
// TODO in sciterjs window-frame
// view.windowFrame = is_osx ? #extended : #solid;
var body; var body;
var connections = []; var connections = [];
var show_chat = false; var show_chat = false;
class Body: Reactor.Component class Body extends Element {
{ cur = 0;
this var cur = 0;
function this() { this() {
body = this; body = this;
} }
function render() { render() {
if (connections.length == 0) return <div />; if (connections.length == 0) return <div />;
var c = connections[this.cur]; let c = connections[this.cur];
this.connection = c; this.connection = c;
this.cid = c.id; this.cid = c.id;
var auth = c.authorized; let auth = c.authorized;
var me = this; let callback = (msg)=> {
var callback = function(msg) { this.sendMsg(msg);
me.sendMsg(msg);
}; };
self.timer(1ms, adaptSize); setTimeout(adaptSize, 1);
var right_style = show_chat ? "" : "display: none"; let right_style = show_chat ? "" : "display: none";
return <div .content> return (<div class="content">
<div .left-panel> <div class="left-panel">
<div .icon-and-id> <div class="icon-and-id">
<div .icon style={"background: " + string2RGB(c.name, 1)}> <div class="icon" style={"background: " + string2RGB(c.name, 1)}>
{c.name[0].toUpperCase()} {c.name[0].toUpperCase()}
</div> </div>
<div> <div>
<div .id style="font-weight: bold; font-size: 1.2em;">{c.name}</div> <div class="id" style="font-weight: bold; font-size: 1.2em;">{c.name}</div>
<div .id>({c.peer_id})</div> <div class="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">{translate('Connected')} {" "} <span id="time">{getElaspsed(c.time)}</span></div>
</div> </div>
</div> </div>
<div /> <div />
{c.is_file_transfer || c.port_forward ? "" : <div>{translate('Permissions')}</div>} {c.is_file_transfer || c.port_forward ? "" : <div>{translate('Permissions')}</div>}
{c.is_file_transfer || c.port_forward ? "" : <div .permissions> {c.is_file_transfer || c.port_forward ? "" : <div class="permissions">
<div class={!c.keyboard ? "disabled" : ""} title={translate('Allow using keyboard and mouse')}><icon .keyboard /></div> <div class={!c.keyboard ? "disabled" : ""} title={translate('Allow using keyboard and mouse')}><icon class="keyboard" /></div>
<div class={!c.clipboard ? "disabled" : ""} title={translate('Allow using clipboard')}><icon .clipboard /></div> <div class={!c.clipboard ? "disabled" : ""} title={translate('Allow using clipboard')}><icon class="clipboard" /></div>
<div class={!c.audio ? "disabled" : ""} title={translate('Allow hearing sound')}><icon .audio /></div> <div class={!c.audio ? "disabled" : ""} title={translate('Allow hearing sound')}><icon class="audio" /></div>
</div>} </div>}
{c.port_forward ? <div>Port Forwarding: {c.port_forward}</div> : ""} {c.port_forward ? <div>Port Forwarding: {c.port_forward}</div> : ""}
<div style="size:*"/> <div style="size:*"/>
<div .buttons> <div class="buttons">
{auth ? "" : <button .button tabindex="-1" #accept>{translate('Accept')}</button>} {auth ? "" : <button class="button" tabindex="-1" id="accept">{translate('Accept')}</button>}
{auth ? "" : <button .button tabindex="-1" .outline #dismiss>{translate('Dismiss')}</button>} {auth ? "" : <button class="button" tabindex="-1" class="outline" id="dismiss">{translate('Dismiss')}</button>}
{auth ? <button .button tabindex="-1" #disconnect>{translate('Disconnect')}</button> : ""} {auth ? <button class="button" tabindex="-1" id="disconnect">{translate('Disconnect')}</button> : ""}
</div> </div>
{c.is_file_transfer || c.port_forward ? "" : <div .chaticon>{svg_chat}</div>} {c.is_file_transfer || c.port_forward ? "" : <div class="chaticon">{svg_chat}</div>}
</div> </div>
<div .right-panel style={right_style}> <div class="right-panel" style={right_style}>
{c.is_file_transfer || c.port_forward ? "" : <ChatBox msgs={c.msgs} callback={callback} />} {c.is_file_transfer || c.port_forward ? "" : <ChatBox msgs={c.msgs} callback={callback} />}
</div> </div>
</div>; </div>);
} }
function sendMsg(text) { sendMsg(text) {
if (!text) return; if (!text) return;
var { cid, connection } = this; let { cid, connection } = this;
checkClickTime(function() { checkClickTime(function() {
connection.msgs.push({ name: "me", text: text, time: getNowStr()}); connection.msgs.push({ name: "me", text: text, time: getNowStr()});
handler.send_msg(cid, text); handler.xcall("send_msg",cid, text);
body.update(); body.componentUpdate();
}); });
} }
event click $(icon.keyboard) (e) { ["on click at icon.keyboard"](e) {
var { cid, connection } = this; let { cid, connection } = this;
checkClickTime(function() { checkClickTime(function() {
connection.keyboard = !connection.keyboard; connection.keyboard = !connection.keyboard;
body.update(); body.componentUpdate();
handler.switch_permission(cid, "keyboard", connection.keyboard); handler.xcall("switch_permission",cid, "keyboard", connection.keyboard);
}); });
} }
event click $(icon.clipboard) { ["on click at icon.clipboard"]() {
var { cid, connection } = this; let { cid, connection } = this;
checkClickTime(function() { checkClickTime(function() {
connection.clipboard = !connection.clipboard; connection.clipboard = !connection.clipboard;
body.update(); body.componentUpdate();
handler.switch_permission(cid, "clipboard", connection.clipboard); handler.xcall("switch_permission",cid, "clipboard", connection.clipboard);
}); });
} }
event click $(icon.audio) { ["on click at icon.audio"]() {
var { cid, connection } = this; let { cid, connection } = this;
checkClickTime(function() { checkClickTime(function() {
connection.audio = !connection.audio; connection.audio = !connection.audio;
body.update(); body.componentUpdate();
handler.switch_permission(cid, "audio", connection.audio); handler.xcall("switch_permission",cid, "audio", connection.audio);
}); });
} }
event click $(button#accept) { ["on click at button#accept"]() {
var { cid, connection } = this; let { cid, connection } = this;
checkClickTime(function() { checkClickTime(function() {
connection.authorized = true; connection.authorized = true;
body.update(); body.componentUpdate();
handler.authorize(cid); handler.xcall("authorize",cid);
self.timer(30ms, function() { setTimeout(()=>view.state = Window.WINDOW_MINIMIZED,30);
view.windowState = View.WINDOW_MINIMIZED;
});
}); });
} }
event click $(button#dismiss) { ["on click at button#dismiss"]() {
var cid = this.cid; let cid = this.cid;
checkClickTime(function() { checkClickTime(function() {
handler.close(cid); handler.close(cid); // TEST
}); });
} }
event click $(button#disconnect) { ["on click at button#disconnect"]() {
var cid = this.cid; let cid = this.cid;
checkClickTime(function() { checkClickTime(function() {
handler.close(cid); handler.close(cid); // TEST
});
}
["on click at div.chaticon"]() {
checkClickTime(function() {
show_chat = !show_chat;
adaptSize();
}); });
} }
} }
$(body).content(<Body />); $("body").content(<Body />);
var header; var header;
class Header: Reactor.Component class Header extends Element {
{ this() {
function this() {
header = this; header = this;
} }
function render() { render() {
var me = this; let me = this;
var conn = connections[body.cur]; let conn = connections[body.cur];
if (conn && conn.unreaded > 0) {; if (conn && conn.unreaded > 0) {
var el = me.select("#unreaded" + conn.id); let el = this.select("#unreaded" + conn.id); // TODO select
if (el) el.style.set { if (el) el.style.setProperty("display","inline-block");
display: "inline-block", setTimeout(function() {
};
self.timer(300ms, function() {
conn.unreaded = 0; conn.unreaded = 0;
var el = me.select("#unreaded" + conn.id); let el = this.select("#unreaded" + conn.id); // TODO
if (el) el.style.set { if (el) el.style.setProperty("display","none");
display: "none", },300);
};
});
} }
var tabs = connections.map(function(c, i) { return me.renderTab(c, i) }); let tabs = connections.map((c, i)=> this.renderTab(c, i));
return <div .tabs-wrapper><div .tabs> return (<div class="tabs-wrapper"><div class="tabs">
{tabs} {tabs}
</div> </div>
<div .tab-arrows> <div class="tab-arrows">
<span .left-arrow>&lt;</span> <span class="left-arrow">&lt;</span>
<span .right-arrow>&gt;</span> <span class="right-arrow">&gt;</span>
</div> </div>
</div>; </div>);
} }
function renderTab(c, i) { renderTab(c, i) {
var cur = body.cur; let cur = body.cur;
return <div class={i == cur ? "active-tab tab" : "tab"}> return (<div class={i == cur ? "active-tab tab" : "tab"}>
{c.name} {c.name}
{c.unreaded > 0 ? <span .unreaded id={"unreaded" + c.id}>{c.unreaded}</span> : ""} {c.unreaded > 0 ? <span class="unreaded" id={"unreaded" + c.id}>{c.unreaded}</span> : ""}
</div>; </div>);
} }
function update_cur(idx) { update_cur(idx) {
checkClickTime(function() { checkClickTime(function(){
body.cur = idx; body.cur = idx;
update(); update();
self.timer(1ms, adjustHeader); setTimeout(adjustHeader,1);
}); });
} }
event click $(div.tab) (_, me) { ["on click at div.tab"] (_, me) {
var idx = me.index; let idx = me.index;
if (idx == body.cur) return; if (idx == body.cur) return;
this.update_cur(idx); this.update_cur(idx);
} }
event click $(span.left-arrow) { ["on click at span.left-arrow"]() {
var cur = body.cur; let cur = body.cur;
if (cur == 0) return; if (cur == 0) return;
this.update_cur(cur - 1); this.update_cur(cur - 1);
} }
event click $(span.right-arrow) { ["on click at span.right-arrow"]() {
var cur = body.cur; let cur = body.cur;
if (cur == connections.length - 1) return; if (cur == connections.length - 1) return;
this.update_cur(cur + 1); this.update_cur(cur + 1);
} }
} }
if (is_osx) { if (is_osx) {
$(header).content(<Header />); $("header").content(<Header />);
$(header).attributes["role"] = "window-caption"; $("header").attributes["role"] = "window-caption"; // TODO
} else { } else {
$(div.window-toolbar).content(<Header />); $("div.window-toolbar").content(<Header />);
setWindowButontsAndIcon(true); setWindowButontsAndIcon(true);
} }
event click $(div.chaticon) {
checkClickTime(function() {
show_chat = !show_chat;
adaptSize();
});
}
function checkClickTime(callback) { function checkClickTime(callback) {
callback(); callback();
} }
function adaptSize() { function adaptSize() {
$(div.right-panel).style.set { $("div.right-panel").style.setProperty("display",show_chat ? "block" : "none");
display: show_chat ? "block" : "none", let el = $("div.chaticon");
}; if (el) el.classList.toggle("active", show_chat);
var el = $(div.chaticon); let [x, y, w, h] = view.state.box("rectw", "border", "screen");
if (el) el.attributes.toggleClass("active", show_chat);
var (x, y, w, h) = view.box(#rectw, #border, #screen);
if (show_chat && w < 600) { if (show_chat && w < 600) {
view.move(x - (600 - w), y, 600, h); view.move(x - (600 - w), y, 600, h);
} else if (!show_chat && w > 450) { } else if (!show_chat && w > 450) {
@ -228,26 +219,26 @@ function adaptSize() {
} }
function update() { function update() {
header.update(); header.componentUpdate();
body.update(); body.componentUpdate();
} }
function bring_to_top(idx=-1) { function bring_to_top(idx=-1) {
if (view.windowState == View.WINDOW_HIDDEN || view.windowState == View.WINDOW_MINIMIZED) { if (view.state == Window.WINDOW_HIDDEN || view.state == Window.WINDOW_MINIMIZED) {
if (is_linux) { if (is_linux) {
view.focus = self; view.focus = $("body");
} else { } else {
view.windowState = View.WINDOW_SHOWN; view.state = Window.WINDOW_SHOWN;
} }
if (idx >= 0) body.cur = idx; if (idx >= 0) body.cur = idx;
} else { } else {
view.windowTopmost = true; view.isTopmost = true; // TEST
view.windowTopmost = false; view.isTopmost = false; // TEST
} }
} }
handler.addConnection = function(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio) { handler.addConnection = function(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio) {
var conn; let conn;
connections.map(function(c) { connections.map(function(c) {
if (c.id == id) conn = c; if (c.id == id) conn = c;
}); });
@ -267,22 +258,20 @@ handler.addConnection = function(id, is_file_transfer, port_forward, peer_id, na
body.cur = connections.length - 1; body.cur = connections.length - 1;
bring_to_top(); bring_to_top();
update(); update();
self.timer(1ms, adjustHeader); setTimeout(adjustHeader,1);
if (authorized) { if (authorized) {
self.timer(3s, function() { setTimeout(()=>view.state = Window.WINDOW_MINIMIZED,3000);
view.windowState = View.WINDOW_MINIMIZED;
});
} }
} }
handler.removeConnection = function(id) { handler.removeConnection = function(id) {
var i = -1; let i = -1;
connections.map(function(c, idx) { connections.map(function(c, idx) {
if (c.id == id) i = idx; if (c.id == id) i = idx;
}); });
connections.splice(i, 1); connections.splice(i, 1);
if (connections.length == 0) { if (connections.length == 0) {
handler.exit(); handler.xcall("exit");
} else { } else {
if (body.cur >= i && body.cur > 0) body.cur -= 1; if (body.cur >= i && body.cur > 0) body.cur -= 1;
update(); update();
@ -290,11 +279,11 @@ handler.removeConnection = function(id) {
} }
handler.newMessage = function(id, text) { handler.newMessage = function(id, text) {
var idx = -1; let idx = -1;
connections.map(function(c, i) { connections.map(function(c, i) {
if (c.id == id) idx = i; if (c.id == id) idx = i;
}); });
var conn = connections[idx]; let conn = connections[idx];
if (!conn) return; if (!conn) return;
conn.msgs.push({name: conn.name, text: text, time: getNowStr()}); conn.msgs.push({name: conn.name, text: text, time: getNowStr()});
bring_to_top(idx); bring_to_top(idx);
@ -304,96 +293,89 @@ handler.newMessage = function(id, text) {
} }
handler.awake = function() { handler.awake = function() {
view.windowState = View.WINDOW_SHOWN; view.state = Window.WINDOW_SHOWN;
view.focus = self; view.focus = $("body");
} }
view << event statechange { // TEST
// view << event statechange {
// adjustBorder();
// }
view.on("statechange",()=>{
adjustBorder(); adjustBorder();
} })
function self.ready() { document.on("ready",()=>{
adjustBorder(); adjustBorder();
var (sw, sh) = view.screenBox(#workarea, #dimension); let [sw, sh] = view.screenBox("workarea", "dimension");
var w = 300; let w = 300;
var h = 400; let h = 400;
view.move(sw - w, 0, w, h); view.move(sw - w, 0, w, h);
} })
document.on("unloadequest",(evt)=>{
view.state = Window.WINDOW_HIDDEN;
console.log("cm unloadequest")
evt.preventDefault(); // prevent unloading TEST
})
function getElaspsed(time) { function getElaspsed(time) {
var now = new Date(); // let now = new Date();
var seconds = Date.diff(time, now, #seconds); // let seconds = Date.diff(time, now, #seconds);
var hours = seconds / 3600; // let hours = seconds / 3600;
var days = hours / 24; // let days = hours / 24;
hours = hours % 24; // hours = hours % 24;
var minutes = seconds % 3600 / 60; // let minutes = seconds % 3600 / 60;
seconds = seconds % 60; // seconds = seconds % 60;
var out = String.printf("%02d:%02d:%02d", hours, minutes, seconds); // let out = String.printf("%02d:%02d:%02d", hours, minutes, seconds);
if (days > 0) { // if (days > 0) {
out = String.printf("%d day%s %s", days, days > 1 ? "s" : "", out); // out = String.printf("%d day%s %s", days, days > 1 ? "s" : "", out);
} // }
let out = "TIME TODO" + new Date(); // TODO
return out; return out;
} }
function updateTime() { // updateTime
self.timer(1s, function() { setInterval(function() {
var el = $(#time); let el = $("#time");
if (el) { if (el) {
var c = connections[body.cur]; let c = connections[body.cur];
if (c) { if (c) {
el.text = getElaspsed(c.time); el.text = getElaspsed(c.time);
}
} }
updateTime(); }
}); },1000);
}
updateTime();
function self.closing() {
view.windowState = View.WINDOW_HIDDEN;
return false;
}
function adjustHeader() { function adjustHeader() {
var hw = $(header).box(#width); let hw = $("header").state.box("width");
var tabswrapper = $(div.tabs-wrapper); let tabswrapper = $("div.tabs-wrapper");
var tabs = $(div.tabs); let tabs = $("div.tabs");
var arrows = $(div.tab-arrows); let arrows = $("div.tab-arrows");
if (!arrows) return; if (!arrows) return;
var n = connections.length; let n = connections.length;
var wtab = 80; let wtab = 80;
var max = hw - 98; let max = hw - 98;
var need_width = n * wtab + 2; // include border of active tab let need_width = n * wtab + 2; // include border of active tab
if (need_width < max) { if (need_width < max) {
arrows.style.set { arrows.style.setProperty("display","none");
display: "none", tabs.style.setProperty("width",need_width);
}; tabs.style.setProperty("margin-left",0);
tabs.style.set { tabswrapper.style.setProperty("width",need_width);
width: need_width,
margin-left: 0,
};
tabswrapper.style.set {
width: need_width,
};
} else { } else {
var margin = (body.cur + 1) * wtab - max + 30; let margin = (body.cur + 1) * wtab - max + 30;
if (margin < 0) margin = 0; if (margin < 0) margin = 0;
arrows.style.set { arrows.style.setProperty("display","block");
display: "block", tabs.style.setProperty("width",(max - 20 + margin) + 'px');
}; tabs.style.setProperty("margin-left",-margin + 'px');
tabs.style.set { tabswrapper.style.setProperty("width",(max + 10) + 'px');
width: (max - 20 + margin) + 'px',
margin-left: -margin + 'px'
};
tabswrapper.style.set {
width: (max + 10) + 'px',
};
} }
} }
view.on("size", adjustHeader); document.onsizechange = ()=>{
console.log("cm onsizechange");
adjustHeader();
}
// handler.addConnection(0, false, 0, "", "test1", true, false, false, false); // handler.addConnection(0, false, 0, "", "test1", true, false, false, false);
// handler.addConnection(1, false, 0, "", "test2--------", true, false, false, false); // handler.addConnection(1, false, 0, "", "test2--------", true, false, false, false);

View File

@ -91,13 +91,13 @@ impl ConnectionManager {
clipboard, clipboard,
audio audio
), ),
); ); // TODO
self.write().unwrap().senders.insert(id, tx); self.write().unwrap().senders.insert(id, tx);
} }
fn remove_connection(&self, id: i32) { fn remove_connection(&self, id: i32) {
self.write().unwrap().senders.remove(&id); self.write().unwrap().senders.remove(&id);
self.call("removeConnection", &make_args!(id)); self.call("removeConnection", &make_args!(id)); // TODO
} }
async fn handle_data( async fn handle_data(

View File

@ -147,7 +147,7 @@ export class ChatBox extends Element {
msgs = []; msgs = [];
callback; callback;
constructor(props) { this(props) {
if (props) { if (props) {
this.msgs = props.msgs || []; this.msgs = props.msgs || [];
this.callback = props.callback; this.callback = props.callback;