diff --git a/src/core/BaseApplication.ts b/src/core/BaseApplication.ts index f810594..68111ad 100644 --- a/src/core/BaseApplication.ts +++ b/src/core/BaseApplication.ts @@ -134,7 +134,7 @@ namespace OS { 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); return this.loadScheme(); } diff --git a/src/core/gui.ts b/src/core/gui.ts index 381a7ad..c6a4905 100644 --- a/src/core/gui.ts +++ b/src/core/gui.ts @@ -619,9 +619,9 @@ namespace OS { data.iconclass = "fa fa-cogs"; } const dock = $("#sysdock")[0] as tag.AppDockTag; + app.sysdock = dock; app.init(); app.observable.one("rendered", function () { - app.sysdock = dock; app.appmenu = $( "[data-id = 'appmenu']", "#syspanel" @@ -815,6 +815,7 @@ namespace OS { if (arr.length > 1) { tip = arr[1]; } + console.log(el); const offset = $(el).offset(); const w = $(el).width(); const h = $(el).height(); @@ -829,6 +830,10 @@ namespace OS { left = offset.left + w / 2 - $(label).width() / 2; top = offset.top - $(label).height() - 5; break; + case "cb": // center bottom + left = offset.left + w / 2 - $(label).width() / 2; + top = offset.top + $(label).height() + 10; + break; default: if (!e) { return; @@ -944,7 +949,7 @@ namespace OS { $("#systooltip")[0].uify(undefined); $("#contextmenu")[0].uify(undefined); - $("#workspace").on("contextmenu",(e) => bindContextMenu(e)); + $("#wrapper").on("contextmenu",(e) => bindContextMenu(e)); // tooltip $(document).on("mouseover", function (e) { const el: any = $(e.target).closest("[tooltip]"); diff --git a/src/core/settings.ts b/src/core/settings.ts index 6357825..68a9a8b 100644 --- a/src/core/settings.ts +++ b/src/core/settings.ts @@ -356,6 +356,13 @@ namespace OS { * @type {string[]} */ services: string[]; + + /** + * List of pinned applications + * + * @type {string[]} + */ + pinned: string[]; }; } /** @@ -476,6 +483,7 @@ namespace OS { startup: { apps: [], services: ["Syslog/PushNotification", "Syslog/Calendar"], + pinned: [], }, }; } @@ -530,7 +538,7 @@ namespace OS { for (let k in setting.system.packages) { const v = setting.system.packages[k]; if (v.app) { - var e, k1, v1; + var e: any, k1: string, v1: { [x: string]: any; detail?: any; path?: any; complex?: any; }; if ( v.name.match(term) || (v.description && v.description.match(term)) diff --git a/src/core/tags/AppDockTag.ts b/src/core/tags/AppDockTag.ts index a71a365..c7384cc 100644 --- a/src/core/tags/AppDockTag.ts +++ b/src/core/tags/AppDockTag.ts @@ -83,7 +83,25 @@ namespace OS { * @param {*} [d] * @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 @@ -171,10 +189,8 @@ namespace OS { el[0].uify(this.observable); bt.set(item); bt.data = item.app; - $(el).on("mouseover", (e) =>{ - el.attr("tooltip", `cr:${item.app.title()}`); - }); item.domel = bt; + $(bt).attr("tooltip", `cr:${item.app.title()}`); bt.onbtclick = (e) => { e.id = this.aid; //e.data.item = item; diff --git a/src/core/tags/SystemPanelTag.ts b/src/core/tags/SystemPanelTag.ts index 6090576..00e64aa 100644 --- a/src/core/tags/SystemPanelTag.ts +++ b/src/core/tags/SystemPanelTag.ts @@ -57,7 +57,7 @@ namespace OS { * @protected * @memberof SystemPanelTag */ - protected init(): void {} + protected init(): void { } /** * Do nothing @@ -66,7 +66,7 @@ namespace OS { * @param {*} [d] * @memberof SystemPanelTag */ - protected reload(d?: any): void {} + protected reload(d?: any): void { } /** * Attach a service to the system tray on the pannel, @@ -178,6 +178,11 @@ namespace OS { ref: "osmenu", class: "afx-panel-os-menu", }, + { + el: "afx-menu", + ref: "pinned", + class: "afx-panel-os-pinned-app", + }, { el: "afx-menu", id: "appmenu", @@ -305,9 +310,30 @@ namespace OS { * @memberof SystemPanelTag */ calibrate(): void { - (this.refs.overlay as OverlayTag).height = `${ - $(window).height() - $(this.refs.panel).height() - }px`; + (this.refs.overlay as OverlayTag).height = `${$(window).height() - $(this.refs.panel).height() + }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); }; - $(this.refs.search).on("keyup",(e) => { + $(this.refs.search).on("keyup", (e) => { return this.search(e); }); - $(this.refs.applist).on("click",(e) => { + $(this.refs.applist).on("click", (e) => { return this.open(); }); Ant.OS.GUI.bindKey("CTRL- ", (e) => { @@ -378,6 +404,32 @@ namespace OS { .css("top", `${$(this.refs.panel).height()}px`) .css("bottom", "0") .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 + ) { + GUI.launch("Setting",[]); + } + m.show(e); + }; + announcer.observable.on("app-pinned", (d) => { + this.RefreshPinnedApp(); + }); + this.RefreshPinnedApp(); } } diff --git a/src/core/tags/WindowTag.ts b/src/core/tags/WindowTag.ts index c4c9a87..69c05a8 100644 --- a/src/core/tags/WindowTag.ts +++ b/src/core/tags/WindowTag.ts @@ -209,6 +209,7 @@ namespace OS { $(this).attr("apptitle", v.__()); if (v) { (this.refs["txtTitle"] as LabelTag).text = v; + this.observable.trigger("apptitlechange", this); } } get apptitle(): string | FormattedString { diff --git a/src/packages/CodePad/BaseExtension.ts b/src/packages/CodePad/BaseExtension.ts index 0cc52a0..3ad6b22 100644 --- a/src/packages/CodePad/BaseExtension.ts +++ b/src/packages/CodePad/BaseExtension.ts @@ -83,12 +83,10 @@ namespace OS { * @memberof BaseExtension */ protected logger() { - if(!this.app.setting.showBottomBar) - { + if (!this.app.setting.showBottomBar) { this.app.showOutput(true); } - else - { + else { this.app.showOutput(false); } return this.app.logger; @@ -142,7 +140,7 @@ namespace OS { * @memberof BaseExtension */ protected copy(files: string[], to: string): Promise { - return new Promise((resolve, reject) =>{ + return new Promise((resolve, reject) => { if (files.length === 0) { return resolve(); } @@ -232,8 +230,8 @@ namespace OS { .then( (d: { result: - | Iterable - | ArrayLike; + | Iterable + | ArrayLike; }) => { const l = (d.result as API.FileInfoType[]).map( (v) => v.path @@ -440,16 +438,33 @@ namespace OS { .asFileHandle() .read("json") .then((data) => { - if(!data.root && this.app.currdir) - { + if (!data.root && this.app.currdir) { data.root = this.app.currdir.path; } resolve(data); }) .catch((e) => { - return reject( - API.throwe(__("Unable to read meta-data")) - ); + // try to ask user to select a folder + 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")) + )) }); }); } diff --git a/src/packages/MarketPlace/package.json b/src/packages/MarketPlace/package.json index ebfdd76..98da55c 100644 --- a/src/packages/MarketPlace/package.json +++ b/src/packages/MarketPlace/package.json @@ -8,7 +8,7 @@ }, "version":"0.2.2-a", "category":"System", - "iconclass":"fa fa-adn", + "iconclass":"fa fa-shopping-bag", "mimes":["none"], "locales": {} } \ No newline at end of file diff --git a/src/packages/Setting/AppAndServiceHandle.ts b/src/packages/Setting/AppAndServiceHandle.ts new file mode 100644 index 0000000..9c262b0 --- /dev/null +++ b/src/packages/Setting/AppAndServiceHandle.ts @@ -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 + +// 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; +} diff --git a/src/packages/Setting/Makefile b/src/packages/Setting/Makefile index 630c4f6..e9d3479 100644 --- a/src/packages/Setting/Makefile +++ b/src/packages/Setting/Makefile @@ -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 = diff --git a/src/packages/Setting/StartupHandle.ts b/src/packages/Setting/StartupHandle.ts index 0aa1914..e976240 100644 --- a/src/packages/Setting/StartupHandle.ts +++ b/src/packages/Setting/StartupHandle.ts @@ -66,8 +66,11 @@ namespace OS { data: services, }) .then((d) => { - setting.system.startup.services.push(d.text); - return this.refresh(); + if(!setting.system.startup.services.includes(d.text)) + { + setting.system.startup.services.push(d.text); + return this.refresh(); + } }); }, }, @@ -93,12 +96,20 @@ namespace OS { const result = []; for (let k in setting.system.packages) { const v = setting.system.packages[k]; - result.push({ - text: k, - iconclass: v.iconclass, - }); + if(v.app) + { + 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 .openDialog("SelectionDialog", { @@ -106,8 +117,11 @@ namespace OS { data: apps, }) .then((d) => { - setting.system.startup.apps.push(d.text); - return this.refresh(); + if(!setting.system.startup.apps.includes(d.app)) + { + setting.system.startup.apps.push(d.app); + return this.refresh(); + } }); }, }, @@ -138,7 +152,7 @@ namespace OS { this.srvlist.data = (() => { const result = []; for (v of setting.system.startup.services) { - result.push({ text: v }); + result.push({ text: v}); } return result; })(); diff --git a/src/packages/Setting/main.css b/src/packages/Setting/main.css index 92f7941..3ef822f 100644 --- a/src/packages/Setting/main.css +++ b/src/packages/Setting/main.css @@ -50,6 +50,11 @@ afx-app-window[data-id = "setting-window"] afx-hbox[data-id="locale"] afx-list-v } /*STARTUP*/ 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; } \ No newline at end of file diff --git a/src/packages/Setting/main.ts b/src/packages/Setting/main.ts index 159e0e6..92b3e89 100644 --- a/src/packages/Setting/main.ts +++ b/src/packages/Setting/main.ts @@ -81,6 +81,7 @@ namespace OS { static LocaleHandle: typeof SettingHandle; static StartupHandle: typeof SettingHandle; static SettingHandle: typeof SettingHandle; + static AppAndServiceHandle: typeof SettingHandle; /** *Creates an instance of Setting. @@ -103,6 +104,7 @@ namespace OS { new Setting.VFSHandle(this.find("vfs"), this); new Setting.LocaleHandle(this.find("locale"), 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._api diff --git a/src/packages/Setting/package.json b/src/packages/Setting/package.json index e50bc7a..47af60d 100644 --- a/src/packages/Setting/package.json +++ b/src/packages/Setting/package.json @@ -6,7 +6,7 @@ "author": "Xuan Sang LE", "email": "xsang.le@gmail.com" }, - "version":"0.0.1-a", + "version":"0.1.1-a", "category":"System", "iconclass":"fa fa-wrench", "mimes":["none"] diff --git a/src/packages/Setting/scheme.html b/src/packages/Setting/scheme.html index 28bfef3..e16ddaa 100644 --- a/src/packages/Setting/scheme.html +++ b/src/packages/Setting/scheme.html @@ -1,6 +1,6 @@ - + - +
@@ -77,9 +77,22 @@
+ +
+ + + +
+ + +
+
+
+
+
- +
diff --git a/src/themes/antos_dark/afx-grid-view.css b/src/themes/antos_dark/afx-grid-view.css index 74db391..af179b5 100644 --- a/src/themes/antos_dark/afx-grid-view.css +++ b/src/themes/antos_dark/afx-grid-view.css @@ -3,6 +3,11 @@ afx-grid-view afx-grid-row:nth-child(even) afx-grid-cell 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 { background-color: #116cd6; diff --git a/src/themes/antos_light/afx-grid-view.css b/src/themes/antos_light/afx-grid-view.css index 6acde69..98880cc 100644 --- a/src/themes/antos_light/afx-grid-view.css +++ b/src/themes/antos_light/afx-grid-view.css @@ -2,7 +2,10 @@ afx-grid-view afx-grid-row:nth-child(even) afx-grid-cell { 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 { background-color: #116cd6; diff --git a/src/themes/system/afx-sys-panel.css b/src/themes/system/afx-sys-panel.css index 5a93fe4..1d34a47 100644 --- a/src/themes/system/afx-sys-panel.css +++ b/src/themes/system/afx-sys-panel.css @@ -21,6 +21,10 @@ afx-sys-panel .afx-panel-os-stray{ 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 { right: 0; position: absolute;