Add features:

- allow pinning apps in Setting
- pinned apps in system pannel
- Services manager in Setting
- Fix and impprove some CSS bug
This commit is contained in:
lxsang 2021-03-15 19:20:42 +01:00
parent 26c397838b
commit 7cd2f97b75
18 changed files with 354 additions and 44 deletions

View File

@ -134,7 +134,7 @@ namespace OS {
return this.trigger("exit", undefined); return this.trigger("exit", undefined);
} }
}); });
this.on("apptitlechange", () => this.sysdock.update(undefined)); this.on("apptitlechange", () => this.sysdock.update(this));
this.updateLocale(this.systemsetting.system.locale); this.updateLocale(this.systemsetting.system.locale);
return this.loadScheme(); return this.loadScheme();
} }

View File

@ -619,9 +619,9 @@ namespace OS {
data.iconclass = "fa fa-cogs"; data.iconclass = "fa fa-cogs";
} }
const dock = $("#sysdock")[0] as tag.AppDockTag; const dock = $("#sysdock")[0] as tag.AppDockTag;
app.sysdock = dock;
app.init(); app.init();
app.observable.one("rendered", function () { app.observable.one("rendered", function () {
app.sysdock = dock;
app.appmenu = $( app.appmenu = $(
"[data-id = 'appmenu']", "[data-id = 'appmenu']",
"#syspanel" "#syspanel"
@ -815,6 +815,7 @@ namespace OS {
if (arr.length > 1) { if (arr.length > 1) {
tip = arr[1]; tip = arr[1];
} }
console.log(el);
const offset = $(el).offset(); const offset = $(el).offset();
const w = $(el).width(); const w = $(el).width();
const h = $(el).height(); const h = $(el).height();
@ -829,6 +830,10 @@ namespace OS {
left = offset.left + w / 2 - $(label).width() / 2; left = offset.left + w / 2 - $(label).width() / 2;
top = offset.top - $(label).height() - 5; top = offset.top - $(label).height() - 5;
break; break;
case "cb": // center bottom
left = offset.left + w / 2 - $(label).width() / 2;
top = offset.top + $(label).height() + 10;
break;
default: default:
if (!e) { if (!e) {
return; return;
@ -944,7 +949,7 @@ namespace OS {
$("#systooltip")[0].uify(undefined); $("#systooltip")[0].uify(undefined);
$("#contextmenu")[0].uify(undefined); $("#contextmenu")[0].uify(undefined);
$("#workspace").on("contextmenu",(e) => bindContextMenu(e)); $("#wrapper").on("contextmenu",(e) => bindContextMenu(e));
// tooltip // tooltip
$(document).on("mouseover", function (e) { $(document).on("mouseover", function (e) {
const el: any = $(e.target).closest("[tooltip]"); const el: any = $(e.target).closest("[tooltip]");

View File

@ -356,6 +356,13 @@ namespace OS {
* @type {string[]} * @type {string[]}
*/ */
services: string[]; services: string[];
/**
* List of pinned applications
*
* @type {string[]}
*/
pinned: string[];
}; };
} }
/** /**
@ -476,6 +483,7 @@ namespace OS {
startup: { startup: {
apps: [], apps: [],
services: ["Syslog/PushNotification", "Syslog/Calendar"], services: ["Syslog/PushNotification", "Syslog/Calendar"],
pinned: [],
}, },
}; };
} }
@ -530,7 +538,7 @@ namespace OS {
for (let k in setting.system.packages) { for (let k in setting.system.packages) {
const v = setting.system.packages[k]; const v = setting.system.packages[k];
if (v.app) { if (v.app) {
var e, k1, v1; var e: any, k1: string, v1: { [x: string]: any; detail?: any; path?: any; complex?: any; };
if ( if (
v.name.match(term) || v.name.match(term) ||
(v.description && v.description.match(term)) (v.description && v.description.match(term))

View File

@ -83,7 +83,25 @@ namespace OS {
* @param {*} [d] * @param {*} [d]
* @memberof AppDockTag * @memberof AppDockTag
*/ */
protected reload(d?: any): void {} protected reload(d?: any): void {
let app: application.BaseApplication = d as application.BaseApplication;
if(!app)
{
return;
}
let i = -1;
const iterable = this.items;
for (let k = 0; k < iterable.length; k++) {
const v = iterable[k];
if (v.app.pid === app.pid) {
i = k;
break;
}
}
if (i !== -1) {
$(this.items[i].domel).attr("tooltip", `cr:${app.title()}`);
}
}
/** /**
* Init the tag before mounting * Init the tag before mounting
@ -171,10 +189,8 @@ namespace OS {
el[0].uify(this.observable); el[0].uify(this.observable);
bt.set(item); bt.set(item);
bt.data = item.app; bt.data = item.app;
$(el).on("mouseover", (e) =>{
el.attr("tooltip", `cr:${item.app.title()}`);
});
item.domel = bt; item.domel = bt;
$(bt).attr("tooltip", `cr:${item.app.title()}`);
bt.onbtclick = (e) => { bt.onbtclick = (e) => {
e.id = this.aid; e.id = this.aid;
//e.data.item = item; //e.data.item = item;

View File

@ -57,7 +57,7 @@ namespace OS {
* @protected * @protected
* @memberof SystemPanelTag * @memberof SystemPanelTag
*/ */
protected init(): void {} protected init(): void { }
/** /**
* Do nothing * Do nothing
@ -66,7 +66,7 @@ namespace OS {
* @param {*} [d] * @param {*} [d]
* @memberof SystemPanelTag * @memberof SystemPanelTag
*/ */
protected reload(d?: any): void {} protected reload(d?: any): void { }
/** /**
* Attach a service to the system tray on the pannel, * Attach a service to the system tray on the pannel,
@ -178,6 +178,11 @@ namespace OS {
ref: "osmenu", ref: "osmenu",
class: "afx-panel-os-menu", class: "afx-panel-os-menu",
}, },
{
el: "afx-menu",
ref: "pinned",
class: "afx-panel-os-pinned-app",
},
{ {
el: "afx-menu", el: "afx-menu",
id: "appmenu", id: "appmenu",
@ -305,9 +310,30 @@ namespace OS {
* @memberof SystemPanelTag * @memberof SystemPanelTag
*/ */
calibrate(): void { calibrate(): void {
(this.refs.overlay as OverlayTag).height = `${ (this.refs.overlay as OverlayTag).height = `${$(window).height() - $(this.refs.panel).height()
$(window).height() - $(this.refs.panel).height() }px`;
}px`; }
/**
* Refresh the pinned applications menu
*
* @private
* @memberof SystemPanelTag
*/
private RefreshPinnedApp(): void
{
if(!setting.system.startup.pinned)
return;
(this.refs.pinned as GUI.tag.MenuTag).items = setting.system.startup.pinned.map((name) => {
const app = setting.system.packages[name];
return {
icon: app.icon,
iconclass: app.iconclass,
app: app.app,
tooltip: `cb:${app.name}`
};
});
} }
/** /**
@ -358,11 +384,11 @@ namespace OS {
return this.toggle(true); return this.toggle(true);
}; };
$(this.refs.search).on("keyup",(e) => { $(this.refs.search).on("keyup", (e) => {
return this.search(e); return this.search(e);
}); });
$(this.refs.applist).on("click",(e) => { $(this.refs.applist).on("click", (e) => {
return this.open(); return this.open();
}); });
Ant.OS.GUI.bindKey("CTRL- ", (e) => { Ant.OS.GUI.bindKey("CTRL- ", (e) => {
@ -378,6 +404,32 @@ namespace OS {
.css("top", `${$(this.refs.panel).height()}px`) .css("top", `${$(this.refs.panel).height()}px`)
.css("bottom", "0") .css("bottom", "0")
.hide(); .hide();
(this.refs.pinned as GUI.tag.MenuTag).onmenuselect = (e) => {
const app = e.data.item.data.app;
if(!app)
return;
GUI.launch(app, []);
};
this.refs.appmenu.contextmenuHandle = (e, m) => { }
this.refs.osmenu.contextmenuHandle = (e, m) => { }
this.refs.systray.contextmenuHandle = (e, m) => { }
this.refs.pinned.contextmenuHandle = (e, m) => { }
this.refs.panel.contextmenuHandle = (e, m) => {
let menu = [
{ text: __("Applications and services setting"), dataid: "app&srv" }
];
m.items = menu;
m.onmenuselect = function (
evt: TagEventType<tag.MenuEventData>
) {
GUI.launch("Setting",[]);
}
m.show(e);
};
announcer.observable.on("app-pinned", (d) => {
this.RefreshPinnedApp();
});
this.RefreshPinnedApp();
} }
} }

View File

@ -209,6 +209,7 @@ namespace OS {
$(this).attr("apptitle", v.__()); $(this).attr("apptitle", v.__());
if (v) { if (v) {
(this.refs["txtTitle"] as LabelTag).text = v; (this.refs["txtTitle"] as LabelTag).text = v;
this.observable.trigger("apptitlechange", this);
} }
} }
get apptitle(): string | FormattedString { get apptitle(): string | FormattedString {

View File

@ -83,12 +83,10 @@ namespace OS {
* @memberof BaseExtension * @memberof BaseExtension
*/ */
protected logger() { protected logger() {
if(!this.app.setting.showBottomBar) if (!this.app.setting.showBottomBar) {
{
this.app.showOutput(true); this.app.showOutput(true);
} }
else else {
{
this.app.showOutput(false); this.app.showOutput(false);
} }
return this.app.logger; return this.app.logger;
@ -142,7 +140,7 @@ namespace OS {
* @memberof BaseExtension * @memberof BaseExtension
*/ */
protected copy(files: string[], to: string): Promise<void> { protected copy(files: string[], to: string): Promise<void> {
return new Promise((resolve, reject) =>{ return new Promise((resolve, reject) => {
if (files.length === 0) { if (files.length === 0) {
return resolve(); return resolve();
} }
@ -232,8 +230,8 @@ namespace OS {
.then( .then(
(d: { (d: {
result: result:
| Iterable<unknown> | Iterable<unknown>
| ArrayLike<unknown>; | ArrayLike<unknown>;
}) => { }) => {
const l = (d.result as API.FileInfoType[]).map( const l = (d.result as API.FileInfoType[]).map(
(v) => v.path (v) => v.path
@ -440,16 +438,33 @@ namespace OS {
.asFileHandle() .asFileHandle()
.read("json") .read("json")
.then((data) => { .then((data) => {
if(!data.root && this.app.currdir) if (!data.root && this.app.currdir) {
{
data.root = this.app.currdir.path; data.root = this.app.currdir.path;
} }
resolve(data); resolve(data);
}) })
.catch((e) => { .catch((e) => {
return reject( // try to ask user to select a folder
API.throwe(__("Unable to read meta-data")) this.app.openDialog("FileDialog", {
); title: __("Select build directory"),
root: this.app.currdir.path,
mimes: ["dir"]
})
.then((d) => {
`${d.file.path}/${file}`
.asFileHandle()
.read("json")
.then((data) => {
if (!data.root) {
data.root = d.file.path;
}
resolve(data);
})
.catch((e1) => reject(e1))
})
.catch(
(e1) => reject(API.throwe(__("Unable to read meta-data"))
))
}); });
}); });
} }

View File

@ -8,7 +8,7 @@
}, },
"version":"0.2.2-a", "version":"0.2.2-a",
"category":"System", "category":"System",
"iconclass":"fa fa-adn", "iconclass":"fa fa-shopping-bag",
"mimes":["none"], "mimes":["none"],
"locales": {} "locales": {}
} }

View File

@ -0,0 +1,167 @@
/*
* decaffeinate suggestions:
* DS101: Remove unnecessary use of Array.from
* DS102: Remove unnecessary code created because of implicit returns
* DS205: Consider reworking code to avoid use of IIFEs
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
// Copyright 2017-2018 Xuan Sang LE <xsang.le AT gmail DOT com>
// AnTOS Web desktop is is licensed under the GNU General Public
// License v3.0, see the LICENCE file for more information
// This program is free software: you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation, either version 3 of
// the License, or (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// General Public License for more details.
// You should have received a copy of the GNU General Public License
//along with this program. If not, see https://www.gnu.org/licenses/.
namespace OS {
const App = OS.application.Setting;
/**
*
*
* @class AppAndServiceHandle
* @extends {App.SettingHandle}
*/
class AppAndServiceHandle extends App.SettingHandle {
private srvlist: GUI.tag.ListViewTag;
private applist: GUI.tag.ListViewTag;
/**
*Creates an instance of AppAndServiceHandle.
* @param {HTMLElement} scheme
* @param {OS.application.Setting} parent
* @memberof AppAndServiceHandle
*/
constructor(scheme: HTMLElement, parent: OS.application.Setting) {
super(scheme, parent);
this.srvlist = this.find("sys-srvlist") as GUI.tag.ListViewTag;
this.applist = this.find("sys-applist") as GUI.tag.ListViewTag;
let services = [];
for (var k in setting.system.packages) {
const v = setting.system.packages[k];
if (v.services) {
const srvs = v.services.map((x) => {
return {
text: `${k}/${x}`,
iconclass: "fa fa-tasks",
}
}
);
services = services.concat(srvs);
}
}
this.srvlist.data = services;
this.srvlist.buttons = [
{
text: "Start",
onbtclick: () => {
const item = this.srvlist.selectedItem;
if (!item) {
return;
}
GUI
.pushService(item.data.text)
.catch((e) => this.parent.error(e.toString(), e));
},
},
{
text: "Stop",
onbtclick: () => {
const item = this.srvlist.selectedItem;
if (!item) {
return;
}
const arr = item.data.text.split("/");
const srv = arr[1];
PM.killAll(srv, true);
},
},
];
this.applist.buttons = [
{
text: "+",
onbtclick: () => {
const apps = (() => {
const result = [];
for (let k in setting.system.packages) {
const v = setting.system.packages[k];
if(v.app)
{
result.push({
text: v.name,
app: k,
iconclass: v.iconclass,
});
}
}
return result.sort((a,b) =>{
if(a.text >b.text) return 1;
if(a.text < b.text) return -1;
return 0;
});
})();
this.parent
.openDialog("SelectionDialog", {
title: "__(Add application)",
data: apps,
})
.then((d) => {
if (!setting.system.startup.pinned) {
setting.system.startup.pinned = [];
}
if (!setting.system.startup.pinned.includes(d.app)) {
setting.system.startup.pinned.push(d.app);
return this.refresh();
}
});
},
},
{
text: "-",
onbtclick: () => {
const item = this.applist.selectedItem;
if (!item) {
return;
}
const selidx = $(item).index();
setting.system.startup.pinned.splice(selidx, 1);
return this.refresh();
},
},
];
this.refresh();
}
/**
*
*
* @private
* @memberof AppAndServiceHandle
*/
private refresh(): void {
let v;
if (!setting.system.startup.pinned) {
return;
}
this.applist.data = (() => {
const result1 = [];
for (v of Array.from(setting.system.startup.pinned)) {
result1.push({ text: v, iconclass: "fa fa-adn" });
}
return result1;
})();
announcer.ostrigger("app-pinned", this.applist.data);
}
}
App.AppAndServiceHandle = AppAndServiceHandle;
}

View File

@ -1,4 +1,4 @@
module_files = main.js AppearanceHandle.js VFSHandle.js LocaleHandle.js StartupHandle.js module_files = main.js AppearanceHandle.js AppAndServiceHandle.js VFSHandle.js LocaleHandle.js StartupHandle.js
libfiles = libfiles =

View File

@ -66,8 +66,11 @@ namespace OS {
data: services, data: services,
}) })
.then((d) => { .then((d) => {
setting.system.startup.services.push(d.text); if(!setting.system.startup.services.includes(d.text))
return this.refresh(); {
setting.system.startup.services.push(d.text);
return this.refresh();
}
}); });
}, },
}, },
@ -93,12 +96,20 @@ namespace OS {
const result = []; const result = [];
for (let k in setting.system.packages) { for (let k in setting.system.packages) {
const v = setting.system.packages[k]; const v = setting.system.packages[k];
result.push({ if(v.app)
text: k, {
iconclass: v.iconclass, result.push({
}); text: v.name,
app: k,
iconclass: v.iconclass,
});
}
} }
return result; return result.sort((a,b) =>{
if(a.text >b.text) return 1;
if(a.text < b.text) return -1;
return 0;
});
})(); })();
this.parent this.parent
.openDialog("SelectionDialog", { .openDialog("SelectionDialog", {
@ -106,8 +117,11 @@ namespace OS {
data: apps, data: apps,
}) })
.then((d) => { .then((d) => {
setting.system.startup.apps.push(d.text); if(!setting.system.startup.apps.includes(d.app))
return this.refresh(); {
setting.system.startup.apps.push(d.app);
return this.refresh();
}
}); });
}, },
}, },
@ -138,7 +152,7 @@ namespace OS {
this.srvlist.data = (() => { this.srvlist.data = (() => {
const result = []; const result = [];
for (v of setting.system.startup.services) { for (v of setting.system.startup.services) {
result.push({ text: v }); result.push({ text: v});
} }
return result; return result;
})(); })();

View File

@ -50,6 +50,11 @@ afx-app-window[data-id = "setting-window"] afx-hbox[data-id="locale"] afx-list-v
} }
/*STARTUP*/ /*STARTUP*/
afx-app-window[data-id = "setting-window"] afx-hbox[data-id="startup"] afx-list-view afx-app-window[data-id = "setting-window"] afx-hbox[data-id="startup"] afx-list-view
{
border: 1px solid #cbcbcb;
}
afx-app-window[data-id = "setting-window"] afx-hbox[data-id="app-services"] afx-list-view
{ {
border: 1px solid #cbcbcb; border: 1px solid #cbcbcb;
} }

View File

@ -81,6 +81,7 @@ namespace OS {
static LocaleHandle: typeof SettingHandle; static LocaleHandle: typeof SettingHandle;
static StartupHandle: typeof SettingHandle; static StartupHandle: typeof SettingHandle;
static SettingHandle: typeof SettingHandle; static SettingHandle: typeof SettingHandle;
static AppAndServiceHandle: typeof SettingHandle;
/** /**
*Creates an instance of Setting. *Creates an instance of Setting.
@ -103,6 +104,7 @@ namespace OS {
new Setting.VFSHandle(this.find("vfs"), this); new Setting.VFSHandle(this.find("vfs"), this);
new Setting.LocaleHandle(this.find("locale"), this); new Setting.LocaleHandle(this.find("locale"), this);
new Setting.StartupHandle(this.find("startup"), this); new Setting.StartupHandle(this.find("startup"), this);
new Setting.AppAndServiceHandle(this.find("app-services"), this);
(this.find("btnsave") as GUI.tag.ButtonTag ).onbtclick = (e) => { (this.find("btnsave") as GUI.tag.ButtonTag ).onbtclick = (e) => {
this._api this._api

View File

@ -6,7 +6,7 @@
"author": "Xuan Sang LE", "author": "Xuan Sang LE",
"email": "xsang.le@gmail.com" "email": "xsang.le@gmail.com"
}, },
"version":"0.0.1-a", "version":"0.1.1-a",
"category":"System", "category":"System",
"iconclass":"fa fa-wrench", "iconclass":"fa fa-wrench",
"mimes":["none"] "mimes":["none"]

View File

@ -1,6 +1,6 @@
<afx-app-window data-id = "setting-window" apptitle="Setting" width="600" height="400"> <afx-app-window data-id = "setting-window" apptitle="Setting" width="650" height="400">
<afx-vbox> <afx-vbox>
<afx-tab-container data-id = "container" dir = "row" tabbarwidth= "120"> <afx-tab-container data-id = "container" dir = "row" tabbarwidth= "150">
<afx-hbox tabname="__(Appearance)" data-id="appearance" iconclass = "fa fa-paint-brush"> <afx-hbox tabname="__(Appearance)" data-id="appearance" iconclass = "fa fa-paint-brush">
<div data-width="10"></div> <div data-width="10"></div>
@ -77,9 +77,22 @@
<div data-width="10"></div> <div data-width="10"></div>
</afx-hbox> </afx-hbox>
<afx-hbox data-id="app-services" tabname = "__(Apps. and Services)" iconclass = "fa fa-adn">
<div data-width="10"></div>
<afx-vbox>
<afx-label text = "__(Services)" iconclass = "fa fa-tasks" class = "header" data-height="23"></afx-label>
<afx-list-view data-id="sys-srvlist"></afx-list-view>
<div data-height="5"></div>
<afx-label text = "__(Pinned applications)" iconclass = "fa fa-adn" class = "header" data-height="23"></afx-label>
<afx-list-view data-id="sys-applist"></afx-list-view>
<div data-height="10"></div>
</afx-vbox>
<div data-width="10"></div>
</afx-hbox>
</afx-tab-container> </afx-tab-container>
<afx-hbox data-height="35"> <afx-hbox data-height="35">
<div data-width = "120" class = "footer"></div> <div data-width = "150" class = "footer"></div>
<div style="text-align:right" > <div style="text-align:right" >
<afx-button text="__(Save)" data-id="btnsave" iconclass="fa fa-save" style="margin-right:10px;" ></afx-button> <afx-button text="__(Save)" data-id="btnsave" iconclass="fa fa-save" style="margin-right:10px;" ></afx-button>
</div> </div>

View File

@ -3,6 +3,11 @@ afx-grid-view afx-grid-row:nth-child(even) afx-grid-cell
background-color: #3b3b3b; background-color: #3b3b3b;
} }
afx-grid-view afx-grid-row:nth-child(odd) afx-grid-cell
{
background-color: #363636;
}
afx-grid-view afx-grid-row.afx-grid-row-selected afx-grid-cell afx-grid-view afx-grid-row.afx-grid-row-selected afx-grid-cell
{ {
background-color: #116cd6; background-color: #116cd6;

View File

@ -2,7 +2,10 @@ afx-grid-view afx-grid-row:nth-child(even) afx-grid-cell
{ {
background-color: #f5F5F5; background-color: #f5F5F5;
} }
afx-grid-view afx-grid-row:nth-child(odd) afx-grid-cell
{
background-color: white;
}
afx-grid-view afx-grid-row.afx-grid-row-selected afx-grid-cell afx-grid-view afx-grid-row.afx-grid-row-selected afx-grid-cell
{ {
background-color: #116cd6; background-color: #116cd6;

View File

@ -21,6 +21,10 @@ afx-sys-panel .afx-panel-os-stray{
position: relative; position: relative;
} }
afx-sys-panel .afx-panel-os-pinned-app afx-menu-entry{
display: inline-block;
}
afx-sys-panel afx-menu.afx-panel-os-stray afx-menu { afx-sys-panel afx-menu.afx-panel-os-stray afx-menu {
right: 0; right: 0;
position: absolute; position: absolute;