diff --git a/accelerator-home-ui/settings.json b/accelerator-home-ui/settings.json index a45e751..5ee2e54 100644 --- a/accelerator-home-ui/settings.json +++ b/accelerator-home-ui/settings.json @@ -13,6 +13,6 @@ "log": true, "enableAppSuspended": true, "showVersion": false, - "version": "6.0.12" + "version": "6.0.13" } } diff --git a/accelerator-home-ui/src/api/AppCatalog.js b/accelerator-home-ui/src/api/AppCatalog.js index 0a65a5d..b7380df 100644 --- a/accelerator-home-ui/src/api/AppCatalog.js +++ b/accelerator-home-ui/src/api/AppCatalog.js @@ -420,6 +420,10 @@ export async function login(user, pass) { try { const loginResponse = await handler.login(user, pass); + if (!loginResponse || typeof loginResponse.expiresIn !== 'number') { + console.warn('Login failed: invalid response from server', loginResponse); + return false; + } appCatalogHandler = handler; handler.scheduleRefresh(loginResponse, () => handleAuthExpired(handler)); eventTarget.dispatchEvent(new RefreshNeeded()); @@ -447,3 +451,7 @@ export async function makeDownloadURL(url) { const handler = appCatalogHandler; return callAndHandleAuthExpired(handler, () => handler.makeDownloadURL(url)); } + +export async function getCatalogServerURL() { + return getServerURL(); +} diff --git a/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js b/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js index 1c6c630..98a991b 100644 --- a/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js +++ b/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js @@ -16,12 +16,12 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -import { Language, Lightning, Router } from '@lightningjs/sdk' +import { Language, Lightning, Router, Utils } from '@lightningjs/sdk' import { CONFIG } from '../Config/Config'; import { Keyboard } from '../ui-components/index' import { KEYBOARD_FORMATS } from '../ui-components/components/Keyboard' import PasswordSwitch from './PasswordSwitch'; -import { login } from '../api/AppCatalog'; +import { login, getCatalogServerURL } from '../api/AppCatalog'; export default class AppCatalogLoginComponent extends Lightning.Component { @@ -40,31 +40,49 @@ export default class AppCatalogLoginComponent extends Lightning.Component { _active() { this.hidePasswd = true this.star = "" + this.catalogURL = null + this.catalogURLState = 'loading' + this.tag('CatalogURLValue').text.text = Language.translate('Loading...') this.tag("Keyboard").visible = false + getCatalogServerURL() + .then(url => { + this.catalogURL = url || null + this.catalogURLState = url ? 'loaded' : 'not-set' + this.tag('CatalogURLValue').text.text = url || Language.translate('Unknown') + }) + .catch(() => { + this.catalogURL = null + this.catalogURLState = 'error' + this.tag('CatalogURLValue').text.text = Language.translate('Unavailable') + }) + } + + _firstEnable() { + this.spinnerAnimation = this.tag('LoadingOverlay.Spinner').animation({ + duration: 3, + repeat: -1, + stopMethod: 'immediate', + stopDelay: 0.2, + actions: [{ p: 'rotation', v: { sm: 0, 0: 0, 1: Math.PI * 2 } }], + }) + } + + _updateConnectButtonColor() { + if (this.textCollection && this.textCollection['EnterUsername'] && this.textCollection['EnterPassword']) { + this.tag('ConnectButton').color = 0xff00aa00 + } else { + this.tag('ConnectButton').color = 0xff444444 + } } handleDone() { this.tag("Keyboard").visible = false if (!this.textCollection['EnterUsername']) { this._setState("EnterUsername"); - } - else if (!this.textCollection['EnterPassword']) { + } else if (!this.textCollection['EnterPassword']) { this._setState("EnterPassword"); - } - else { - this.LOG('App Catalog Login - credentials submitted') - login(this.textCollection['EnterUsername'], this.textCollection['EnterPassword']) - .then(result => { - if (result) { - this.LOG('Login successful - navigating back') - if (!Router.isNavigating()) { - Router.back() - } - } else { - this.ERR('Login failed') - } - }) - .catch(err => this.ERR('Login error: ' + err)) + } else { + this._setState("ConnectButton"); } } @@ -89,9 +107,32 @@ export default class AppCatalogLoginComponent extends Lightning.Component { BorderTop: { x: 190, y: 130, w: 1488, h: 2, rect: true, }, + CatalogURLLabel: { + x: 190, + y: 148, + text: { + text: Language.translate("App Catalog URL") + ": ", + fontFace: CONFIG.language.font, + fontSize: 22, + textColor: 0xff808080, + }, + }, + CatalogURLValue: { + x: 525, + y: 148, + text: { + text: Language.translate("Loading..."), + fontFace: CONFIG.language.font, + fontSize: 22, + textColor: 0xff808080, + wordWrapWidth: 1200, + wordWrap: false, + textOverflow: 'ellipsis', + }, + }, Username: { x: 190, - y: 170, + y: 230, text: { text: Language.translate("Username") + ": ", fontFace: CONFIG.language.font, @@ -100,12 +141,12 @@ export default class AppCatalogLoginComponent extends Lightning.Component { }, UsernameBox: { x: 425, - y: 160, + y: 220, texture: Lightning.Tools.getRoundRect(1248, 58, 0, 3, 0xffffffff, false) }, UsernameText: { x: 445, - y: 170, + y: 230, zIndex: 2, text: { text: '', @@ -119,7 +160,7 @@ export default class AppCatalogLoginComponent extends Lightning.Component { }, Password: { x: 190, - y: 240, + y: 300, text: { text: Language.translate("Password") + ":", fontFace: CONFIG.language.font, @@ -128,12 +169,12 @@ export default class AppCatalogLoginComponent extends Lightning.Component { }, PasswordBox: { x: 425, - y: 230, + y: 290, texture: Lightning.Tools.getRoundRect(1248, 58, 0, 3, 0xffffffff, false) }, Pwd: { x: 445, - y: 240, + y: 300, zIndex: 2, text: { text: '', @@ -146,11 +187,11 @@ export default class AppCatalogLoginComponent extends Lightning.Component { }, }, BorderBottom: { - x: 190, y: 326, w: 1488, h: 2, rect: true, + x: 190, y: 386, w: 1488, h: 2, rect: true, }, ExitButton: { - x: 960, - y: 350, + x: 740, + y: 410, mountX: 0.5, w: 200, h: 50, @@ -169,9 +210,30 @@ export default class AppCatalogLoginComponent extends Lightning.Component { }, }, }, + ConnectButton: { + x: 1180, + y: 410, + mountX: 0.5, + w: 200, + h: 50, + rect: true, + color: 0xff444444, + shader: { type: Lightning.shaders.RoundedRectangle, radius: 10 }, + ConnectLabel: { + x: 100, + y: 25, + mount: 0.5, + text: { + text: Language.translate('Connect'), + fontFace: CONFIG.language.font, + fontSize: 22, + textColor: 0xffffffff, + }, + }, + }, Keyboard: { - y: 420, - x: 425, + y: 480, + x: 400, type: Keyboard, visible: false, zIndex: 2, @@ -180,22 +242,145 @@ export default class AppCatalogLoginComponent extends Lightning.Component { PasswrdSwitch: { h: 45, w: 66.9, - x: 1642, - y: 260, + x: 1617, + y: 320, zIndex: 2, type: PasswordSwitch, mount: 0.5, visible: true }, ShowPassword: { - x: 1365, - y: 242, + x: 1350, + y: 302, w: 300, h: 75, zIndex: 2, text: { text: Language.translate('Show Password'), fontSize: 25, fontFace: CONFIG.language.font, textColor: 0xffffffff, textAlign: 'left' }, visible: true - } + }, + AuthFailedPopup: { + x: 960, + y: 540, + mount: 0.5, + w: 560, + h: 200, + rect: true, + color: 0xff222222, + shader: { type: Lightning.shaders.RoundedRectangle, radius: 12 }, + visible: false, + zIndex: 11, + PopupText: { + x: 280, + y: 60, + mountX: 0.5, + text: { + text: Language.translate('Authentication failed. Please try again.'), + fontFace: CONFIG.language.font, + fontSize: 26, + textColor: 0xffffffff, + textAlign: 'center', + wordWrapWidth: 500, + wordWrap: true, + }, + }, + OkButton: { + x: 280, + y: 145, + mountX: 0.5, + mountY: 0.5, + w: 150, + h: 46, + rect: true, + color: 0xff444444, + shader: { type: Lightning.shaders.RoundedRectangle, radius: 10 }, + OkLabel: { + x: 75, + y: 23, + mount: 0.5, + text: { + text: Language.translate('OK'), + fontFace: CONFIG.language.font, + fontSize: 22, + textColor: 0xffffffff, + }, + }, + }, + }, + URLNotSetPopup: { + x: 960, + y: 540, + mount: 0.5, + w: 560, + h: 200, + rect: true, + color: 0xff222222, + shader: { type: Lightning.shaders.RoundedRectangle, radius: 12 }, + visible: false, + zIndex: 11, + PopupText: { + x: 280, + y: 60, + mountX: 0.5, + text: { + text: Language.translate('App Catalog URL is not set'), + fontFace: CONFIG.language.font, + fontSize: 26, + textColor: 0xffffffff, + textAlign: 'center', + wordWrapWidth: 500, + wordWrap: true, + }, + }, + OkButton: { + x: 280, + y: 145, + mountX: 0.5, + mountY: 0.5, + w: 150, + h: 46, + rect: true, + color: 0xff444444, + shader: { type: Lightning.shaders.RoundedRectangle, radius: 10 }, + OkLabel: { + x: 75, + y: 23, + mount: 0.5, + text: { + text: Language.translate('OK'), + fontFace: CONFIG.language.font, + fontSize: 22, + textColor: 0xffffffff, + }, + }, + }, + }, + LoadingOverlay: { + w: 1920, + h: 1080, + rect: true, + color: 0xCC000000, + visible: false, + zIndex: 10, + Spinner: { + x: 920, + y: 490, + w: 80, + h: 80, + mount: 0.5, + src: Utils.asset('images/settings/Loading.png'), + }, + AuthText: { + x: 960, + y: 550, + mountX: 0.5, + text: { + text: Language.translate('Authenticating...'), + fontFace: CONFIG.language.font, + fontSize: 28, + textColor: 0xffffffff, + }, + }, + }, } } @@ -206,6 +391,7 @@ export default class AppCatalogLoginComponent extends Lightning.Component { this.tag("UsernameText").text.text = Language.translate("Press OK to enter Username"); this.tag('UsernameText').text.textColor = 0xff808080 this.tag('Pwd').text.textColor = 0xff808080 + this._updateConnectButtonColor() } encrypt() { @@ -315,12 +501,130 @@ export default class AppCatalogLoginComponent extends Lightning.Component { _handleDown() { this._setState('EnterUsername') } + _handleRight() { + this._setState('ConnectButton') + } _handleEnter() { if (!Router.isNavigating()) { Router.back() } } }, + class ConnectButton extends this { + $enter() { + this.tag('ConnectButton').color = (this.textCollection['EnterUsername'] && this.textCollection['EnterPassword']) + ? 0xff00cc00 + : 0xff444444 + } + $exit() { + this._updateConnectButtonColor() + } + _handleUp() { + this._setState('EnterPassword') + } + _handleDown() { + this._setState('EnterUsername') + } + _handleLeft() { + this._setState('ExitButton') + } + _handleEnter() { + this.tag('Keyboard').visible = false + if (this.catalogURLState === 'loading') { + this.LOG('Catalog URL still loading, please wait...') + return + } + if (this.catalogURLState === 'error' || this.catalogURLState === 'not-set' || !this.catalogURL) { + this._setState('URLNotSetPopup') + return + } + if (!this.textCollection['EnterUsername']) { + this._setState('EnterUsername') + return + } + if (!this.textCollection['EnterPassword']) { + this._setState('EnterPassword') + return + } + this._setState('Authenticating') + login(this.textCollection['EnterUsername'], this.textCollection['EnterPassword']) + .then(result => { + if (result) { + this.LOG('Login successful - navigating to menu') + if (!Router.isNavigating()) { + Router.navigate('menu') + } + } else { + this.ERR('Login failed') + setTimeout(() => this._setState('AuthFailedPopup'), 0) + } + }) + .catch(err => { + this.ERR('Login error: ' + err) + setTimeout(() => this._setState('AuthFailedPopup'), 0) + }) + } + }, + class AuthFailedPopup extends this { + $enter() { + this.tag('AuthFailedPopup').visible = true + this.tag('AuthFailedPopup.OkButton').color = CONFIG.theme.hex + } + $exit() { + this.tag('AuthFailedPopup').visible = false + this.tag('AuthFailedPopup.OkButton').color = 0xff444444 + } + _handleEnter() { + this._setState('ConnectButton') + } + _handleBack() { + this._setState('ConnectButton') + } + _handleUp() {} + _handleDown() {} + _handleLeft() {} + _handleRight() {} + }, + class URLNotSetPopup extends this { + $enter() { + this.tag('URLNotSetPopup').visible = true + this.tag('URLNotSetPopup.OkButton').color = CONFIG.theme.hex + const msg = this.catalogURLState === 'error' + ? Language.translate('Unable to retrieve App Catalog URL') + : Language.translate('App Catalog URL is not set') + this.tag('URLNotSetPopup.PopupText').text.text = msg + } + $exit() { + this.tag('URLNotSetPopup').visible = false + this.tag('URLNotSetPopup.OkButton').color = 0xff444444 + } + _handleEnter() { + this._setState('ConnectButton') + } + _handleBack() { + this._setState('ConnectButton') + } + _handleUp() {} + _handleDown() {} + _handleLeft() {} + _handleRight() {} + }, + class Authenticating extends this { + $enter() { + this.tag('LoadingOverlay').visible = true + this.spinnerAnimation.start() + } + $exit() { + this.spinnerAnimation.stop() + this.tag('LoadingOverlay').visible = false + } + _handleEnter() {} + _handleBack() {} + _handleUp() {} + _handleDown() {} + _handleLeft() {} + _handleRight() {} + }, class Keyboard extends this { $enter(state) { this.prevState = state.prevState @@ -361,6 +665,7 @@ export default class AppCatalogLoginComponent extends Lightning.Component { this.star += (this.prevState === "EnterPassword") ? '\u25CF' : '' this.tag(this.element).text.text = this.encrypt() ? this.star : this.textCollection[this.prevState]; } + this._updateConnectButtonColor() } _handleUp() { this._setState(this.prevState) @@ -378,5 +683,6 @@ export default class AppCatalogLoginComponent extends Lightning.Component { this.textCollection = { 'EnterUsername': '', 'EnterPassword': '' } this.tag("Pwd").text.text = this.textCollection['EnterPassword'] this.tag("UsernameText").text.text = this.textCollection['EnterUsername'] + this.tag('ConnectButton').color = 0xff444444 } } diff --git a/accelerator-home-ui/static/language/translations/en.json b/accelerator-home-ui/static/language/translations/en.json index 427ed25..aa9dbd9 100644 --- a/accelerator-home-ui/static/language/translations/en.json +++ b/accelerator-home-ui/static/language/translations/en.json @@ -1,6 +1,7 @@ { "en" : "English", "es": "Spanish", + "OK": "OK", "home": "Home", "click to launch": "click to launch", "wifi": "WiFi Settings", @@ -123,5 +124,16 @@ "INVALID_CREDENTIALS - The connection failed due to invalid credentials":"", "NO_SSID - The SSID does not exist":"", "UNKNOWN - Any other error":"", - "Configuring as default":"Configuring as default" + "Configuring as default":"Configuring as default", + "Loading...":"Loading...", + "Authenticating...":"Authenticating...", + "Unknown":"Unknown", + "Unavailable":"Unavailable", + "App Catalog URL is not set":"App Catalog URL is not set", + "Unable to retrieve App Catalog URL":"Unable to retrieve App Catalog URL", + "Authentication failed. Please try again.":"Authentication failed. Please try again.", + "Connect to the Application Catalog":"Connect to the Application Catalog", + "App Catalog URL":"App Catalog URL", + "Press OK to enter Username":"Press OK to enter Username", + "Exit":"Exit" } \ No newline at end of file diff --git a/accelerator-home-ui/static/language/translations/es.json b/accelerator-home-ui/static/language/translations/es.json index ad17c49..d856c63 100644 --- a/accelerator-home-ui/static/language/translations/es.json +++ b/accelerator-home-ui/static/language/translations/es.json @@ -295,5 +295,14 @@ "Are you sure you want to uninstall this app?":"¿Está seguro de que desea desinstalar esta aplicación?", "Press OK to enter Username":"Presione OK para ingresar el nombre de usuario", "Username":"Nombre de usuario", - "Downloading":"Descargando" + "Downloading":"Descargando", + "Authentication failed. Please try again.":"Autenticación fallida. Por favor, inténtelo de nuevo.", + "Exit":"Salir", + "App Catalog URL":"URL del catálogo de aplicaciones", + "Loading...":"Cargando...", + "Authenticating...":"Autenticando...", + "Unknown":"Desconocido", + "Unavailable":"No disponible", + "App Catalog URL is not set":"La URL del catálogo de aplicaciones no está configurada", + "Unable to retrieve App Catalog URL":"No se pudo obtener la URL del catálogo de aplicaciones" } diff --git a/bolt/package-configs/com.rdkcentral.refui.json b/bolt/package-configs/com.rdkcentral.refui.json index c64ed36..927a96f 100644 --- a/bolt/package-configs/com.rdkcentral.refui.json +++ b/bolt/package-configs/com.rdkcentral.refui.json @@ -1,7 +1,7 @@ { "id": "com.rdkcentral.refui", - "version": "6.0.12", - "versionName": "6.0.12", + "version": "6.0.13", + "versionName": "6.0.13", "name": "RDK Ref UI Home Screen", "packageType": "application", "entryPoint": "--lightning --dev file:///usr/share/refui/index.html",