diff --git a/README-RU.md b/README-RU.md index 2265e2d..35e113d 100644 --- a/README-RU.md +++ b/README-RU.md @@ -78,7 +78,7 @@ AppLauncher поддерживает: - NV-102 (+) - - NV-300 + - NV-300 (+) - Mag STB (Aura STB) diff --git a/README.md b/README.md index 7b365bb..cd3a232 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ AppLauncher AppLauncher allows running Smart TV and STB application avoiding standard installation process. -AppLauncher lets to create list of applications’ URLs to run. URLs are sorted +AppLauncher lets to create list of applications URLs to run. URLs are sorted according to last activities: adding or launching. Install AppLauncher once and easily run dozens of your applications at Smart TV @@ -18,11 +18,11 @@ or STB. Important details: -1. You have to run web-server to provide application's URL to run. AppLauncher +1. You have to run web-server to provide application URL to run. AppLauncher works only with URLs, not ipk or zip files! -2. AppLauncher could not check applications’ URLs before running them due to - platforms' limitations. Be careful while entering URL. Improper URL can +2. AppLauncher could not check applications URLs before running them due to + platforms limitations. Be careful while entering URL. Improper URL can cause Smart TV/STB hang-up. Reboot your Smart TV/STB in this situation. 3. You can use remote control digital buttons to enter digits into URL instead @@ -36,7 +36,7 @@ Platforms AppLauncer was tested on devices marked (+). It must also work on other devices listed below, but there can be problems of various types. If you run AppLauncher on devices without (+) mark, please write mail to -[applauncher@interfaced.ru](mailto:applauncher@interfaced.ru) and inform us about both success and problems +[applauncher@interfaced.tv](mailto:applauncher@interfaced.tv) and inform us about both success and problems you have. @@ -77,7 +77,7 @@ AppLauncher supports: - NV-102 (+) - - NV-300 + - NV-300 (+) - Mag STB (Aura STB) diff --git a/app/launcher/app-config.js b/app/launcher/app-config.js index 17ffe2e..41e9cce 100644 --- a/app/launcher/app-config.js +++ b/app/launcher/app-config.js @@ -6,5 +6,6 @@ goog.provide('launcher.appConfig'); * @struct */ launcher.appConfig = { + googleAnalyticsId: 'UA-29756002-6', noticeTime: 5000 }; diff --git a/app/launcher/application.js b/app/launcher/application.js index 80cb396..d7ad26f 100644 --- a/app/launcher/application.js +++ b/app/launcher/application.js @@ -2,6 +2,7 @@ goog.provide('launcher.Application'); goog.require('launcher.BaseApplication'); goog.require('launcher.services.AppList'); goog.require('launcher.services.HelpBarItemFactory'); +goog.require('zb.ui.GoogleAnalytics'); @@ -12,6 +13,7 @@ goog.require('launcher.services.HelpBarItemFactory'); launcher.Application = function() { zb.console.setLevel(zb.console.Level.LOG | zb.console.Level.ERROR); this.services = { + ga: null, appList: null, helpBarItemFactory: null }; @@ -33,6 +35,21 @@ launcher.Application.prototype.canBack = function() { * @inheritDoc */ launcher.Application.prototype.onReady = function() { + var gaId = ''; + if (COMPILED) { + gaId = launcher.appConfig.googleAnalyticsId; + + this._layerManager.on(this._layerManager.EVENT_TRANSITION_SUCCESS, function(eventName, transitionData) { + transitionData = /** @type {zb.LayerManager.TransitionData} */(transitionData); + var layer = transitionData.layer; + var pageName = '/' + /s-([a-z0-9\-]+)$/i.exec(layer.getCSSClassName())[1]; + this.services.ga.sendPageview(pageName); + }.bind(this)); + } + + this.services.ga = new zb.ui.GoogleAnalytics(gaId, this.device, { + analyticsJS: 'analytics.js' + }); this.services.appList = new launcher.services.AppList(this.device.storage); this.services.helpBarItemFactory = new launcher.services.HelpBarItemFactory; this.setHomeScene('app-list'); @@ -45,8 +62,10 @@ launcher.Application.prototype.onReady = function() { launcher.Application.prototype.onStart = function() { var apps = this.services.appList.getApps(); if (apps.length) { + this.services.ga.sendEvent('app', 'start'); this.home(); } else { + this.services.ga.sendEvent('app', 'first-start'); this.show('app-add', {}); } }; @@ -70,6 +89,7 @@ launcher.Application.prototype._appendScreenSizeClass = function() { /** * @type {{ + * ga: zb.ui.GoogleAnalytics, * appList: launcher.services.AppList, * helpBarItemFactory: launcher.services.HelpBarItemFactory * }} diff --git a/app/launcher/scenes/about/about.js b/app/launcher/scenes/about/about.js index 78f448b..42acecd 100644 --- a/app/launcher/scenes/about/about.js +++ b/app/launcher/scenes/about/about.js @@ -1,6 +1,6 @@ goog.provide('launcher.scenes.About'); -goog.require('launcher.scenes.AbstractBase'); goog.require('launcher.scenes.templates.about.about'); +goog.require('launcher.scenes.AbstractBase'); @@ -11,12 +11,14 @@ goog.require('launcher.scenes.templates.about.about'); launcher.scenes.About = function() { goog.base(this); this._addContainerClass('s-about'); + + this._createHelpBar(); }; goog.inherits(launcher.scenes.About, launcher.scenes.AbstractBase); /** - * @inheritDoc + * @protected */ launcher.scenes.About.prototype._createHelpBar = function() { goog.base(this, '_createHelpBar'); @@ -30,16 +32,14 @@ launcher.scenes.About.prototype._createHelpBar = function() { }; -/** - * @inheritDoc - */ +/** @inheritDoc */ launcher.scenes.About.prototype._renderTemplate = function() { return launcher.scenes.templates.about.about(this._getTemplateData(), this._getTemplateOptions()); }; /** -* @type {launcher.scenes.templates.about.AboutOut} -* @protected -*/ + * @type {launcher.scenes.templates.about.AboutOut} + * @protected + */ launcher.scenes.About.prototype._exported; diff --git a/app/launcher/scenes/about/about.jst b/app/launcher/scenes/about/about.jst index 99442f9..01233d5 100644 --- a/app/launcher/scenes/about/about.jst +++ b/app/launcher/scenes/about/about.jst @@ -3,17 +3,17 @@

AppLauncher allows to run Smart TV and STB application avoiding standard application installation process. - AppLauncher lets to create list of applications’ URLs to run. + AppLauncher lets to create list of applications URLs to run. URLs are sorted according to last activities: adding or launching.

Attention: - AppLauncher couldn’t check applications’ URLs before running them due to platform limitations. + AppLauncher couldn’t check applications URLs before running them due to platform limitations. Be careful while entering URL. Improper URL can cause Smart TV/STB hang-up. Reboot your Smart TV/STB in this situation.

Developed by Interfaced -
site: interfaced.ru, e-mail: info@ifaced.ru +
site: interfaced.tv, e-mail: info@interfaced.tv
diff --git a/app/launcher/scenes/abstract-base/abstract-base.css b/app/launcher/scenes/abstract-base/abstract-base.css index d8723bf..d3758ce 100644 --- a/app/launcher/scenes/abstract-base/abstract-base.css +++ b/app/launcher/scenes/abstract-base/abstract-base.css @@ -12,7 +12,7 @@ font-size: 47px; font-weight: bold; } - .s-abstract-base-head__made { + .s-abstract-base-head__version { font-size: 23px; margin-left: 5px; } @@ -33,6 +33,9 @@ .s-abstract-base-head__notice._remove { background: #e78787; } + .s-abstract-base-head__notice._change { + background: #f8d56e; + } .s-abstract-base {} .s-abstract-base .s-abstract-base-head { diff --git a/app/launcher/scenes/abstract-base/abstract-base.js b/app/launcher/scenes/abstract-base/abstract-base.js index 92c59f6..1730703 100644 --- a/app/launcher/scenes/abstract-base/abstract-base.js +++ b/app/launcher/scenes/abstract-base/abstract-base.js @@ -45,6 +45,16 @@ launcher.scenes.AbstractBase.prototype.processKey = function(zbKey, e) { */ launcher.scenes.AbstractBase.prototype._createHelpBar = function() { this._helpBar = new zb.ui.HelpBar; + this._helpBar.setOrder([ + zb.device.input.Keys.ENTER, + zb.device.input.Keys.PAGE_UP, + zb.device.input.Keys.PAGE_DOWN, + zb.device.input.Keys.RED, + zb.device.input.Keys.GREEN, + zb.device.input.Keys.YELLOW, + zb.device.input.Keys.BLUE, + zb.device.input.Keys.BACK + ]); this._container.appendChild(this._helpBar.getContainer()); this.appendWidget(this._helpBar); }; diff --git a/app/launcher/scenes/abstract-base/abstract-base.jst b/app/launcher/scenes/abstract-base/abstract-base.jst index c9d18e2..8805794 100644 --- a/app/launcher/scenes/abstract-base/abstract-base.jst +++ b/app/launcher/scenes/abstract-base/abstract-base.jst @@ -3,7 +3,7 @@
AppLauncher - by Interfaced + v.{{- zb.packageInfo.version }}
URL added
diff --git a/app/launcher/scenes/app-add/app-add-input-active.png b/app/launcher/scenes/app-add/app-add-input-active.png new file mode 100644 index 0000000..4a19151 Binary files /dev/null and b/app/launcher/scenes/app-add/app-add-input-active.png differ diff --git a/app/launcher/scenes/app-add/app-add-input.png b/app/launcher/scenes/app-add/app-add-input.png new file mode 100644 index 0000000..58c7d1b Binary files /dev/null and b/app/launcher/scenes/app-add/app-add-input.png differ diff --git a/app/launcher/scenes/app-add/app-add.css b/app/launcher/scenes/app-add/app-add.css index 7d15e28..8a77764 100644 --- a/app/launcher/scenes/app-add/app-add.css +++ b/app/launcher/scenes/app-add/app-add.css @@ -1,17 +1,30 @@ /* AppAdd scene *******************************/ +.s-app-add-input-button { + background: url(app-add-input.png) 50% 50% no-repeat; + border: 2px solid #00809c; + border-radius: 12px; +} + +.s-app-add-input-button._active { + background-color: #00809c; + background-image: url(app-add-input-active.png); +} + .s-app-add-input {} .s-app-add-input__title { - text-align: center; font-size: 23px; font-weight: bold; + text-align: center; } .s-app-add-input__address { position: relative; margin-top: 8px; } - .s-app-add-input .w-button { + .s-app-add-input .s-app-add-input-button { + width: 60px; + height: 40px; position: absolute; top: 0; left: 100%; @@ -19,30 +32,29 @@ } .s-app-add-input__input { width: 100%; - font-size: 23px; + font-size: 24px; + padding: 7px 0; box-sizing: border-box; - padding: 7px; - padding-right: 0; - border: 1px solid #022a33; + outline: 1px solid #022a33; } .s-app-add-input__input._active { - box-shadow: 0 0 5px #00809c; - } - .s-app-add-input__input:focus { - outline: none; + box-shadow: 0 0 8px 2px #00809c; } .s-app-add-input__warning { font-size: 18px; color: #00809c; margin-top: 17px; } + .s-app-add-input .w-zbui-div-input .w-zbui-div-input__wrapper { + margin-left: 7px; + } .s-app-add {} .s-app-add .s-app-add-input { position: absolute; top: 50px; - left: 200px; right: 200px; + left: 200px; } .s-app-add .w-keyboard { position: absolute; diff --git a/app/launcher/scenes/app-add/app-add.js b/app/launcher/scenes/app-add/app-add.js index 4d182df..6ae913a 100644 --- a/app/launcher/scenes/app-add/app-add.js +++ b/app/launcher/scenes/app-add/app-add.js @@ -1,6 +1,7 @@ goog.provide('launcher.scenes.AppAdd'); goog.require('launcher.scenes.AbstractBase'); goog.require('launcher.scenes.templates.appAdd.appAdd'); +goog.require('zb.html'); @@ -9,6 +10,8 @@ goog.require('launcher.scenes.templates.appAdd.appAdd'); * @extends {launcher.scenes.AbstractBase} */ launcher.scenes.AppAdd = function() { + this._url = null; + goog.base(this); this._addContainerClass('s-app-add'); this.setDefaultWidget(this._exported.input); @@ -18,21 +21,49 @@ launcher.scenes.AppAdd = function() { }.bind(this)); this._exported.input.on(this._exported.input.EVENT_FINISH, this._onInputFinish.bind(this)); + this._exported.input.setTheme(this._exported.input.THEME_NONE); this._exported.keyboard.setInput(this._exported.input); - this.setNavigationRule(this._exported.keyboard, zb.Direction.RIGHT, null); - this.setNavigationRule(this._exported.keyboard, zb.Direction.LEFT, null); + this.setNavigationRule(this._exported.keyboard, zb.std.plain.Direction.Value.RIGHT, null); + this.setNavigationRule(this._exported.keyboard, zb.std.plain.Direction.Value.LEFT, null); }; goog.inherits(launcher.scenes.AppAdd, launcher.scenes.AbstractBase); /** + * @param {launcher.scenes.AppAdd.Data} data * @inheritDoc */ launcher.scenes.AppAdd.prototype.beforeDOMShow = function(state, data) { goog.base(this, 'beforeDOMShow', state, data); - this._exported.input.setValue('http://'); + + if (state) { + return; + } + + var url = 'http://'; + var title = 'New application URL'; + var savedUrl = null; + + if (data.url !== undefined) { + url = data.url; + savedUrl = data.url; + title = 'Edit application URL'; + } + + this._url = savedUrl; + this._exported.input.setValue(url); + zb.html.text(this._exported.title, title); +}; + + +/** + * @inheritDoc + */ +launcher.scenes.AppAdd.prototype.afterDOMShow = function(state, data) { + goog.base(this, 'afterDOMShow', state, data); + this._exported.input.showCaret(true); }; @@ -60,6 +91,17 @@ launcher.scenes.AppAdd.prototype._renderTemplate = function() { }; +/** + * @inheritDoc + */ +launcher.scenes.AppAdd.prototype._processKey = function(zbKey, e) { + if (!this._exported.keyboard.processShortcutKey(zbKey)) { + return goog.base(this, '_processKey', zbKey, e); + } + return true; +}; + + /** * @param {string} eventName * @param {string} url @@ -68,7 +110,13 @@ launcher.scenes.AppAdd.prototype._renderTemplate = function() { launcher.scenes.AppAdd.prototype._onInputFinish = function(eventName, url) { if (url) { this._exported.input.setValue('', true); - app.services.appList.addApp(url); + + if (this._url !== null) { + app.services.appList.changeApp(this._url, url); + } else { + app.services.appList.addApp(url); + } + if (app.canBack()) { app.back(); } else { @@ -95,3 +143,24 @@ launcher.scenes.AppAdd.prototype._pressBack = function() { * @protected */ launcher.scenes.AppAdd.prototype._exported; + + +/** +* @type {?string} +* @protected +*/ +launcher.scenes.AppAdd.prototype._url; + + +/** + * @typedef {{ + * url: (string|undefined) + * }} + */ +launcher.scenes.AppAdd.Input; + + +/** + * @typedef {launcher.scenes.AppAdd.Input} + */ +launcher.scenes.AppAdd.Data; diff --git a/app/launcher/scenes/app-add/app-add.jst b/app/launcher/scenes/app-add/app-add.jst index ec01e33..db55984 100644 --- a/app/launcher/scenes/app-add/app-add.jst +++ b/app/launcher/scenes/app-add/app-add.jst @@ -1,10 +1,10 @@ {{$ launcher.scenes.templates.appAdd.appAdd }}
-
New application URL:
+
New application URL
-
add
- +
+
Be careful while printing URL. AppLauncher cannot validate URL due to platform limitations.
diff --git a/app/launcher/scenes/app-list/app-list.css b/app/launcher/scenes/app-list/app-list.css index 48b621a..3e99a3e 100644 --- a/app/launcher/scenes/app-list/app-list.css +++ b/app/launcher/scenes/app-list/app-list.css @@ -9,3 +9,20 @@ right: 0; left: 0; } + + .s-app-list__throbber-container { + width: 100%; + height: 100%; + background: rgba(0, 0, 0, 0.5); + display: none; + position: absolute; + top: 0; + left: 0; + } + .s-app-list__throbber-container .w-zbui-throbber { + position: absolute; + top: 50%; + left: 50%; + margin-top: -44px; + margin-left: -44px; + } diff --git a/app/launcher/scenes/app-list/app-list.js b/app/launcher/scenes/app-list/app-list.js index 143a582..9ff21d6 100644 --- a/app/launcher/scenes/app-list/app-list.js +++ b/app/launcher/scenes/app-list/app-list.js @@ -16,26 +16,24 @@ launcher.scenes.AppList = function() { this._addContainerClass('s-app-list'); this._appList = new zb.ui.DataList; - this._exported.appList.setDataList(this._appList, { - padding: this.COUNT_APPS_ON_PAGE - 1 + this._exported.appList.setSource(this._appList, { + padding: this.COUNT_APPS_ON_PAGE }); this._exported.appList.on(this._exported.appList.EVENT_CLICK, this._onAppClick.bind(this)); - app.services.appList.on(app.services.appList.EVENT_APP_LIST_CHANGED, this._setApps.bind(this)); - app.services.appList.on(app.services.appList.EVENT_APP_REMOVED, this._notice.showRemoved.bind(this._notice)); - app.services.appList.on(app.services.appList.EVENT_APP_ADDED, this._notice.showAdded.bind(this._notice)); -}; -goog.inherits(launcher.scenes.AppList, launcher.scenes.AbstractBase); + app.services.appList.on(app.services.appList.EVENT_APP_REMOVED, this._onAppRemoved.bind(this)); + app.services.appList.on(app.services.appList.EVENT_APP_ADDED, this._onAppAdded.bind(this)); + app.services.appList.on(app.services.appList.EVENT_APP_CHANGED, this._onAppChanged.bind(this)); + this._appList.setItems(app.services.appList.getApps()); -/** - * @inheritDoc - */ -launcher.scenes.AppList.prototype.afterDOMShow = function(state, data) { - goog.base(this, 'afterDOMShow', state, data); + // Prevent save/load state for app list. + delete this._namedWidgets['appList']; - this._appList.setItems(app.services.appList.getApps()); + this._configureThrobber(); + this._updateHelpBar(); }; +goog.inherits(launcher.scenes.AppList, launcher.scenes.AbstractBase); /** @@ -59,9 +57,10 @@ launcher.scenes.AppList.prototype._createHelpBar = function() { this._paginationHelpBarItem.hide(); helpBar.setItems([ - factory.createOk(this._executeApp.bind(this)), + factory.createOk(this._executeCurrentApp.bind(this)), factory.createBack(), factory.createRemoveApp(this._removeApp.bind(this)), + factory.createEditApp(this._editApp.bind(this)), factory.createAddApp(this._addApp.bind(this)), factory.createAbout(), this._paginationHelpBarItem @@ -85,16 +84,25 @@ launcher.scenes.AppList.prototype._updateHelpBar = function() { * @private */ launcher.scenes.AppList.prototype._onAppClick = function(eventName, appView) { - app.services.appList.executeApp(appView.url); + this._executeApp(appView.url); +}; + + +/** + * @private + */ +launcher.scenes.AppList.prototype._executeCurrentApp = function() { + this._executeApp(this._getCurrentAppUrl()); }; /** + * @param {string} url * @private */ -launcher.scenes.AppList.prototype._executeApp = function() { - var application = this._exported.appList.getCurrentData(); - app.services.appList.executeApp(application.url); +launcher.scenes.AppList.prototype._executeApp = function(url) { + var promise = app.services.appList.executeApp(url); + this._exported.throbber.wait(promise); }; @@ -102,17 +110,17 @@ launcher.scenes.AppList.prototype._executeApp = function() { * @private */ launcher.scenes.AppList.prototype._removeApp = function() { - var currentApp = this._appList.current(); - if (!currentApp) { + var url = this._getCurrentAppUrl(); + if (!url) { return; } launcher.popups.Confirm .asPromise({ - url: currentApp.url + url: url }) .then(function() { - app.services.appList.removeApp(currentApp.url); + app.services.appList.removeApp(url); var appList = app.services.appList.getApps(); if (!appList.length) { app.show('app-add', {}); @@ -129,13 +137,70 @@ launcher.scenes.AppList.prototype._addApp = function() { }; +/** + * @private + */ +launcher.scenes.AppList.prototype._editApp = function() { + var url = this._getCurrentAppUrl(); + if (!url) { + return; + } + + app.show('app-add', {url: url}); +}; + + +/** + * @return {string} + * @protected + */ +launcher.scenes.AppList.prototype._getCurrentAppUrl = function() { + var currentApp = this._appList.current(); + if (!currentApp) { + return ''; + } + + return currentApp.url; +}; + + +/** + * @param {string} eventName + * @param {number} index + * @param {string} url + * @private + */ +launcher.scenes.AppList.prototype._onAppRemoved = function(eventName, index, url) { + this._notice.showRemoved(); + this._appList.removeAt(index); + this._updateHelpBar(); +}; + + /** * @param {string} eventName - * @param {Array.} apps + * @param {number} index + * @param {string} url * @private */ -launcher.scenes.AppList.prototype._setApps = function(eventName, apps) { - this._appList.setItems(apps); +launcher.scenes.AppList.prototype._onAppAdded = function(eventName, index, url) { + var appItem = /** @type {!launcher.services.AppList.AppView} */(app.services.appList.getAppByIndex(index)); + this._notice.showAdded(); + this._appList.addAt(appItem, index); + this._appList.selectAt(index); + this._updateHelpBar(); +}; + + +/** + * @param {string} eventName + * @param {number} index + * @param {string} newUrl + * @param {string} oldUrl + * @private + */ +launcher.scenes.AppList.prototype._onAppChanged = function(eventName, index, newUrl, oldUrl) { + this._notice.showChanged(); this._updateHelpBar(); }; @@ -175,6 +240,21 @@ launcher.scenes.AppList.prototype._showHidePaginationHelpBarItem = function(show }; +/** + * @protected + */ +launcher.scenes.AppList.prototype._configureThrobber = function() { + var throbber = this._exported.throbber; + throbber.on(throbber.EVENT_START, function() { + this._exported.throbberContainer.style.display = 'block'; + }.bind(this)); + throbber.on(throbber.EVENT_STOP, function() { + this._exported.throbberContainer.style.display = 'none'; + }.bind(this)); + this._container.appendChild(this._exported.throbberContainer); +}; + + /** * @type {launcher.scenes.templates.appList.AppListOut} * @protected @@ -199,4 +279,4 @@ launcher.scenes.AppList.prototype._paginationHelpBarItem; /** * @const {number} */ -launcher.scenes.AppList.prototype.COUNT_APPS_ON_PAGE = 10; +launcher.scenes.AppList.prototype.COUNT_APPS_ON_PAGE = 9; diff --git a/app/launcher/scenes/app-list/app-list.jst b/app/launcher/scenes/app-list/app-list.jst index d021478..5b44791 100644 --- a/app/launcher/scenes/app-list/app-list.jst +++ b/app/launcher/scenes/app-list/app-list.jst @@ -1,3 +1,7 @@ {{$ launcher.scenes.templates.appList.appList }} {{% launcher.widgets.AppList, {}, appList }} + +
+ {{% zb.ui.Throbber, {}, throbber }} +
diff --git a/app/launcher/services/app-list.js b/app/launcher/services/app-list.js index 7e522ef..de14c08 100644 --- a/app/launcher/services/app-list.js +++ b/app/launcher/services/app-list.js @@ -16,25 +16,53 @@ launcher.services.AppList = function(storage) { goog.inherits(launcher.services.AppList, zb.events.EventPublisher); +/** + * @param {string} oldUrl + * @param {string} newUrl + * @return {boolean} + */ +launcher.services.AppList.prototype.changeApp = function(oldUrl, newUrl) { + this._logEvent('app-change'); + var index = this._findAppByUrl(oldUrl); + if (-1 !== index) { + this._apps[index].url = newUrl; + + // move to first position + var app = this._apps[index]; + this._apps.splice(index, 1); + this._fireEvent(this.EVENT_APP_REMOVED, index, newUrl); + this._apps.splice(index, 0, app); + this._fireEvent(this.EVENT_APP_ADDED, index, newUrl); + + this._fireEvent(this.EVENT_APP_CHANGED, newUrl, oldUrl); + + this._saveApps(); + return true; + } + return false; +}; + + /** * @param {string} url */ launcher.services.AppList.prototype.addApp = function(url) { + this._logEvent('app-add'); var index = this._findAppByUrl(url); if (-1 !== index) { - // prevent url duplication - return; + this.removeApp(url); } /** @type {launcher.services.AppList.AppView} */ var app = { url: url, - launchTime: Date.now(), + launchTime: NaN, launchCount: 0 }; + this._touchApp(app); this._apps.unshift(app); + this._fireEvent(this.EVENT_APP_ADDED, 0, url); this._saveApps(); - this._fireEvent(this.EVENT_APP_ADDED, url); }; @@ -42,28 +70,52 @@ launcher.services.AppList.prototype.addApp = function(url) { * @param {string} url */ launcher.services.AppList.prototype.removeApp = function(url) { + this._logEvent('app-remove'); var index = this._findAppByUrl(url); if (-1 !== index) { this._apps.splice(index, 1); + this._fireEvent(this.EVENT_APP_REMOVED, index, url); this._saveApps(); - this._fireEvent(this.EVENT_APP_REMOVED, url); } }; /** * @param {string} url + * @return {IThenable} */ launcher.services.AppList.prototype.executeApp = function(url) { + this._logEvent('app-execute'); var app = this._apps[this._findAppByUrl(url)]; if (app) { app.launchCount++; - app.launchTime = Date.now(); + this._touchApp(app); this._saveApps(); } - this._replaceUrl(url); + return new Promise(function(resolve, reject) { + // never resolve promise while new page is not loaded + this._replaceUrl(url); + }.bind(this)); +}; + + +/** + * @param {number} index + * @return {?launcher.services.AppList.AppView} + */ +launcher.services.AppList.prototype.getAppByIndex = function(index) { + return this._apps[index] || null; +}; + + +/** + * @param {string} url + * @return {?launcher.services.AppList.AppView} + */ +launcher.services.AppList.prototype.getAppByUrl = function(url) { + return this._apps[this._findAppByUrl(url)] || null; }; @@ -78,6 +130,23 @@ launcher.services.AppList.prototype.getApps = function() { }; +/** + * @param {string} eventName + * @private + */ +launcher.services.AppList.prototype._logEvent = function(eventName) { + app.services.ga.sendEvent('app', eventName); +}; + + +/** + * @param {launcher.services.AppList.AppView} app + */ +launcher.services.AppList.prototype._touchApp = function(app) { + app.launchTime = Date.now(); +}; + + /** * @param {string} url * @return {number} @@ -179,14 +248,21 @@ launcher.services.AppList.prototype.STORAGE_KEY = 'app-launcher-list'; /** - * Fired with: {string} url + * Fired with: {number} index, {string} url * @const {string} */ launcher.services.AppList.prototype.EVENT_APP_ADDED = 'app-added'; /** - * Fired with: {string} url + * Fired with: {number} index, {string} newUrl, {string} oldUrl + * @const {string} + */ +launcher.services.AppList.prototype.EVENT_APP_CHANGED = 'app-changed'; + + +/** + * Fired with: {number} index, {string} url * @const {string} */ launcher.services.AppList.prototype.EVENT_APP_REMOVED = 'app-removed'; diff --git a/app/launcher/services/help-bar-item-factory.js b/app/launcher/services/help-bar-item-factory.js index aee34a2..ea3cb4c 100644 --- a/app/launcher/services/help-bar-item-factory.js +++ b/app/launcher/services/help-bar-item-factory.js @@ -51,13 +51,26 @@ launcher.services.HelpBarItemFactory.prototype.createRemoveApp = function(opt_ha }; +/** + * @param {Function=} opt_handler + * @return {zb.ui.HelpBarItem} + */ +launcher.services.HelpBarItemFactory.prototype.createEditApp = function(opt_handler) { + return this._createHelpBarItem({ + label: 'edit selected', + keys: [zb.device.input.Keys.YELLOW], + cssClass: '_yellow' + }, opt_handler); +}; + + /** * @param {Function=} opt_handler * @return {zb.ui.HelpBarItem} */ launcher.services.HelpBarItemFactory.prototype.createAddApp = function(opt_handler) { return this._createHelpBarItem({ - label: 'add application', + label: 'add URL', keys: [zb.device.input.Keys.GREEN], cssClass: '_green' }, opt_handler); @@ -84,7 +97,7 @@ launcher.services.HelpBarItemFactory.prototype.createAbout = function(opt_handle */ launcher.services.HelpBarItemFactory.prototype.createPagination = function(opt_handler) { return this._createHelpBarItem({ - label: 'page up/page down', + label: 'page up/down', keys: [zb.device.input.Keys.PAGE_UP, zb.device.input.Keys.PAGE_DOWN], cssClass: '_pagination' }, opt_handler); diff --git a/app/launcher/widgets/app-list/app-list.css b/app/launcher/widgets/app-list/app-list.css index 01ec5d8..6cbcf17 100644 --- a/app/launcher/widgets/app-list/app-list.css +++ b/app/launcher/widgets/app-list/app-list.css @@ -35,7 +35,7 @@ } .w-app-list._active .w-app-list-item._active .w-app-list-item__shad { border-color: #c3e1e8; - box-shadow: 0 0 8px #00809c; + box-shadow: 0 0 8px 1px #00809c; } .w-app-list { diff --git a/app/launcher/widgets/button/button.js b/app/launcher/widgets/button/button.js index f7c068f..f5b1bea 100644 --- a/app/launcher/widgets/button/button.js +++ b/app/launcher/widgets/button/button.js @@ -4,6 +4,7 @@ goog.require('zb.ui.Button'); /** + * @deprecated as redundant * @inheritDoc * @extends {zb.ui.Button} * @constructor diff --git a/app/launcher/widgets/help-bar/help-bar-item-pagination.png b/app/launcher/widgets/help-bar/help-bar-item-pagination.png index bade7c8..403a22e 100644 Binary files a/app/launcher/widgets/help-bar/help-bar-item-pagination.png and b/app/launcher/widgets/help-bar/help-bar-item-pagination.png differ diff --git a/app/launcher/widgets/help-bar/help-bar-item-yellow.png b/app/launcher/widgets/help-bar/help-bar-item-yellow.png new file mode 100644 index 0000000..cd66ee5 Binary files /dev/null and b/app/launcher/widgets/help-bar/help-bar-item-yellow.png differ diff --git a/app/launcher/widgets/help-bar/help-bar.css b/app/launcher/widgets/help-bar/help-bar.css index 8e49424..2dc945d 100644 --- a/app/launcher/widgets/help-bar/help-bar.css +++ b/app/launcher/widgets/help-bar/help-bar.css @@ -3,35 +3,58 @@ .w-help-bar-item { background-repeat: no-repeat; - background-position: 0 50%; - line-height: 43px; + background-position: 4px 50%; + line-height: 30px; + border-radius: 5px; } + .w-help-bar-item._back { background-image: url(help-bar-item-back.png); - padding-left: 22px; + padding-left: 26px; + padding-right: 7px; +} + +.w-help-bar-item._pagination, +.w-help-bar-item._ok { + padding-left: 40px; + padding-right: 7px; } + .w-help-bar-item._pagination { background-image: url(help-bar-item-pagination.png); - padding-left: 24px; } + .w-help-bar-item._ok { background-image: url(help-bar-item-ok.png); - padding-left: 36px; } + +.w-help-bar-item._red, +.w-help-bar-item._green, +.w-help-bar-item._yellow, +.w-help-bar-item._blue { + padding-left: 43px; + padding-right: 7px; +} + .w-help-bar-item._red { background-image: url(help-bar-item-red.png); - padding-left: 39px; } + .w-help-bar-item._green { background-image: url(help-bar-item-green.png); - padding-left: 39px; } + +.w-help-bar-item._yellow { + background-image: url(help-bar-item-yellow.png); +} + .w-help-bar-item._blue { background-image: url(help-bar-item-blue.png); - padding-left: 39px; } + .w-help-bar-item._active { - color: #00809c; + background-color: #00809c; + color: #fff; } .w-help-bar { diff --git a/app/launcher/widgets/keyboard/keyboard.css b/app/launcher/widgets/keyboard/keyboard.css index c280436..4310c82 100644 --- a/app/launcher/widgets/keyboard/keyboard.css +++ b/app/launcher/widgets/keyboard/keyboard.css @@ -11,6 +11,26 @@ border: 2px solid #00809c; border-radius: 12px; } + +.w-keyboard-item._yellow, +.w-keyboard-item._red, +.w-keyboard-item._green { + color: #fff; + border-color: transparent; +} + +.w-keyboard-item._yellow { + background-color: #e5d202; +} + +.w-keyboard-item._red { + background-color: #d10b0b; +} + +.w-keyboard-item._green { + background-color: #0f8200; +} + .w-keyboard-item._service { width: 64px; height: 44px; @@ -28,18 +48,25 @@ border: 1px solid #00809c; border-radius: 10px; } + .w-keyboard-item._backspace, .w-keyboard-item._type { width: 70px; } + .w-keyboard-item._caps { background: url(keyboard-item-caps.png) 50% 50% no-repeat; } + .w-keyboard-item._active { background-color: #00809c; color: #fff; } +.w-keyboard-item._switch-keyboard { + font-size: 24px; +} + .w-keyboard {} .w-keyboard__line { text-align: center; diff --git a/app/launcher/widgets/keyboard/keyboard.js b/app/launcher/widgets/keyboard/keyboard.js index 4cc8d70..e8415b2 100644 --- a/app/launcher/widgets/keyboard/keyboard.js +++ b/app/launcher/widgets/keyboard/keyboard.js @@ -27,6 +27,34 @@ launcher.widgets.Keyboard.prototype._renderTemplate = function() { }; +/** + * @param {zb.device.input.Keys} zbKey + * @return {boolean} + */ +launcher.widgets.Keyboard.prototype.processShortcutKey = function(zbKey) { + var zbKeys = zb.device.input.Keys; + var zbCharKey = app.device.input.keyToPrintableChar(zbKey); + + switch (zbKey) { + case zbKeys.RED: + this._setSymbol('.'); + return true; + case zbKeys.GREEN: + this._setSymbol(':'); + return true; + case zbKeys.YELLOW: + this._setSymbol('/'); + return true; + default: + if (zbCharKey !== null) { + this._setSymbol(zbCharKey); + return true; + } + return false; + } +}; + + /** * @inheritDoc */ diff --git a/app/launcher/widgets/keyboard/keyboard.jst b/app/launcher/widgets/keyboard/keyboard.jst index f9f43fc..ff8cc53 100644 --- a/app/launcher/widgets/keyboard/keyboard.jst +++ b/app/launcher/widgets/keyboard/keyboard.jst @@ -4,16 +4,19 @@
- {{ "1 2 3 4 5 6 7 8 9 0 : .".split(" ").forEach(function(sym) { }} + {{ "1 2 3 4 5 6 7 8 9 0".split(" ").forEach(function(sym) { }}
{{=sym}}
{{ }); }} +
.
+
:
- {{ "? q w e r t y u i o p /".split(" ").forEach(function(sym) { }} + {{ "? q w e r t y u i o p".split(" ").forEach(function(sym) { }}
{{=sym}}
{{ }); }} +
/
@@ -22,7 +25,9 @@ {{ "a s d f g h j k l".split(" ").forEach(function(sym) { }}
{{=sym}}
{{ }); }} -
123
+
+ #%& +
@@ -47,7 +52,7 @@ {{ "- _ = + ~ , ; !".split(" ").forEach(function(sym) { }}
{{=sym}}
{{ }); }} -
ABC
+
ABC
<
diff --git a/app/launcher/widgets/notice/notice.js b/app/launcher/widgets/notice/notice.js index 132f000..e7d3f71 100644 --- a/app/launcher/widgets/notice/notice.js +++ b/app/launcher/widgets/notice/notice.js @@ -34,25 +34,40 @@ launcher.widgets.Notice.prototype.isFocusable = function() { /** */ launcher.widgets.Notice.prototype.showAdded = function() { - this.open(true); + this.open(launcher.widgets.Notice.State.ADDED); zb.html.text(this._container, 'URL added'); }; +/** + */ +launcher.widgets.Notice.prototype.showChanged = function() { + this.open(launcher.widgets.Notice.State.CHANGED); + zb.html.text(this._container, 'URL edited'); +}; + + /** */ launcher.widgets.Notice.prototype.showRemoved = function() { - this.open(false); + this.open(launcher.widgets.Notice.State.REMOVED); zb.html.text(this._container, 'URL removed'); }; /** - * @param {boolean} isAdded + * @param {launcher.widgets.Notice.State} state */ -launcher.widgets.Notice.prototype.open = function(isAdded) { - zb.html.updateClassName(this._container, launcher.widgets.Notice.State.ADDED, isAdded); - zb.html.updateClassName(this._container, launcher.widgets.Notice.State.REMOVED, !isAdded); +launcher.widgets.Notice.prototype.open = function(state) { + var allClasses = Object.keys(launcher.widgets.Notice.State) + .map(function(key) { + return launcher.widgets.Notice.State[key]; + }); + + allClasses.forEach(function(cssClass) { + zb.html.updateClassName(this._container, cssClass, cssClass === state); + }, this); + zb.html.show(this._container); this._timeout.restart(); }; @@ -77,5 +92,6 @@ launcher.widgets.Notice.prototype._timeout; */ launcher.widgets.Notice.State = { ADDED: '_add', - REMOVED: '_remove' + REMOVED: '_remove', + CHANGED: '_change' }; diff --git a/custom-platforms/dune/template/root/logo.png b/custom-platforms/dune/template/root/logo.png index 149d3e5..1b83b9d 100644 Binary files a/custom-platforms/dune/template/root/logo.png and b/custom-platforms/dune/template/root/logo.png differ diff --git a/custom-platforms/eltex/template/root/logo.png b/custom-platforms/eltex/template/root/logo.png index 2afa1ac..d72bb42 100755 Binary files a/custom-platforms/eltex/template/root/logo.png and b/custom-platforms/eltex/template/root/logo.png differ diff --git a/custom-platforms/eltex/template/root/logo_small.png b/custom-platforms/eltex/template/root/logo_small.png index e417394..59ee1d0 100755 Binary files a/custom-platforms/eltex/template/root/logo_small.png and b/custom-platforms/eltex/template/root/logo_small.png differ diff --git a/custom-platforms/samsung/icons/106x87.png b/custom-platforms/samsung/icons/106x87.png index 8dbe353..50e8d57 100644 Binary files a/custom-platforms/samsung/icons/106x87.png and b/custom-platforms/samsung/icons/106x87.png differ diff --git a/custom-platforms/samsung/icons/115x95.png b/custom-platforms/samsung/icons/115x95.png index 34a5f48..f793a42 100644 Binary files a/custom-platforms/samsung/icons/115x95.png and b/custom-platforms/samsung/icons/115x95.png differ diff --git a/custom-platforms/samsung/icons/85x70.png b/custom-platforms/samsung/icons/85x70.png index 9e09d9f..73792ce 100644 Binary files a/custom-platforms/samsung/icons/85x70.png and b/custom-platforms/samsung/icons/85x70.png differ diff --git a/custom-platforms/samsung/icons/95x78.png b/custom-platforms/samsung/icons/95x78.png index a573cc4..8a7763e 100644 Binary files a/custom-platforms/samsung/icons/95x78.png and b/custom-platforms/samsung/icons/95x78.png differ diff --git a/docs/eltex-eng.md b/docs/eltex-eng.md index 1f0e239..fa77dc8 100644 --- a/docs/eltex-eng.md +++ b/docs/eltex-eng.md @@ -1,9 +1,11 @@ Installation guide for Eltex STB -------------------------------- +### Eltex STB NV-10x + 1. Copy folder with application to USB flash drive. -2. Download libstbbrowser.so from http://download.eltex-media.ru/nv/nv300/plugins/libstbbrowser.so and copy it to folder with application. +2. Download libstbbrowser.so from http://download.eltex-media.ru/nv/nv102/plugins/libstbbrowser.so and copy it to folder with application. 3. Plug USB flash drive into STB. @@ -15,15 +17,47 @@ Installation guide for Eltex STB 5. Enter commands: - `mount -o remount,rw /sdk` + ``` + mount -o remount,rw /sdk + cd /sdk/qt-install-4.7.0/STBGUI_PLUGIN/ + cp -r /mnt/stb/local/$flash_drive/$path_to_appLauncher appLauncher + sync + reboot + ``` + + where - `cd /sdk/qt-install-4.7.0/STBGUI_PLUGIN/` + `$flash_drive` - flash drive's name in the system, - `cp -r /mnt/stb/local/$flash_drive/$path_to_appLauncher appLauncher` + `$path_to_appLauncher` - path to the distrib folder. - `sync` +6. Application will be available in the main menu. + +### Eltex STB NV-300 - `reboot` +1. Copy folder with application to USB flash drive. + +2. Download libstbbrowser.so from http://download.eltex-media.ru/nv/nv300/plugins/libstbbrowser.so and copy it to folder with application. + +3. Plug USB flash drive into STB. + +4. Connect to STB via SSH: + + **login:** root, + + **password:** is generated from STB serial number: + - Generator for Windows http://download.eltex-media.ru/nv/psswdgen/PSSWDGen_win.zip + - Generator for Linux http://download.eltex-media.ru/nv/psswdgen/PSSWDGen-linux-x86_64 + +5. Enter commands: + + ``` + mount -o remount,rw /sdk + cd /usr/local/bin/stbgui/ + cp -r /mnt/stb/local/$flash_drive/$path_to_appLauncher appLauncher + sync + reboot + ``` where @@ -31,4 +65,4 @@ Installation guide for Eltex STB `$path_to_appLauncher` - path to the distrib folder. -6. Application will be available in the main menu. +6. Application will be available in the main menu. \ No newline at end of file diff --git a/docs/eltex-rus.md b/docs/eltex-rus.md index 9c42a83..a175743 100644 --- a/docs/eltex-rus.md +++ b/docs/eltex-rus.md @@ -1,9 +1,11 @@ Руководство по установке приложений на Eltex STB -------------------------------- +### Eltex STB NV-10x + 1. Скопировать папку с приложением на USB флэш диск. -2. Скачать libstbbrowser.so с http://download.eltex-media.ru/nv/nv300/plugins/libstbbrowser.so и скопировать его в папку с приложением. +2. Скачать libstbbrowser.so с http://download.eltex-media.ru/nv/nv102/plugins/libstbbrowser.so и скопировать его в папку с приложением. 3. Вставить USB флэш диск в приставку. @@ -15,15 +17,47 @@ 5. Ввести команды: - `mount -o remount,rw /sdk` + ``` + mount -o remount,rw /sdk + cd /sdk/qt-install-4.7.0/STBGUI_PLUGIN/ + cp -r /mnt/stb/local/$flash_drive/$path_to_appLauncher appLauncher + sync + reboot + ``` + + где + + `$flash_drive` - наименование флэш диска в системе, + + `$path_to_appLauncher` - путь до папки с приложением. + +6. Приложение станет доступным в главном меню. + +### Eltex STB NV-300 + +1. Скопировать папку с приложением на USB флэш диск. + +2. Скачать libstbbrowser.so с http://download.eltex-media.ru/nv/nv300/plugins/libstbbrowser.so и скопировать его в папку с приложением. + +3. Вставить USB флэш диск в приставку. - `cd /sdk/qt-install-4.7.0/STBGUI_PLUGIN/` +4. Присоединиться к приставке через SSH: - `cp -r /mnt/stb/local/$flash_drive/$path_to_appLauncher appLauncher` + **login:** root, - `sync` + **password:** генерируется на основе серийного номера приставки: + - генератор паролей под Windows http://download.eltex-media.ru/nv/psswdgen/PSSWDGen_win.zip + - генератор паролей под Linux http://download.eltex-media.ru/nv/psswdgen/PSSWDGen-linux-x86_64 + +5. Ввести команды: - `reboot` + ``` + mount -o remount,rw /sdk + cd /usr/local/bin/stbgui/ + cp -r /mnt/stb/local/$flash_drive/$path_to_appLauncher appLauncher + sync + reboot + ``` где diff --git a/docs/lg-netcast-eng.md b/docs/lg-netcast-eng.md index 1f616cd..7a31382 100644 --- a/docs/lg-netcast-eng.md +++ b/docs/lg-netcast-eng.md @@ -5,16 +5,43 @@ Installation guide for LG NetCast Smart TV ### 2012 -1. Plug Ethernet cable to connect your TV to Internet. +- Login -2. Unzip your application zip archive to folder `lgapps\installed` of USB flash drive. + 1. Plug Ethernet cable to connect your TV to Internet. + + 2. Press **HOME** home remote button. + + 3. Select icon with man silhouette in the right top corner. -3. Plug flash drive into TV. + 4. (if you don't have account) Press **red** remote button. -4. Press **MY APPS** remote button, press **OK** remote button. + 5. (if you don't have account) Select two times **Agree**. -5. OR press **HOME** remote button, select **My Apps**, press **OK** remote button. + 6. (if you don't have account) Enter **E-mail**, **Password**. -6. Select USB icon in the top-right corner near free space counter. + 7. (if you don't have account) Select **Check validity**. -7. Select your application. + 8. (if you don't have account) Select **OK**. + + 9. (if you don't have account) Check e-mail which you entered as ID and + confirm registration. + + + 10. Enter **ID or e-mail** and **Password** and select **Sign In**. + +- Launch on TV + + 1. Unzip your application zip archive to folder `lgapps\installed` of NTFS formatted USB flash drive. + + 2. Plug flash drive into TV into USB connector marked **USB Apps**. + + 3. Press **MY APPS** remote button, press **OK** remote button. + + 4. OR press **HOME** remote button, select **My Apps**, press **OK** remote button. + + 5. Select USB icon in the top-right corner near free space counter. + + 6. Select your application. + + +**Note:** USB flash drive must be formatted into NTFS. \ No newline at end of file diff --git a/docs/lg-netcast-rus.md b/docs/lg-netcast-rus.md index a6b2eb9..24b356d 100644 --- a/docs/lg-netcast-rus.md +++ b/docs/lg-netcast-rus.md @@ -5,16 +5,43 @@ ### 2012 -1. Вставить сетевой кабель в телевизор, чтобы подключить его к Интернет. +- Вход в систему -2. Распаковать zip архив с приложением в папку `lgapps\installed` USB флэш диска. + 1. Вставить сетевой кабель в телевизор, чтобы подключить его к Интернет. + + 2. Нажать на пульте кнопку **HOME**. + + 3. Выбрать иконку с человечком в правом верхнем углу экрана. -3. Вставить USB флэш диск в телевизор. + 4. (если у вас нет аккаунта) Нажать на пульте **Красную кнопку**. -4. Нажать на пульте кнопку **MY APPS**, нажать на пульте кнопку **OK**. + 5. (если у вас нет аккаунта) Выбрать **Согласен** два раза. -5. ИЛИ нажать на пульте кнопку **HOME**, выбрать **Мои приложения**, нажать на пульте кнопку **OK**. + 6. (если у вас нет аккаунта) Ввести **E-mail**, **Пароль**. -6. Выбрать иконку USB в правой верхней части экрана рядом с указателем свободного места. + 7. (если у вас нет аккаунта) Выбрать **Проверка подлинности**. -7. Выбрать установленное приложение. + 8. (если у вас нет аккаунта) Выбрать **OK**. + + 9. (если у вас нет аккаунта) Проверить электронную почту, которую вы ввели + в качестве идентфикатора, и подтвердить регистрацию. + + 10. Ввести **ID или e-mail** и **Пароль** и выбрать **Войти**. + + +- Запуск на телевизоре + + 2. Распаковать zip архив с приложением в папку `lgapps\installed` USB флэш диска, отформатированного под NTFS. + + 3. Вставить USB флэш диск в телевизор в разъем, подписанный **USB Apps**. + + 4. Нажать на пульте кнопку **MY APPS**, нажать на пульте кнопку **OK**. + + 5. ИЛИ нажать на пульте кнопку **HOME**, выбрать **Мои приложения**, нажать на пульте кнопку **OK**. + + 6. Выбрать иконку USB в правой верхней части экрана рядом с указателем свободного места. + + 7. Выбрать установленное приложение. + + +**Примечание:** USB флэш диск должен быть отформатирован под NTFS. diff --git a/docs/lg-webos-eng.md b/docs/lg-webos-eng.md index 785ada2..257693a 100644 --- a/docs/lg-webos-eng.md +++ b/docs/lg-webos-eng.md @@ -31,7 +31,7 @@ Installation guide for LG webOS SmartTV - Launch on TV 1. Unzip your application zip archive to folder - `developer\apps\usr\palm\applications\` of USB flash drive + `developer\apps\usr\palm\applications\` of NTFS formatted USB flash drive. 2. Plug flash drive into TV. diff --git a/docs/lg-webos-rus.md b/docs/lg-webos-rus.md index b6bf622..2ede28e 100644 --- a/docs/lg-webos-rus.md +++ b/docs/lg-webos-rus.md @@ -23,7 +23,7 @@ 7. (если у вас нет аккаунта) Выбрать **OK**. 8. (если у вас нет аккаунта) Проверить электронную почту, которую вы ввели - в качестве идентфикатора, и подтвердить регистрацию. + в качестве идентификатора, и подтвердить регистрацию. 9. (если у вас нет аккаунта) Выбрать **ВОЙТИ**. @@ -34,7 +34,7 @@ - Запуск на телевизоре 1. Распаковать zip архив с приложением в папку - `developer\apps\usr\palm\applications\` USB флэш диска + `developer\apps\usr\palm\applications\` USB флэш диска, отформатированного под NTFS. 2. Вставить USB флэш диск в телевизор. diff --git a/package.json b/package.json index cfe42ed..984d59a 100644 --- a/package.json +++ b/package.json @@ -1,52 +1,57 @@ { "name": "appLauncher", - "version": "0.1.0", + "version": "0.2.0", "description": "AppLauncher allows running Smart TV and STB application avoiding standard installation process.", "homepage": "https://github.com/ifaced/app-launcher", - "repository" : { - "type" : "git", - "url" : "https://github.com/ifaced/app-launcher.git" + "repository": { + "type": "git", + "url": "https://github.com/ifaced/app-launcher.git" }, "contributors": [ { - "name" : "Andrew Motoshin", - "email" : "andrew@htmlhero.ru", - "url" : "http://htmlhero.ru/" + "name": "Andrew Motoshin", + "email": "andrew@htmlhero.ru", + "url": "http://htmlhero.ru/" }, { - "name" : "Oleg Akinin", - "email" : "o.akinin@ifaced.ru" + "name": "Oleg Akinin", + "email": "o.akinin@ifaced.ru" }, { - "name" : "Vyatcheslav Zaytcev", - "email" : "slava@ifaced.ru" + "name": "Vyatcheslav Zaytcev", + "email": "slava@ifaced.ru" }, { - "name" : "Anuar Turenov", - "email" : "turenov@ifaced.ru" + "name": "Anuar Turenov", + "email": "turenov@ifaced.ru" }, { - "name" : "Maxim Dymchenko", - "email" : "maximatorrus@ifaced.ru" + "name": "Maxim Dymchenko", + "email": "maximatorrus@ifaced.ru" }, { - "name" : "Kirill Dronkin", - "email" : "kirilldronkin@ifaced.ru" + "name": "Kirill Dronkin", + "email": "kirilldronkin@ifaced.ru" }, { - "name" : "Alex Babenko", - "email" : "babenkoalex@ifaced.ru" + "name": "Dmitry Zubarev", + "email": "zubrolet@interfaced.ru" + }, + { + "name": "Alex Babenko", + "email": "babenkoalex@ifaced.ru" } ], "license": "Apache-2.0", "dependencies": { - "zombiebox": "0.0.176", - "zombiebox-platform-dune": "0.0.41", - "zombiebox-platform-eltex": "0.0.22", - "zombiebox-platform-lg": "0.0.11", - "zombiebox-platform-mag250": "0.0.26", - "zombiebox-platform-samsung": "0.0.26", - "zombiebox-platform-tvip": "0.0.10", - "zombiebox-platform-webos": "0.0.10" + "zombiebox": "0.0.193", + "zombiebox-extension-ui": "^0.1.2", + "zombiebox-platform-dune": "0.0.44", + "zombiebox-platform-eltex": "0.0.26", + "zombiebox-platform-lg": "0.0.14", + "zombiebox-platform-mag250": "0.0.35", + "zombiebox-platform-samsung": "0.0.40", + "zombiebox-platform-tvip": "0.0.12", + "zombiebox-platform-webos": "0.0.11" } } diff --git a/web/analytics.js b/web/analytics.js new file mode 100644 index 0000000..818acbc --- /dev/null +++ b/web/analytics.js @@ -0,0 +1,38 @@ +(function(){var aa=encodeURIComponent,f=window,ba=setTimeout,n=Math,ea=RegExp;function fa(a,b){return a.name=b}function Pc(a,b){return a.href=b} +var p="push",h="hash",ha="slice",Qc="replace",q="data",r="cookie",t="indexOf",m="match",ia="defaultValue",ja="port",u="createElement",id="setAttribute",v="name",da="getTime",x="host",y="length",z="prototype",la="clientWidth",A="split",B="location",ma="hostname",ga="search",jd="target",C="call",E="protocol",na="clientHeight",Ab="href",F="substring",kd="action",G="apply",oa="navigator",Ub="parentNode",H="join",I="toLowerCase";var pa=new function(){var a=[];this.set=function(b){a[b]=!0};this.M=function(){for(var b=[],c=0;c=a[y])wc(a,b);else if(8192>=a[y]){var c=b;if(0<=O[oa].userAgent[t]("Firefox")&&![].reduce)throw new Ea(a[y]);xc(a,c)||Fa(a,c)}else throw new Da(a[y]);},wc=function(a,b){var c=Ca(oc()+"/collect?"+a);c.onload=c.onerror=function(){c.onload=null;c.onerror=null;b()}}, +xc=function(a,b){var c,d=O.XDomainRequest;if(d)c=new d,c.open("POST",oc()+"/collect");else if(d=O.XMLHttpRequest)d=new d,"withCredentials"in d&&(c=d,c.open("POST",oc()+"/collect",!0),c.setRequestHeader("Content-Type","text/plain"));if(c)return c.onreadystatechange=function(){4==c.readyState&&(b(),c=null)},c.send(a),!0},Fa=function(a,b){if(M.body){a=aa(a);try{var c=M[u]('')}catch(d){c=M[u]("iframe"),fa(c,a)}c.height="0";c.width="0";c.style.display="none";c.style.visibility= +"hidden";var e=M[B],e=oc()+"/analytics_iframe.html#"+aa(e[E]+"//"+e[x]+"/favicon.ico"),g=function(){c.src="";c[Ub]&&c[Ub].removeChild(c)};ta(O,"beforeunload",g);var ca=!1,l=0,k=function(){if(!ca){try{if(9=100*R(a,Ka))throw"abort";}function Ma(a){if(xa(P(a,Na)))throw"abort";}function Oa(){var a=M[B][E];} +function Pa(a){a.set(Ac,R(a,Ac)+1);var b=[];Qa.map(function(c,d){if(d.p){var e=a.get(c);void 0!=e&&e!=d[ia]&&("boolean"==typeof e&&(e*=1),b[p](d.p+"="+sa(""+e)))}});b[p]("z="+ra());a.set(Ra,b[H]("&"),!0)}function Sa(a){Ga(P(a,Ra),a.get(Ia));a.set(Ia,L,!0)}function Hc(a){var b=O.gaData;b&&(b.expId&&a.set(Nc,b.expId),b.expVar&&a.set(Oc,b.expVar))}function cd(){if(O[oa]&&"preview"==O[oa].loadPurpose)throw"abort";};function Ta(a){var b=R(a,Ua);500<=b&&J(15);var c=P(a,Va);if("transaction"!=c&&"item"!=c){var c=R(a,Wa),d=(new Date)[da](),e=R(a,Xa);0==e&&a.set(Xa,d);e=n.round(2*(d-e)/1E3);0=c)throw"abort";a.set(Wa,--c)}a.set(Ua,++b)};var Ya=function(){this.data=new N},Qa=new N,Za=[];Ya[z].get=function(a){var b=$a(a),c=this[q].get(a);b&&void 0==c&&(c=K(b[ia])?b[ia]():b[ia]);return b&&b.n?b.n(this,a,c):c};var P=function(a,b){var c=a.get(b);return void 0==c?"":""+c},R=function(a,b){var c=a.get(b);return void 0==c||""===c?0:1*c};Ya[z].set=function(a,b,c){if(a)if("object"==typeof a)for(var d in a)a.hasOwnProperty(d)&&ab(this,d,a[d],c);else ab(this,a,b,c)}; +var ab=function(a,b,c,d){var e=$a(b);e&&e.o?e.o(a,b,c,d):a[q].set(b,c,d)},bb=function(a,b,c,d,e){fa(this,a);this.p=b;this.n=d;this.o=e;this.defaultValue=c},$a=function(a){var b=Qa.get(a);if(!b)for(var c=0;c=c)&&(c={},Ec(c)||Fc(c))){var d=c[Eb];void 0==d||Infinity==d||isNaN(d)||(0c)a[b]=void 0};var hc=!1,mc=function(a){if("cookie"==P(a,ac)){var b=P(a,U),c=nd(a),d=kc(P(a,Yb)),e=lc(P(a,W)),g=1E3*R(a,Zb),ca=P(a,Na);if("auto"!=e)zc(b,c,d,e,ca,g)&&(hc=!0);else{J(32);var l;t:{c=[];e=eb()[A](".");if(4==e[y]&&(l=e[e[y]-1],parseInt(l,10)==l)){l=["none"];break t}for(l=e[y]-2;0<=l;l--)c[p](e[ha](l)[H]("."));c[p]("none");l=c}for(var k=0;k=a&&d[p]({hash:ca[0],R:e[g],O:ca})}return 0==d[y]?void 0:1==d[y]?d[0]:Zc(b,d)||Zc(c,d)||Zc(null,d)||d[0]}function Zc(a,b){var c,d;null==a?c=d=1:(c=La(a),d=La(0==a[t](".")?a[F](1):"."+a));for(var e=0;ed[y])){c=[];for(var e=0;e=ca[0]||0>=ca[1]?"":ca[H]("x");a.set(rb,c);a.set(tb,fc());a.set(ob,M.characterSet||M.charset);a.set(sb,b&&"function"===typeof b.javaEnabled&&b.javaEnabled()||!1);a.set(nb,(b&&(b.language||b.browserLanguage)||"")[I]());if(d&&a.get(cc)&&(b=M[B][h])){b=b[F](1);b=b[A]("&");d=[];for(c=0;carguments[y])){var b,c;"string"===typeof arguments[0]?(b=arguments[0],c=[][ha][C](arguments,1)):(b=arguments[0]&&arguments[0][Va],c=arguments);b&&(c=wa(qc[b]||[],c),c[Va]=b,this.b.set(c,void 0,!0),this.filters.D(this.b),"pageview"==b&&Lc(this),this.b[q].m={})}};var Lc=function(a){a.I||(a.I=!0,gc(a.b,function(b){a.send("timing",b)}))};var rc=function(a){if("prerender"==M.webkitVisibilityState)return!1;a();return!0},Mc=function(a){if(!rc(a)){J(16);var b=!1,c=function(){!b&&rc(a)&&(b=!0,ua(M,"webkitvisibilitychange",c))};ta(M,"webkitvisibilitychange",c)}};var td=/^(?:(\w+)\.)?(?:(\w+):)?(\w+)$/,sc=function(a){if(K(a[0]))this.u=a[0];else{var b=td.exec(a[0]);null!=b&&4==b[y]&&(this.c=b[1]||"t0",this.e=b[2]||"",this.d=b[3],this.a=[][ha][C](a,1),this.e||(this.A="create"==this.d,this.i="require"==this.d,this.g="provide"==this.d));b=a[1];a=a[2];if(!this.d)throw"abort";if(this.i&&(!qa(b)||""==b))throw"abort";if(this.g&&(!qa(b)||""==b||!K(a)))throw"abort";if(ud(this.c)||ud(this.e))throw"abort";if(this.g&&"t0"!=this.c)throw"abort";}}; +function ud(a){return 0<=a[t](".")||0<=a[t](":")};var Z={F:"/plugins/ua/"};Z.k=new N;Z.f=[];Z.B=function(a,b,c){var d=Z.k.get(a);if(!K(d))return!1;b.plugins_=b.plugins_||new N;b.plugins_.set(a,new d(b,c||{}));return!0};Z.C=function(a,b){Z.k.set(a,b)};Z.D=function(a){var b=Z.J[G](Z,arguments),b=Z.f.concat(b);for(Z.f=[];0a[A]("/")[0][t](":")&&(a=ca+e[2][F](0,e[2].lastIndexOf("/"))+"/"+a):a=ca+e[2]+(a||g);Pc(c,a);d=b(c);return{protocol:(c[E]||"")[I](),host:d[0],port:d[1], +path:d[2],G:c[ga]||"",url:a||""}};var $=function(a){J(1);Z.D[G](Z,[arguments])};$.h={};$.P=[];$.L=0;$.answer=42;var uc=[Na,W,V];$.create=function(a){var b=wa(uc,[][ha][C](arguments));b[V]||(b[V]="t0");var c=""+b[V];if($.h[c])return $.h[c];b=new pc(b);$.h[c]=b;$.P[p](b);return b};$.j=function(a){return $.h[a]};$.K=function(){return $.P[ha](0)};$.N=function(){var a=O[gb];if(!a||42!=a.answer){$.L=a&&a.l;$.loaded=!0;O[gb]=$;Cc();var b=a&&a.q;"[object Array]"==Object[z].toString[C](Object(b))&&Mc(function(){Z.D[G]($,b)})}};$.N();function La(a){var b=1,c=0,d;if(a)for(b=0,d=a[y]-1;0<=d;d--)c=a.charCodeAt(d),b=(b<<6&268435455)+c+(c<<14),c=b&266338304,b=0!=c?b^c>>21:b;return b};})(window); \ No newline at end of file