From 749f89d0af61e7aab7d96cb70a392e4efb8f8020 Mon Sep 17 00:00:00 2001 From: suryag23 Date: Thu, 19 Mar 2026 20:12:56 +0530 Subject: [PATCH 01/35] Changes for the error and uninstall overlay screen then some bug fixes also part of this --- accelerator-home-ui/src/App.js | 58 ++-- accelerator-home-ui/src/AppController.js | 26 +- accelerator-home-ui/src/items/AppCard.js | 5 +- .../src/items/AppCatalogItem.js | 8 +- accelerator-home-ui/src/items/DacAppItem.js | 13 +- .../src/keyIntercept/keyIntercept.js | 39 ++- .../src/overlays/UninstallConfirmation.js | 297 ++++++++++++++++++ accelerator-home-ui/src/routes/routes.js | 6 +- .../src/screens/FailAndOkScreen.js | 123 ++++++++ accelerator-home-ui/src/views/AppInfoPage.js | 76 ++++- accelerator-home-ui/src/views/AppStore.js | 27 ++ accelerator-home-ui/src/views/MainView.js | 49 ++- 12 files changed, 644 insertions(+), 83 deletions(-) create mode 100644 accelerator-home-ui/src/overlays/UninstallConfirmation.js create mode 100644 accelerator-home-ui/src/screens/FailAndOkScreen.js diff --git a/accelerator-home-ui/src/App.js b/accelerator-home-ui/src/App.js index c86832c..86b06ea 100644 --- a/accelerator-home-ui/src/App.js +++ b/accelerator-home-ui/src/App.js @@ -35,6 +35,7 @@ import { import Keymap from './Config/Keymap'; import Menu from './views/Menu' import Failscreen from './screens/FailScreen'; +import FailAndOkScreen from './screens/FailAndOkScreen'; import { keyIntercept } from './keyIntercept/keyIntercept'; @@ -193,6 +194,9 @@ export default class App extends Router.App { Fail: { type: Failscreen, }, + FailOk: { + type: FailAndOkScreen, + }, Volume: { type: Volume }, @@ -514,7 +518,7 @@ export default class App extends Router.App { "Prime": "n:2" } this._getPowerStatebeforeReboot(); - this._registerFireboltListeners() + // this._registerFireboltListeners() Keyboard.provide('xrn:firebolt:capability:input:keyboard', new KeyboardUIProvider(this)) this.LOG("Keyboard provider registered") @@ -1704,32 +1708,32 @@ export default class App extends Router.App { this._getPowerStateWhileReboot(); }); } - _registerFireboltListeners() { - FireBoltApi.get().deviceinfo.gettype() - FireBoltApi.get().lifecycle.ready() - - FireBoltApi.get().lifecycle.registerEvent('foreground', value => { - this.LOG("FireBoltApi[foreground] value:" + JSON.stringify(value) + ", launchResidentApp with:" + JSON.stringify(GLOBALS.selfClientName)); - // Ripple launches refui with this rdkshell client name. - GLOBALS.topmostApp = GLOBALS.selfClientName; - FireBoltApi.get().discovery.launch("refui", { - "action": "home", - "context": { - "source": "device" - } - }).then(() => { - AlexaApi.get().reportApplicationState("menu", true); - }) - }) - FireBoltApi.get().lifecycle.registerEvent('background', value => { - // Ripple changed app states; it will be a 'FireboltApp' - GLOBALS.topmostApp = "FireboltApp"; - this.LOG("FireBoltApi[foreground] value:" + JSON.stringify(value) + ", Updating top app as:" + JSON.stringify(GLOBALS.topmostApp)); - }) - FireBoltApi.get().lifecycle.state().then(res => { - this.LOG("Lifecycle.state result:" + JSON.stringify(res)) - }); - } + // _registerFireboltListeners() { + // FireBoltApi.get().deviceinfo.gettype() + // FireBoltApi.get().lifecycle.ready() + + // FireBoltApi.get().lifecycle.registerEvent('foreground', value => { + // this.LOG("FireBoltApi[foreground] value:" + JSON.stringify(value) + ", launchResidentApp with:" + JSON.stringify(GLOBALS.selfClientName)); + // // Ripple launches refui with this rdkshell client name. + // GLOBALS.topmostApp = GLOBALS.selfClientName; + // FireBoltApi.get().discovery.launch("refui", { + // "action": "home", + // "context": { + // "source": "device" + // } + // }).then(() => { + // AlexaApi.get().reportApplicationState("menu", true); + // }) + // }) + // FireBoltApi.get().lifecycle.registerEvent('background', value => { + // // Ripple changed app states; it will be a 'FireboltApp' + // GLOBALS.topmostApp = "FireboltApp"; + // this.LOG("FireBoltApi[foreground] value:" + JSON.stringify(value) + ", Updating top app as:" + JSON.stringify(GLOBALS.topmostApp)); + // }) + // FireBoltApi.get().lifecycle.state().then(res => { + // this.LOG("Lifecycle.state result:" + JSON.stringify(res)) + // }); + // } _firstEnable() { this.LOG("App Calling listenToVoiceControl method to activate VoiceControl Plugin") diff --git a/accelerator-home-ui/src/AppController.js b/accelerator-home-ui/src/AppController.js index 4ae3d35..5a4a564 100644 --- a/accelerator-home-ui/src/AppController.js +++ b/accelerator-home-ui/src/AppController.js @@ -175,25 +175,15 @@ export default class AppController { async addKeyIntercepts(appId, clientId) { if (appId === "com.rdkcentral.youtube") { try { + const intercepts = [ + { "keyCode": Keymap.AudioVolumeMute, "modifiers": [] }, + { "keyCode": Keymap.AudioVolumeDown, "modifiers": [] }, + { "keyCode": Keymap.AudioVolumeUp, "modifiers": [] }, + { "keyCode": Keymap.Youtube, "modifiers": [] } + ]; await RDKWindowManager.get().addKeyIntercepts({ - "intercepts": { - "intercepts": [{ - "keys": [{ - "keyCode": Keymap.AudioVolumeMute, - "modifiers": [] - }, { - "keyCode": Keymap.AudioVolumeDown, - "modifiers": [] - }, { - "keyCode": Keymap.AudioVolumeUp, - "modifiers": [] - }, { - "keyCode": Keymap.Youtube, - "modifiers": [] - }], - "client": clientId - }] - } + "clientId": clientId, + "intercepts": JSON.stringify(intercepts) }); } catch (err) { throw new ThunderError("RDKWindowManager.addKeyIntercepts()", err); diff --git a/accelerator-home-ui/src/items/AppCard.js b/accelerator-home-ui/src/items/AppCard.js index 52d5582..7aee6b4 100644 --- a/accelerator-home-ui/src/items/AppCard.js +++ b/accelerator-home-ui/src/items/AppCard.js @@ -66,9 +66,6 @@ class ActionButton extends Lightning.Component { set primary(isPrimary) { this._isPrimary = isPrimary; - if (isPrimary) { - this.patch({ color: CONFIG.theme.hex }); - } } get primary() { @@ -97,7 +94,7 @@ class ActionButton extends Lightning.Component { _unfocus() { this.tag('FocusIndicator').alpha = 0; this.patch({ - color: this._isPrimary ? CONFIG.theme.hex : 0xFF3D3D3D, + color: 0xFF3D3D3D, smooth: { scale: 1 } }); } diff --git a/accelerator-home-ui/src/items/AppCatalogItem.js b/accelerator-home-ui/src/items/AppCatalogItem.js index 5922135..a52d8d8 100644 --- a/accelerator-home-ui/src/items/AppCatalogItem.js +++ b/accelerator-home-ui/src/items/AppCatalogItem.js @@ -50,6 +50,7 @@ export const DACAppMixin = (Base) => class extends Base { this.updateDACStatus(statusProgressTag, overlayTag) if (!success) { this.tag(statusProgressTag).setProgress(1.0, 'Error: ' + msg) + this.fireAncestors('$showInstallError', { name: this._app.name, errorCode: msg || -1 }) } return true; // Installation operation completed } else if (this._app.isUnInstalling) { @@ -58,6 +59,7 @@ export const DACAppMixin = (Base) => class extends Base { this.updateDACStatus(statusProgressTag, overlayTag) if (!success) { this.tag(statusProgressTag).setProgress(1.0, 'Error: ' + msg) + this.fireAncestors('$showUninstallError', { name: this._app.name, error: msg }) } return true; // Uninstall operation completed } @@ -97,10 +99,12 @@ export const DACAppMixin = (Base) => class extends Base { } else { this.ERR("Failed to launch app: " + this._app.name) this.tag(overlayTag + '.OverlayText').text.text = Language.translate('Launch failed'); + this.fireAncestors('$showLaunchError', { name: this._app.name }); } } catch (err) { this.ERR("Error launching app: " + JSON.stringify(err)) this.tag(overlayTag + '.OverlayText').text.text = Language.translate('Launch failed'); + this.fireAncestors('$showLaunchError', { name: this._app.name, error: err.message || err }); } this.tag(overlayTag).setSmooth('alpha', 0, { duration: 5 }) return true; // Already installed @@ -117,10 +121,12 @@ export const DACAppMixin = (Base) => class extends Base { this._app.isInstalling = true; if (!await installDACApp(this._app, this.tag(statusProgressTag))) { this._app.isInstalling = false; - this.tag(overlayTag + '.OverlayText').text.text = Language.translate("Status") + ':' + (this._app.errorCode ?? -1); + const errorCode = this._app.errorCode ?? -1; + this.tag(overlayTag + '.OverlayText').text.text = Language.translate("Status") + ':' + errorCode; this.tag(overlayTag).alpha = 0.7 this.tag(overlayTag + '.OverlayText').alpha = 1 this.tag(overlayTag).setSmooth('alpha', 0, { duration: 5 }) + this.fireAncestors('$showInstallError', { name: this._app.name, errorCode: errorCode }); return false; } return true; diff --git a/accelerator-home-ui/src/items/DacAppItem.js b/accelerator-home-ui/src/items/DacAppItem.js index 006c604..28319c1 100644 --- a/accelerator-home-ui/src/items/DacAppItem.js +++ b/accelerator-home-ui/src/items/DacAppItem.js @@ -189,7 +189,14 @@ export default class DacAppItem extends DACAppMixin(Lightning.Component) { if (this._app.isInstalled) { this.LOG("App is already installed, launching...") // Launch the installed app - this._app.isRunning = await startDACApp(this._app); + try { + this._app.isRunning = await startDACApp(this._app); + if (!this._app.isRunning) { + this.fireAncestors('$showLaunchError', { name: this._app.name }); + } + } catch (err) { + this.fireAncestors('$showLaunchError', { name: this._app.name, error: err.message || err }); + } return } await this.performDACInstall('ImageWrapper.StatusProgress', 'ImageWrapper.Overlay'); @@ -244,6 +251,10 @@ export default class DacAppItem extends DACAppMixin(Lightning.Component) { async _handleEnter() { // Handle "More Apps" item - navigate to apps route if (this.data.applicationType === 'MoreApps') { + if (!GLOBALS.IsConnectedToInternet) { + this.fireAncestors('$showNetworkError') + return + } Router.navigate('apps'); return; } diff --git a/accelerator-home-ui/src/keyIntercept/keyIntercept.js b/accelerator-home-ui/src/keyIntercept/keyIntercept.js index d810cfb..f7ba8ba 100644 --- a/accelerator-home-ui/src/keyIntercept/keyIntercept.js +++ b/accelerator-home-ui/src/keyIntercept/keyIntercept.js @@ -26,29 +26,26 @@ const thunder = ThunderJS(CONFIG.thunderConfig); export function keyIntercept(clientName = GLOBALS.selfClientId) { return new Promise((resolve, reject) => { + const intercepts = [ + { "keyCode": Keymap.Home, "modifiers": [] }, + { "keyCode": Keymap.AudioVolumeDown, "modifiers": [] }, + { "keyCode": Keymap.AudioVolumeUp, "modifiers": [] }, + { "keyCode": Keymap.AudioVolumeMute, "modifiers": [] }, + { "keyCode": Keymap.Inputs_Shortcut, "modifiers": [] }, + { "keyCode": Keymap.Picture_Setting_Shortcut, "modifiers": [] }, + { "keyCode": Keymap.Youtube, "modifiers": [] }, + { "keyCode": Keymap.Power, "modifiers": [] }, + { "keyCode": Keymap.Amazon, "modifiers": [] }, + { "keyCode": Keymap.Netflix, "modifiers": [] }, + { "keyCode": Keymap.Settings_Shortcut, "modifiers": [] }, + { "keyCode": Keymap.Guide_Shortcut, "modifiers": [] }, + { "keyCode": Keymap.AppCarousel, "modifiers": [] }, + { "keyCode": Keymap.Escape, "modifiers": [] } + ]; RDKWindowManager.get().addKeyIntercepts( { - "intercepts":{ - "intercepts": [{ - "keys": [ - { "keyCode": Keymap.Home, "modifiers": [] }, - { "keyCode": Keymap.AudioVolumeDown, "modifiers": [] }, - { "keyCode": Keymap.AudioVolumeUp, "modifiers": [] }, - { "keyCode": Keymap.AudioVolumeMute, "modifiers": [] }, - { "keyCode": Keymap.Inputs_Shortcut, "modifiers": [] }, - { "keyCode": Keymap.Picture_Setting_Shortcut, "modifiers": [] }, - { "keyCode": Keymap.Youtube, "modifiers": [] }, - { "keyCode": Keymap.Power, "modifiers": [] }, - { "keyCode": Keymap.Amazon, "modifiers": [] }, - { "keyCode": Keymap.Netflix, "modifiers": [] }, - { "keyCode": Keymap.Settings_Shortcut, "modifiers": [] }, - { "keyCode": Keymap.Guide_Shortcut, "modifiers": [] }, - { "keyCode": Keymap.AppCarousel, "modifiers": [] }, - { "keyCode": Keymap.Escape, "modifiers": [] } - ], - "client": clientName, - }] - }, + "clientId": clientName, + "intercepts": JSON.stringify(intercepts) } ).then(result => { if (result.success) { diff --git a/accelerator-home-ui/src/overlays/UninstallConfirmation.js b/accelerator-home-ui/src/overlays/UninstallConfirmation.js new file mode 100644 index 0000000..3190ce3 --- /dev/null +++ b/accelerator-home-ui/src/overlays/UninstallConfirmation.js @@ -0,0 +1,297 @@ +/** + * If not stated otherwise in this file or this component's LICENSE + * file the following copyright and licenses apply: + * + * Copyright 2020 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ +import { Lightning, Utils, Language } from "@lightningjs/sdk"; +import { CONFIG } from "../Config/Config"; + +/** + * Class for Uninstall Confirmation Overlay Component. + */ +export default class UninstallConfirmation extends Lightning.Component { + static _template() { + return { + rect: true, + w: 1920, + h: 1080, + color: 0xCC000000, // Semi-transparent black background + zIndex: 10, + UninstallDialog: { + x: 960, + y: 540, + mount: 0.5, + rect: true, + w: 620, + h: 320, + color: 0xFF1A1A1A, + shader: { + type: Lightning.shaders.RoundedRectangle, + radius: 16, + }, + DialogBorder: { + x: -2, + y: -2, + w: 624, + h: 324, + rect: true, + color: 0x00000000, + shader: { + type: Lightning.shaders.RoundedRectangle, + radius: 18, + stroke: 2, + strokeColor: 0xFF3D3D3D, + }, + }, + Title: { + x: 310, + y: 40, + mountX: 0.5, + text: { + text: Language.translate("Uninstall"), + fontFace: CONFIG.language.font, + fontSize: 36, + textColor: CONFIG.theme.hex, + fontStyle: "bold", + }, + }, + BorderTop: { + x: 30, + y: 90, + w: 560, + h: 2, + rect: true, + color: 0xFF3D3D3D, + }, + Info: { + x: 310, + y: 130, + mountX: 0.5, + text: { + text: Language.translate("Are you sure you want to uninstall this app?"), + fontFace: CONFIG.language.font, + fontSize: 24, + textColor: 0xFFCCCCCC, + textAlign: "center", + wordWrapWidth: 520, + }, + }, + AppName: { + x: 310, + y: 170, + mountX: 0.5, + text: { + text: "", + fontFace: CONFIG.language.font, + fontSize: 22, + textColor: 0xFFAAAAAA, + textAlign: "center", + wordWrapWidth: 520, + }, + }, + Buttons: { + x: 310, + y: 230, + mountX: 0.5, + w: 440, + h: 50, + Confirm: { + x: 0, + w: 200, + h: 50, + rect: true, + color: 0xFFFFFFFF, + shader: { + type: Lightning.shaders.RoundedRectangle, + radius: 8, + }, + Title: { + x: 100, + y: 25, + mount: 0.5, + text: { + text: Language.translate("Confirm"), + fontFace: CONFIG.language.font, + fontSize: 22, + textColor: 0xFF000000, + }, + }, + }, + Cancel: { + x: 220, + w: 200, + h: 50, + rect: true, + color: 0xFF7D7D7D, + shader: { + type: Lightning.shaders.RoundedRectangle, + radius: 8, + }, + Title: { + x: 100, + y: 25, + mount: 0.5, + text: { + text: Language.translate("Cancel"), + fontFace: CONFIG.language.font, + fontSize: 22, + textColor: 0xFF000000, + }, + }, + }, + }, + Loader: { + x: 310, + y: 160, + mountX: 0.5, + w: 90, + h: 90, + zIndex: 2, + src: Utils.asset("images/settings/Loading.png"), + visible: false, + }, + }, + }; + } + + /** + * Set the app info for the uninstall confirmation + * @param {Object} appInfo - App data (id, name, version, etc.) + */ + set appInfo(data) { + this._appInfo = data; + const appName = data.name || data.appName || "Unknown App"; + this.tag("UninstallDialog.AppName").text.text = `"${appName}"`; + } + + get appInfo() { + return this._appInfo; + } + + _focus() { + this._setState("Confirm"); + + this.loadingAnimation = this.tag("UninstallDialog.Loader").animation({ + duration: 3, + repeat: -1, + stopMethod: "immediate", + stopDelay: 0.2, + actions: [{ p: "rotation", v: { sm: 0, 0: 0, 1: 2 * Math.PI } }], + }); + } + + static _states() { + return [ + class Confirm extends this { + $enter() { + this._focus(); + } + _handleEnter() { + this.fireAncestors("$confirmUninstall", this._appInfo); + } + _handleRight() { + this._setState("Cancel"); + } + _handleBack() { + this.fireAncestors("$cancelUninstall"); + } + _focus() { + this.tag("Buttons.Confirm").patch({ + color: CONFIG.theme.hex, + }); + this.tag("Buttons.Confirm.Title").patch({ + text: { textColor: 0xFFFFFFFF }, + }); + } + _unfocus() { + this.tag("Buttons.Confirm").patch({ + color: 0xFFFFFFFF, + }); + this.tag("Buttons.Confirm.Title").patch({ + text: { textColor: 0xFF000000 }, + }); + } + $exit() { + this._unfocus(); + } + }, + class Cancel extends this { + $enter() { + this._focus(); + } + _handleEnter() { + this.fireAncestors("$cancelUninstall"); + } + _handleLeft() { + this._setState("Confirm"); + } + _handleBack() { + this.fireAncestors("$cancelUninstall"); + } + _focus() { + this.tag("Buttons.Cancel").patch({ + color: CONFIG.theme.hex, + }); + this.tag("Buttons.Cancel.Title").patch({ + text: { textColor: 0xFFFFFFFF }, + }); + } + _unfocus() { + this.tag("Buttons.Cancel").patch({ + color: 0xFF7D7D7D, + }); + this.tag("Buttons.Cancel.Title").patch({ + text: { textColor: 0xFF000000 }, + }); + } + $exit() { + this._unfocus(); + } + }, + class Uninstalling extends this { + $enter() { + this.loadingAnimation.start(); + this.tag("UninstallDialog.Loader").visible = true; + this.tag("UninstallDialog.Title").text.text = Language.translate("Uninstalling") + "..."; + this.tag("UninstallDialog.Buttons").visible = false; + this.tag("UninstallDialog.Info").visible = false; + this.tag("UninstallDialog.AppName").visible = false; + } + $exit() { + this.loadingAnimation.stop(); + this.tag("UninstallDialog.Loader").visible = false; + this.tag("UninstallDialog.Title").text.text = Language.translate("Uninstall"); + this.tag("UninstallDialog.Buttons").visible = true; + this.tag("UninstallDialog.Info").visible = true; + this.tag("UninstallDialog.AppName").visible = true; + } + _handleEnter() { /* do nothing */ } + _handleLeft() { /* do nothing */ } + _handleRight() { /* do nothing */ } + _handleBack() { /* do nothing */ } + _handleUp() { /* do nothing */ } + _handleDown() { /* do nothing */ } + }, + ]; + } + + /** + * Show the uninstalling state with loader + */ + showUninstalling() { + this._setState("Uninstalling"); + } +} diff --git a/accelerator-home-ui/src/routes/routes.js b/accelerator-home-ui/src/routes/routes.js index bafef6c..7f99815 100644 --- a/accelerator-home-ui/src/routes/routes.js +++ b/accelerator-home-ui/src/routes/routes.js @@ -101,12 +101,12 @@ export default { { path: 'apps', component: AppStore, - widgets: ['Menu', 'Volume', "AppCarousel"] + widgets: ['Menu', 'FailOk', 'Volume', "AppCarousel"] }, { path: 'appinfo', component: AppInfoPage, - widgets: ['Menu', 'Volume', "AppCarousel"] + widgets: ['Menu', 'FailOk', 'Volume', "AppCarousel"] }, { path: 'usb/player', @@ -140,7 +140,7 @@ export default { } return Promise.resolve() }, - widgets: ['Menu', 'Fail', 'Volume','MiracastNotification', "AppCarousel", "VideoInfoChange"], + widgets: ['Menu', 'Fail', 'FailOk', 'Volume','MiracastNotification', "AppCarousel", "VideoInfoChange"], }, { path: 'tv-overlay/:type', diff --git a/accelerator-home-ui/src/screens/FailAndOkScreen.js b/accelerator-home-ui/src/screens/FailAndOkScreen.js new file mode 100644 index 0000000..f638cc0 --- /dev/null +++ b/accelerator-home-ui/src/screens/FailAndOkScreen.js @@ -0,0 +1,123 @@ +/** + * If not stated otherwise in this file or this component's LICENSE + * file the following copyright and licenses apply: + * + * Copyright 2020 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ +import { Language, Lightning, Router } from "@lightningjs/sdk"; +import { CONFIG } from '../Config/Config' + +const errorTitle = 'Error Title' +const errorMsg = 'Error Message' +export default class FailAndOkScreen extends Lightning.Component { + + constructor(...args) { + super(...args); + this.INFO = console.info; + this.LOG = console.log; + this.ERR = console.error; + this.WARN = console.warn; + } + + notify(args) { + this.LOG("notify args: " + JSON.stringify(args)) + if (args.title && args.msg) { + this.tag('FailScreen.Title').text.text = args.title + this.tag('FailScreen.Message').text.text = Language.translate(args.msg) + } + } + + pageTransition() { + return 'left' + } + + _focus() { + this.LOG("FailAndOkScreen _focus() called, alpha before: " + this.alpha) + this.alpha = 1 + this.LOG("FailAndOkScreen _focus() alpha set to 1") + this.tag('FailScreen.OkButton').color = CONFIG.theme.hex + this.tag('FailScreen.OkButton.OkLabel').text.textColor = 0xFFFFFFFF + } + + _unfocus() { + this.alpha = 0 + this.tag('FailScreen.Title').text.text = errorTitle + this.tag('FailScreen.Message').text.text = errorMsg + this.tag('FailScreen.OkButton').color = 0xFFFFFFFF + this.tag('FailScreen.OkButton.OkLabel').text.textColor = 0xFF000000 + } + + static _template() { + return { + alpha: 0, + w: 1920, + h: 1080, + rect: true, + color: 0xcc000000, + FailScreen: { + x: 960, + y: 300, + Title: { + mountX: 0.5, + text: { + text: errorTitle, + fontFace: CONFIG.language.font, + fontSize: 40, + textColor: CONFIG.theme.hex, + }, + }, + BorderTop: { + x: 0, y: 75, w: 1558, h: 3, rect: true, mountX: 0.5, + }, + Message: { + x: 0, + y: 125, + mountX: 0.5, + text: { + text: errorMsg, + fontFace: CONFIG.language.font, + fontSize: 25, + }, + }, + OkButton: { + x: 0, y: 200, w: 200, mountX: 0.5, h: 50, rect: true, color: 0xFFFFFFFF, + OkLabel: { + x: 100, + y: 25, + mount: 0.5, + text: { + text: Language.translate("OK"), + fontFace: CONFIG.language.font, + fontSize: 25, + textColor: 0xFF000000, + }, + }, + }, + BorderBottom: { + x: 0, y: 300, w: 1558, h: 3, rect: true, mountX: 0.5, + }, + }, + }; + } + + _handleEnter() { + Router.focusPage() + } + + _handleBack() { + Router.focusPage() + } + +} diff --git a/accelerator-home-ui/src/views/AppInfoPage.js b/accelerator-home-ui/src/views/AppInfoPage.js index 9070e46..1e17697 100644 --- a/accelerator-home-ui/src/views/AppInfoPage.js +++ b/accelerator-home-ui/src/views/AppInfoPage.js @@ -23,6 +23,7 @@ import { CONFIG, GLOBALS } from "../Config/Config"; import AppCard from "../items/AppCard"; import { getInstalledDACApps, startDACApp, uninstallDACApp } from "../api/DACApi"; import { filterExcludedApps } from "../helpers/DACAppPresentation"; +import UninstallConfirmation from "../overlays/UninstallConfirmation"; export default class AppInfoPage extends Lightning.Component { @@ -158,6 +159,13 @@ export default class AppInfoPage extends Lightning.Component { } } } + }, + + // Uninstall Confirmation Overlay + UninstallConfirmationOverlay: { + type: UninstallConfirmation, + visible: false, + zIndex: 10 } } } @@ -247,7 +255,7 @@ export default class AppInfoPage extends Lightning.Component { break; case 'uninstall': console.log("Uninstall app:", appInfo.name); - this._uninstallApp(appInfo); + this._showUninstallConfirmation(appInfo); break; default: console.log("Unknown action:", action); @@ -293,14 +301,67 @@ export default class AppInfoPage extends Lightning.Component { console.log(`${appInfo.name} uninstalled successfully`); // Refresh the list after uninstall await this._fetchInstalledApps(); + return true; } else { console.error(`Failed to uninstall ${appInfo.name}`); + return false; } } catch (error) { console.error(`Error uninstalling ${appInfo.name}:`, error); + return false; + } + } + + /** + * Show the uninstall confirmation overlay + */ + _showUninstallConfirmation(appInfo) { + this._pendingUninstallApp = appInfo; + this.tag('UninstallConfirmationOverlay').appInfo = appInfo; + this.tag('UninstallConfirmationOverlay').visible = true; + this._setState('UninstallConfirmation'); + } + + /** + * Hide the uninstall confirmation overlay + */ + _hideUninstallConfirmation() { + this.tag('UninstallConfirmationOverlay').visible = false; + this._pendingUninstallApp = null; + // Set correct state based on whether apps remain + if (this._appData.length > 0) { + this._setState('AppList'); + } else { + this._setState('EmptyState'); } } + /** + * Signal handler: user confirmed uninstall + */ + $confirmUninstall(appInfo) { + console.log('Uninstall confirmed for:', appInfo.name); + this.tag('UninstallConfirmationOverlay').showUninstalling(); + this._uninstallApp(appInfo).then((success) => { + this._hideUninstallConfirmation(); + if (!success) { + this.widgets.failok.notify({ + title: Language.translate('Uninstall Failed'), + msg: Language.translate('Failed to uninstall') + ` "${appInfo.name}". ` + Language.translate('Please try again later.'), + }); + Router.focusWidget('FailOk'); + } + }); + } + + /** + * Signal handler: user cancelled uninstall + */ + $cancelUninstall() { + console.log('Uninstall cancelled'); + this._hideUninstallConfirmation(); + } + /** * Update scroll indicator position */ @@ -378,6 +439,17 @@ export default class AppInfoPage extends Lightning.Component { return false; } }, + class UninstallConfirmation extends this { + $enter() { + this.tag('UninstallConfirmationOverlay').visible = true; + } + _getFocused() { + return this.tag('UninstallConfirmationOverlay'); + } + $exit() { + this.tag('UninstallConfirmationOverlay').visible = false; + } + }, class EmptyState extends this { $enter() { this.tag('EmptyState.OkButton').color = CONFIG.theme.hex; @@ -393,6 +465,8 @@ export default class AppInfoPage extends Lightning.Component { return this; } _focus() { + // Re-fetch installed apps in case new apps were installed while away + this._fetchInstalledApps(); this.tag('EmptyState.OkButton').color = CONFIG.theme.hex; this.tag('EmptyState.OkButton.OkLabel').text.textColor = 0xFFFFFFFF; this.tag('EmptyState.OkButton.FocusBorder').alpha = 1; diff --git a/accelerator-home-ui/src/views/AppStore.js b/accelerator-home-ui/src/views/AppStore.js index 083d1d5..5c621bc 100644 --- a/accelerator-home-ui/src/views/AppStore.js +++ b/accelerator-home-ui/src/views/AppStore.js @@ -78,6 +78,33 @@ export default class AppStore extends Lightning.Component { this._setState('Catalog') } + $showInstallError({ name, errorCode }) { + const appName = name || Language.translate('App') + const msg = Language.translate('Something went wrong while installing') + ` "${appName}". ` + Language.translate('Error code') + `: ${errorCode}` + this.widgets.failok.notify({ title: Language.translate('Installation Failed'), msg: msg }) + Router.focusWidget('FailOk') + } + + $showUninstallError({ name, error }) { + const appName = name || Language.translate('App') + let msg = Language.translate('Failed to uninstall') + ` "${appName}". ` + Language.translate('Please try again later.') + if (error) { + msg += ' ' + Language.translate('Error') + `: ${error}` + } + this.widgets.failok.notify({ title: Language.translate('Uninstall Failed'), msg: msg }) + Router.focusWidget('FailOk') + } + + $showLaunchError({ name, error }) { + const appName = name || Language.translate('App') + let msg = Language.translate('Something went wrong while launching') + ` "${appName}". ` + Language.translate('Please check the internet and remaining setup.') + if (error) { + msg += ' ' + Language.translate('Error') + `: ${error}` + } + this.widgets.failok.notify({ title: Language.translate('Launch Failed'), msg: msg }) + Router.focusWidget('FailOk') + } + static _states() { return [ class Catalog extends this { diff --git a/accelerator-home-ui/src/views/MainView.js b/accelerator-home-ui/src/views/MainView.js index 27c258a..b07e3dc 100644 --- a/accelerator-home-ui/src/views/MainView.js +++ b/accelerator-home-ui/src/views/MainView.js @@ -718,8 +718,35 @@ export default class MainView extends Lightning.Component { } } $showNetworkError() { - this.widgets.fail.notify({ title: 'Network State', msg: 'Offline' }) - Router.focusWidget('Fail') + this.widgets.failok.notify({ title: Language.translate('No Internet'), msg: Language.translate('No internet connection. Please check your network and try again.') }) + Router.focusWidget('FailOk') + } + + $showInstallError({ name, errorCode }) { + const appName = name || Language.translate('App') + const msg = Language.translate('Something went wrong while installing') + ` "${appName}". ` + Language.translate('Error code') + `: ${errorCode}` + this.widgets.failok.notify({ title: Language.translate('Installation Failed'), msg: msg }) + Router.focusWidget('FailOk') + } + + $showUninstallError({ name, error }) { + const appName = name || Language.translate('App') + let msg = Language.translate('Failed to uninstall') + ` "${appName}". ` + Language.translate('Please try again later.') + if (error) { + msg += ' ' + Language.translate('Error') + `: ${error}` + } + this.widgets.failok.notify({ title: Language.translate('Uninstall Failed'), msg: msg }) + Router.focusWidget('FailOk') + } + + $showLaunchError({ name, error }) { + const appName = name || Language.translate('App') + let msg = Language.translate('Something went wrong while launching') + ` "${appName}". ` + Language.translate('Please check the internet and remaining setup.') + if (error) { + msg += ' ' + Language.translate('Error') + `: ${error}` + } + this.widgets.failok.notify({ title: Language.translate('Launch Failed'), msg: msg }) + Router.focusWidget('FailOk') } /** @@ -925,10 +952,11 @@ export default class MainView extends Lightning.Component { }) } else if (applicationType === 'DAC') { // Launch DAC app using startDACApp - if (!GLOBALS.IsConnectedToInternet) { - this.fireAncestors('$showNetworkError') - return - } + // if (!GLOBALS.IsConnectedToInternet) { + // console.log('No internet connection. Cannot launch DAC app.') + // this.$showNetworkError() + // return + // } let dacApp = { id: appIdentifier || uri, name: appData.displayName, @@ -937,7 +965,14 @@ export default class MainView extends Lightning.Component { url: uri } this.LOG('Launching DAC app from My Apps: ' + JSON.stringify(dacApp)) - startDACApp(dacApp) + try { + const launched = await startDACApp(dacApp) + if (!launched) { + this.$showLaunchError({ name: appData.displayName }) + } + } catch (err) { + this.$showLaunchError({ name: appData.displayName, error: err.message || err }) + } } } }, From bd9385e873bffa2cdd772ad536cf034f27717c89 Mon Sep 17 00:00:00 2001 From: suryag23 Date: Fri, 20 Mar 2026 13:36:02 +0530 Subject: [PATCH 02/35] Addressed the review comments --- accelerator-home-ui/src/items/AppCard.js | 9 --------- .../src/overlays/UninstallConfirmation.js | 17 +++++++++++++++++ accelerator-home-ui/src/views/AppInfoPage.js | 5 +++-- accelerator-home-ui/src/views/MainView.js | 10 +++++----- 4 files changed, 25 insertions(+), 16 deletions(-) diff --git a/accelerator-home-ui/src/items/AppCard.js b/accelerator-home-ui/src/items/AppCard.js index 7aee6b4..a5badc6 100644 --- a/accelerator-home-ui/src/items/AppCard.js +++ b/accelerator-home-ui/src/items/AppCard.js @@ -64,14 +64,6 @@ class ActionButton extends Lightning.Component { this.tag('Label').text.text = text; } - set primary(isPrimary) { - this._isPrimary = isPrimary; - } - - get primary() { - return this._isPrimary || false; - } - set action(actionType) { this._action = actionType; } @@ -190,7 +182,6 @@ export default class AppCard extends Lightning.Component { x: 0, type: ActionButton, label: Language.translate('Launch'), - primary: true, action: 'launch' }, UpdateButton: { diff --git a/accelerator-home-ui/src/overlays/UninstallConfirmation.js b/accelerator-home-ui/src/overlays/UninstallConfirmation.js index 3190ce3..cc146d6 100644 --- a/accelerator-home-ui/src/overlays/UninstallConfirmation.js +++ b/accelerator-home-ui/src/overlays/UninstallConfirmation.js @@ -193,6 +193,23 @@ export default class UninstallConfirmation extends Lightning.Component { }); } + /** + * Safety-net cleanup when the overlay loses focus (e.g. parent hides or + * navigates away). Ensures the loader animation is stopped and the dialog + * UI is restored to its default state even if no explicit state transition + * (Uninstalling → Confirm) was triggered before dismissal. + */ + _unfocus() { + if (this.loadingAnimation && this.loadingAnimation.isActive()) { + this.loadingAnimation.stop(); + } + this.tag("UninstallDialog.Loader").visible = false; + this.tag("UninstallDialog.Title").text.text = Language.translate("Uninstall"); + this.tag("UninstallDialog.Buttons").visible = true; + this.tag("UninstallDialog.Info").visible = true; + this.tag("UninstallDialog.AppName").visible = true; + } + static _states() { return [ class Confirm extends this { diff --git a/accelerator-home-ui/src/views/AppInfoPage.js b/accelerator-home-ui/src/views/AppInfoPage.js index 1e17697..8af8e3c 100644 --- a/accelerator-home-ui/src/views/AppInfoPage.js +++ b/accelerator-home-ui/src/views/AppInfoPage.js @@ -316,7 +316,6 @@ export default class AppInfoPage extends Lightning.Component { * Show the uninstall confirmation overlay */ _showUninstallConfirmation(appInfo) { - this._pendingUninstallApp = appInfo; this.tag('UninstallConfirmationOverlay').appInfo = appInfo; this.tag('UninstallConfirmationOverlay').visible = true; this._setState('UninstallConfirmation'); @@ -326,8 +325,10 @@ export default class AppInfoPage extends Lightning.Component { * Hide the uninstall confirmation overlay */ _hideUninstallConfirmation() { + // Reset overlay to its initial state so that Uninstalling.$exit() runs, + // stopping the loader animation and restoring hidden UI elements. + this.tag('UninstallConfirmationOverlay')._setState('Confirm'); this.tag('UninstallConfirmationOverlay').visible = false; - this._pendingUninstallApp = null; // Set correct state based on whether apps remain if (this._appData.length > 0) { this._setState('AppList'); diff --git a/accelerator-home-ui/src/views/MainView.js b/accelerator-home-ui/src/views/MainView.js index b07e3dc..f31a73e 100644 --- a/accelerator-home-ui/src/views/MainView.js +++ b/accelerator-home-ui/src/views/MainView.js @@ -952,11 +952,11 @@ export default class MainView extends Lightning.Component { }) } else if (applicationType === 'DAC') { // Launch DAC app using startDACApp - // if (!GLOBALS.IsConnectedToInternet) { - // console.log('No internet connection. Cannot launch DAC app.') - // this.$showNetworkError() - // return - // } + if (!GLOBALS.IsConnectedToInternet) { + console.log('No internet connection. Cannot launch DAC app.') + this.$showNetworkError() + return + } let dacApp = { id: appIdentifier || uri, name: appData.displayName, From fff83e41c11b689df2dc261dd41cdfa5f5bd1de2 Mon Sep 17 00:00:00 2001 From: suryag23 Date: Fri, 20 Mar 2026 14:09:13 +0530 Subject: [PATCH 03/35] Addressed the review comments --- .../src/items/AppCatalogItem.js | 3 +++ .../src/overlays/StatusProgress.js | 1 + .../src/screens/FailAndOkScreen.js | 2 +- accelerator-home-ui/src/views/AppInfoPage.js | 26 +++++++++---------- 4 files changed, 18 insertions(+), 14 deletions(-) diff --git a/accelerator-home-ui/src/items/AppCatalogItem.js b/accelerator-home-ui/src/items/AppCatalogItem.js index a52d8d8..25e16da 100644 --- a/accelerator-home-ui/src/items/AppCatalogItem.js +++ b/accelerator-home-ui/src/items/AppCatalogItem.js @@ -118,6 +118,9 @@ export const DACAppMixin = (Base) => class extends Base { this.tag(overlayTag + '.OverlayText').alpha = 1; this.tag(overlayTag).setSmooth('alpha', 0, { duration: 5 }); + // Reset progress bar to clear any stale state from a previous install cycle + this.tag(statusProgressTag).reset(); + this._app.isInstalling = true; if (!await installDACApp(this._app, this.tag(statusProgressTag))) { this._app.isInstalling = false; diff --git a/accelerator-home-ui/src/overlays/StatusProgress.js b/accelerator-home-ui/src/overlays/StatusProgress.js index 532c27f..168e3f5 100644 --- a/accelerator-home-ui/src/overlays/StatusProgress.js +++ b/accelerator-home-ui/src/overlays/StatusProgress.js @@ -66,6 +66,7 @@ export default class Progress extends lng.Component { var ww = (this.w - 4) * pc if(pc != 1.0) { this.tag("BackgroundOverlay").alpha=0.6 + this.tag("Label").alpha = 1.0 this.tag("ProgressBar").setSmooth('alpha', 0.7, {duration: .1}) this.tag("Progress").setSmooth('w', ww, { duration: 1 }) } diff --git a/accelerator-home-ui/src/screens/FailAndOkScreen.js b/accelerator-home-ui/src/screens/FailAndOkScreen.js index f638cc0..1ccf42a 100644 --- a/accelerator-home-ui/src/screens/FailAndOkScreen.js +++ b/accelerator-home-ui/src/screens/FailAndOkScreen.js @@ -35,7 +35,7 @@ export default class FailAndOkScreen extends Lightning.Component { this.LOG("notify args: " + JSON.stringify(args)) if (args.title && args.msg) { this.tag('FailScreen.Title').text.text = args.title - this.tag('FailScreen.Message').text.text = Language.translate(args.msg) + this.tag('FailScreen.Message').text.text = args.msg } } diff --git a/accelerator-home-ui/src/views/AppInfoPage.js b/accelerator-home-ui/src/views/AppInfoPage.js index 8af8e3c..982006f 100644 --- a/accelerator-home-ui/src/views/AppInfoPage.js +++ b/accelerator-home-ui/src/views/AppInfoPage.js @@ -299,8 +299,6 @@ export default class AppInfoPage extends Lightning.Component { const result = await uninstallDACApp({ id: appInfo.id, version: appInfo.version, name: appInfo.name }, this); if (result) { console.log(`${appInfo.name} uninstalled successfully`); - // Refresh the list after uninstall - await this._fetchInstalledApps(); return true; } else { console.error(`Failed to uninstall ${appInfo.name}`); @@ -340,19 +338,21 @@ export default class AppInfoPage extends Lightning.Component { /** * Signal handler: user confirmed uninstall */ - $confirmUninstall(appInfo) { + async $confirmUninstall(appInfo) { console.log('Uninstall confirmed for:', appInfo.name); this.tag('UninstallConfirmationOverlay').showUninstalling(); - this._uninstallApp(appInfo).then((success) => { - this._hideUninstallConfirmation(); - if (!success) { - this.widgets.failok.notify({ - title: Language.translate('Uninstall Failed'), - msg: Language.translate('Failed to uninstall') + ` "${appInfo.name}". ` + Language.translate('Please try again later.'), - }); - Router.focusWidget('FailOk'); - } - }); + const success = await this._uninstallApp(appInfo); + // Dismiss overlay first, then refresh list so state transitions don't compete + this._hideUninstallConfirmation(); + if (success) { + await this._fetchInstalledApps(); + } else { + this.widgets.failok.notify({ + title: Language.translate('Uninstall Failed'), + msg: Language.translate('Failed to uninstall') + ` "${appInfo.name}". ` + Language.translate('Please try again later.'), + }); + Router.focusWidget('FailOk'); + } } /** From 3cd38bc48805d598a29e87c5a5ee2f3aa06a17fb Mon Sep 17 00:00:00 2001 From: suryag23 Date: Fri, 20 Mar 2026 14:28:20 +0530 Subject: [PATCH 04/35] Addressed the review comments --- .../src/items/AppCatalogItem.js | 3 ++- accelerator-home-ui/src/views/AppInfoPage.js | 22 ++++++++++++------- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/accelerator-home-ui/src/items/AppCatalogItem.js b/accelerator-home-ui/src/items/AppCatalogItem.js index 25e16da..af4fd2c 100644 --- a/accelerator-home-ui/src/items/AppCatalogItem.js +++ b/accelerator-home-ui/src/items/AppCatalogItem.js @@ -46,11 +46,12 @@ export const DACAppMixin = (Base) => class extends Base { if (this._app.isInstalling) { this._app.isInstalled = success this._app.isInstalling = false + const errorCode = this._app.errorCode ?? -1; if (Object.prototype.hasOwnProperty.call(this._app, "errorCode")) delete this._app.errorCode; this.updateDACStatus(statusProgressTag, overlayTag) if (!success) { this.tag(statusProgressTag).setProgress(1.0, 'Error: ' + msg) - this.fireAncestors('$showInstallError', { name: this._app.name, errorCode: msg || -1 }) + this.fireAncestors('$showInstallError', { name: this._app.name, errorCode: errorCode }) } return true; // Installation operation completed } else if (this._app.isUnInstalling) { diff --git a/accelerator-home-ui/src/views/AppInfoPage.js b/accelerator-home-ui/src/views/AppInfoPage.js index 982006f..50400d7 100644 --- a/accelerator-home-ui/src/views/AppInfoPage.js +++ b/accelerator-home-ui/src/views/AppInfoPage.js @@ -320,19 +320,15 @@ export default class AppInfoPage extends Lightning.Component { } /** - * Hide the uninstall confirmation overlay + * Hide the uninstall confirmation overlay. + * Only handles overlay cleanup; callers are responsible for + * setting the correct page state afterward. */ _hideUninstallConfirmation() { // Reset overlay to its initial state so that Uninstalling.$exit() runs, // stopping the loader animation and restoring hidden UI elements. this.tag('UninstallConfirmationOverlay')._setState('Confirm'); this.tag('UninstallConfirmationOverlay').visible = false; - // Set correct state based on whether apps remain - if (this._appData.length > 0) { - this._setState('AppList'); - } else { - this._setState('EmptyState'); - } } /** @@ -342,11 +338,15 @@ export default class AppInfoPage extends Lightning.Component { console.log('Uninstall confirmed for:', appInfo.name); this.tag('UninstallConfirmationOverlay').showUninstalling(); const success = await this._uninstallApp(appInfo); - // Dismiss overlay first, then refresh list so state transitions don't compete + // Dismiss overlay first, then let _fetchInstalledApps -> _loadAppData + // be the single source of truth for the next page state. this._hideUninstallConfirmation(); if (success) { + // _loadAppData will set AppList or EmptyState based on refreshed data await this._fetchInstalledApps(); } else { + // Uninstall failed — data hasn't changed, restore list focus + this._setState('AppList'); this.widgets.failok.notify({ title: Language.translate('Uninstall Failed'), msg: Language.translate('Failed to uninstall') + ` "${appInfo.name}". ` + Language.translate('Please try again later.'), @@ -361,6 +361,12 @@ export default class AppInfoPage extends Lightning.Component { $cancelUninstall() { console.log('Uninstall cancelled'); this._hideUninstallConfirmation(); + // Data hasn't changed — restore previous page state + if (this._appData.length > 0) { + this._setState('AppList'); + } else { + this._setState('EmptyState'); + } } /** From 7f0c80982737e682a3bd25e5c3eac0fd8c660a6a Mon Sep 17 00:00:00 2001 From: yashaswini-rk Date: Mon, 16 Mar 2026 23:47:58 -0400 Subject: [PATCH 05/35] RDKEAPPRT-612 :Add dac store details via RFC --- accelerator-home-ui/src/api/AppApi.js | 2 +- accelerator-home-ui/src/api/DACApi.js | 30 +++++++++++++++++++++++---- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/accelerator-home-ui/src/api/AppApi.js b/accelerator-home-ui/src/api/AppApi.js index 4b2bb9b..d3ec733 100644 --- a/accelerator-home-ui/src/api/AppApi.js +++ b/accelerator-home-ui/src/api/AppApi.js @@ -1607,7 +1607,7 @@ export default class AppApi { getRFCConfig(rfcParamsList) { return new Promise((resolve, reject) => { - thunder.call('org.rdk.System', 'getRFCConfig', rfcParamsList).then(result => { + thunder.call('org.rdk.System', 'getRFCConfig',{rfcList:[rfcParamsList]}).then(result => { if (result.success) { resolve(result) } else { diff --git a/accelerator-home-ui/src/api/DACApi.js b/accelerator-home-ui/src/api/DACApi.js index d03afbf..423cb7e 100644 --- a/accelerator-home-ui/src/api/DACApi.js +++ b/accelerator-home-ui/src/api/DACApi.js @@ -20,6 +20,7 @@ import DownloadManager from './DownloadManagerApi'; import PackageManager from './PackageManagerApi'; import AppManager from './AppManagerApi'; +import AppApi from './AppApi'; import AppController from '../AppController'; import { ThunderError } from './ThunderError'; import { Metrics } from '@firebolt-js/sdk' @@ -73,11 +74,32 @@ let storeConfig = null; async function getStoreConfig() { if (!storeConfig) { - const config = await PackageManager.get().configuration(); - if (typeof config?.configUrl !== "string") { - throw new Error("Invalid config: " + JSON.stringify(config)); + const appApi = new AppApi(); + const rfcKey = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.DAC.ConfigURL"; + let resolvedConfigUrl = null; + try { + const result = await appApi.getRFCConfig(rfcKey); + const rfcUrl = result?.RFCConfig?.[rfcKey]; + console.log("config URL from RFC :", rfcUrl); + if (typeof rfcUrl == "string" && rfcUrl.trim().length > 0) { + resolvedConfigUrl = rfcUrl.trim(); + } else { + console.warn("RFC URL empty or invalid; will fall back to PackageManager."); + } + } catch (err) { + console.warn("getRFCConfig failed; will fall back to PackageManager.", err); + } + + if (!resolvedConfigUrl) { + const config = await PackageManager.get().configuration(); + if (typeof config?.configUrl !== "string") { + throw new Error("Invalid config: " + JSON.stringify(config)); + } else { + resolvedConfigUrl = config?.configUrl; + console.log("config URL from packagemanager :", resolvedConfigUrl); + } } - const fetchResponse = await fetch(config.configUrl); + const fetchResponse = await fetch(resolvedConfigUrl); if (!fetchResponse.ok) { throw new Error(`Unexpected response: ${fetchResponse.status}: ${fetchResponse.statusText}`); } From 6f3b3a2b3f08d0fa6cecd29af3b87dcac41eb90f Mon Sep 17 00:00:00 2001 From: yashaswini-rk Date: Mon, 16 Mar 2026 23:55:23 -0400 Subject: [PATCH 06/35] RDKEAPPRT-612:dac store url via RFC --- accelerator-home-ui/src/api/DACApi.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/accelerator-home-ui/src/api/DACApi.js b/accelerator-home-ui/src/api/DACApi.js index 423cb7e..9dcd068 100644 --- a/accelerator-home-ui/src/api/DACApi.js +++ b/accelerator-home-ui/src/api/DACApi.js @@ -80,7 +80,6 @@ async function getStoreConfig() { try { const result = await appApi.getRFCConfig(rfcKey); const rfcUrl = result?.RFCConfig?.[rfcKey]; - console.log("config URL from RFC :", rfcUrl); if (typeof rfcUrl == "string" && rfcUrl.trim().length > 0) { resolvedConfigUrl = rfcUrl.trim(); } else { @@ -96,7 +95,6 @@ async function getStoreConfig() { throw new Error("Invalid config: " + JSON.stringify(config)); } else { resolvedConfigUrl = config?.configUrl; - console.log("config URL from packagemanager :", resolvedConfigUrl); } } const fetchResponse = await fetch(resolvedConfigUrl); From 0acb616126a19adc4fdb005589261464b8c0fcb1 Mon Sep 17 00:00:00 2001 From: yashaswini-rk Date: Thu, 19 Mar 2026 17:46:17 -0400 Subject: [PATCH 07/35] RDKEAPPRT-612 : Get DAC store details via RFC --- accelerator-home-ui/src/api/AppApi.js | 2 +- accelerator-home-ui/src/api/DACApi.js | 62 ++++++++++++++++++--------- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/accelerator-home-ui/src/api/AppApi.js b/accelerator-home-ui/src/api/AppApi.js index d3ec733..c1d5f45 100644 --- a/accelerator-home-ui/src/api/AppApi.js +++ b/accelerator-home-ui/src/api/AppApi.js @@ -1607,7 +1607,7 @@ export default class AppApi { getRFCConfig(rfcParamsList) { return new Promise((resolve, reject) => { - thunder.call('org.rdk.System', 'getRFCConfig',{rfcList:[rfcParamsList]}).then(result => { + thunder.call('org.rdk.System', 'getRFCConfig',{"rfcList":[rfcParamsList]}).then(result => { if (result.success) { resolve(result) } else { diff --git a/accelerator-home-ui/src/api/DACApi.js b/accelerator-home-ui/src/api/DACApi.js index 9dcd068..3ab198c 100644 --- a/accelerator-home-ui/src/api/DACApi.js +++ b/accelerator-home-ui/src/api/DACApi.js @@ -39,6 +39,8 @@ const APP_DETAILS_KEY = "refui.details"; const APP_DEFAULT_ARCH = "arm"; +const APP_STORE_RFC_KEY = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.DAC.ConfigURL"; + function makeLogMessage(call, err) { return err.toString() + " <=> " + call; } @@ -72,31 +74,51 @@ class OperationLock { let packageLock = new OperationLock(); let storeConfig = null; -async function getStoreConfig() { - if (!storeConfig) { +async function getConfigUrlFromRFC() { + try { const appApi = new AppApi(); - const rfcKey = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.DAC.ConfigURL"; - let resolvedConfigUrl = null; - try { - const result = await appApi.getRFCConfig(rfcKey); - const rfcUrl = result?.RFCConfig?.[rfcKey]; - if (typeof rfcUrl == "string" && rfcUrl.trim().length > 0) { - resolvedConfigUrl = rfcUrl.trim(); - } else { - console.warn("RFC URL empty or invalid; will fall back to PackageManager."); - } - } catch (err) { - console.warn("getRFCConfig failed; will fall back to PackageManager.", err); + console.log("Resolving DAC Store URL from RFC "); + const result = await appApi.getRFCConfig(APP_STORE_RFC_KEY); + const rfcUrl = result?.RFCConfig?.[APP_STORE_RFC_KEY]; + if (typeof rfcUrl === "string" && rfcUrl.trim().length > 0) { + const resolvedConfigUrl = rfcUrl.trim(); + console.log("Resolved DAC Store URL from RFC "); + return resolvedConfigUrl; + } + console.warn("DAC Store RFC URL empty or invalid"); + return null; + } catch (err) { + console.error("Failed to get DAC Store URL from RFC", err); + return null; + } +} + +async function getConfigUrlFromPackageManager() { + try { + console.log("Resolving DAC Store URL from PackageManager..."); + const config = await PackageManager.get().configuration(); + console.log("Resolved DAC Store URL from PackageManager: "); + if (typeof config?.configUrl !== "string" || config.configUrl.trim().length === 0) { + throw new Error("Invalid config: " + JSON.stringify(config)); } + return config.configUrl.trim(); + } catch (err) { + console.error("Failed to resolve DAC Store URL from PackageManager", err); + throw err; + } +} + +async function getStoreConfig() { + if (!storeConfig) { + console.log("Resolving DAC Store config URL..."); + let resolvedConfigUrl = await getConfigUrlFromRFC(); + if (!resolvedConfigUrl) { - const config = await PackageManager.get().configuration(); - if (typeof config?.configUrl !== "string") { - throw new Error("Invalid config: " + JSON.stringify(config)); - } else { - resolvedConfigUrl = config?.configUrl; - } + resolvedConfigUrl = await getConfigUrlFromPackageManager(); } + + console.log("Resolved DAC Store config URL "); const fetchResponse = await fetch(resolvedConfigUrl); if (!fetchResponse.ok) { throw new Error(`Unexpected response: ${fetchResponse.status}: ${fetchResponse.statusText}`); From 19c9dca069e4e0b025b2c314ad02c362e7e9e85e Mon Sep 17 00:00:00 2001 From: suryag23 <141610966+suryag23@users.noreply.github.com> Date: Tue, 24 Mar 2026 13:53:00 +0530 Subject: [PATCH 08/35] RDKEAPPRT-645 Add default error overlay when user tries to enter VOD content (#162) * RDKEAPPRT-645 Add default error overlay when user tries to enter VOD content * Addressed the review comments --- accelerator-home-ui/src/views/MainView.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/accelerator-home-ui/src/views/MainView.js b/accelerator-home-ui/src/views/MainView.js index f31a73e..b70b891 100644 --- a/accelerator-home-ui/src/views/MainView.js +++ b/accelerator-home-ui/src/views/MainView.js @@ -1066,14 +1066,10 @@ export default class MainView extends Lightning.Component { Router.focusWidget('Menu') } } - async _handleEnter() { + _handleEnter() { if (Router.isNavigating()) return; - this.LOG("MainView: internetConnectivity " + JSON.stringify(GLOBALS.IsConnectedToInternet)); - let params ={url: this.tag('TVShows').items[this.tag('TVShows').index].data.uri, - } - if (GLOBALS.IsConnectedToInternet) { - Router.navigate("player",params) - } + this.widgets.failok.notify({ title: Language.translate('Not Supported'), msg: Language.translate('VOD feature is not supported.') }) + Router.focusWidget('FailOk') } $exit() { this.tag('Text3').text.fontStyle = 'normal' From b9dfca048869fb42db10c0d6e64c992a8c7de94d Mon Sep 17 00:00:00 2001 From: suryag23 Date: Wed, 25 Mar 2026 14:56:13 +0530 Subject: [PATCH 09/35] RDKEAPPRT-646 Create the Username, Password page and add it inside the settings route --- .../src/routes/networkRoutes.js | 6 + .../src/screens/DacStoreLoginComponent.js | 369 ++++++++++++++++++ .../src/screens/SettingsScreen.js | 61 ++- 3 files changed, 427 insertions(+), 9 deletions(-) create mode 100644 accelerator-home-ui/src/screens/DacStoreLoginComponent.js diff --git a/accelerator-home-ui/src/routes/networkRoutes.js b/accelerator-home-ui/src/routes/networkRoutes.js index 1f8e091..15386bb 100644 --- a/accelerator-home-ui/src/routes/networkRoutes.js +++ b/accelerator-home-ui/src/routes/networkRoutes.js @@ -26,6 +26,7 @@ import NetworkInterfaceScreen from "../screens/OtherSettingsScreens/NetworkInter import WifiPairingScreen from "../screens/WiFiPairingScreen" import WiFiScreen from "../screens/WifiScreen" import RCVolumeInfoScreen from '../screens/RcInformationScreen' +import DacStoreLoginComponent from '../screens/DacStoreLoginComponent' const networkRoutes = [ { @@ -72,6 +73,11 @@ const networkRoutes = [ path: 'settings/bluetooth/RCVolumeInfoScreen', component: RCVolumeInfoScreen, widgets: ["Menu",'Volume', "Fail","AppCarousel"] + }, + { + path: 'settings/dacstore', + component: DacStoreLoginComponent, + widgets: ['Volume', 'AppCarousel'] } ] diff --git a/accelerator-home-ui/src/screens/DacStoreLoginComponent.js b/accelerator-home-ui/src/screens/DacStoreLoginComponent.js new file mode 100644 index 0000000..e6157b3 --- /dev/null +++ b/accelerator-home-ui/src/screens/DacStoreLoginComponent.js @@ -0,0 +1,369 @@ +/** + * If not stated otherwise in this file or this component's LICENSE + * file the following copyright and licenses apply: + * + * Copyright 2020 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ +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'; + +export default class DacStoreLoginComponent extends Lightning.Component { + + constructor(...args) { + super(...args); + this.INFO = console.info; + this.LOG = console.log; + this.ERR = console.error; + this.WARN = console.warn; + } + + pageTransition() { + return 'left' + } + + _active() { + this.hidePasswd = true + this.star = "" + this.tag("Keyboard").visible = false + } + + handleDone() { + this.tag("Keyboard").visible = false + if (!this.textCollection['EnterUsername']) { + this._setState("EnterUsername"); + } + else if (!this.textCollection['EnterPassword']) { + this._setState("EnterPassword"); + } + else { + this.LOG('DAC Store Login - Username: ' + this.textCollection['EnterUsername']) + } + } + + static _template() { + return { + Background: { + w: 1920, + h: 1080, + rect: true, + color: 0xCC000000, + }, + Text: { + x: 758, + y: 70, + text: { + text: Language.translate("Connect to the Application Catalog"), + fontFace: CONFIG.language.font, + fontSize: 35, + textColor: CONFIG.theme.hex, + }, + }, + BorderTop: { + x: 190, y: 130, w: 1488, h: 2, rect: true, + }, + Username: { + x: 190, + y: 176, + text: { + text: Language.translate("Username") + ": ", + fontFace: CONFIG.language.font, + fontSize: 25, + }, + }, + UsernameBox: { + x: 400, + y: 160, + texture: Lightning.Tools.getRoundRect(1273, 58, 0, 3, 0xffffffff, false) + }, + UsernameText: { + x: 420, + y: 170, + zIndex: 2, + text: { + text: '', + fontSize: 25, + fontFace: CONFIG.language.font, + textColor: 0xffffffff, + wordWrapWidth: 1300, + wordWrap: false, + textOverflow: 'ellipsis', + }, + }, + Password: { + x: 190, + y: 246, + text: { + text: Language.translate("Password") + ":", + fontFace: CONFIG.language.font, + fontSize: 25, + }, + }, + PasswordBox: { + x: 400, + y: 230, + texture: Lightning.Tools.getRoundRect(1273, 58, 0, 3, 0xffffffff, false) + }, + Pwd: { + x: 420, + y: 240, + zIndex: 2, + text: { + text: '', + fontSize: 25, + fontFace: CONFIG.language.font, + textColor: 0xffffffff, + wordWrapWidth: 1300, + wordWrap: false, + textOverflow: 'ellipsis', + }, + }, + BorderBottom: { + x: 190, y: 326, w: 1488, h: 2, rect: true, + }, + ExitButton: { + x: 960, + y: 350, + mountX: 0.5, + w: 200, + h: 50, + rect: true, + color: 0xff444444, + shader: { type: Lightning.shaders.RoundedRectangle, radius: 10 }, + ExitLabel: { + x: 100, + y: 25, + mount: 0.5, + text: { + text: Language.translate('Exit'), + fontFace: CONFIG.language.font, + fontSize: 22, + textColor: 0xffffffff, + }, + }, + }, + Keyboard: { + y: 420, + x: 400, + type: Keyboard, + visible: false, + zIndex: 2, + formats: KEYBOARD_FORMATS.qwerty + }, + PasswrdSwitch: { + h: 45, + w: 66.9, + x: 1642, + y: 260, + zIndex: 2, + type: PasswordSwitch, + mount: 0.5, + visible: true + }, + ShowPassword: { + x: 1365, + y: 242, + w: 300, + h: 75, + zIndex: 2, + text: { text: Language.translate('Show Password'), fontSize: 25, fontFace: CONFIG.language.font, textColor: 0xffffffff, textAlign: 'left' }, + visible: true + } + } + } + + _focus() { + this._setState('EnterUsername'); + this.textCollection = { 'EnterUsername': '', 'EnterPassword': '' } + this.tag('Pwd').text.text = Language.translate("Press OK to enter Password"); + this.tag("UsernameText").text.text = Language.translate("Press OK to enter Username"); + this.tag('UsernameText').text.textColor = 0xff808080 + this.tag('Pwd').text.textColor = 0xff808080 + } + + encrypt() { + if (this.prevState === "EnterPassword" && this.hidePasswd) + return true + else + return false + } + + _updateText(txt) { + this.tag("Pwd").text.text = txt; + } + + _handleBack() { + if (!Router.isNavigating()) { + Router.back() + } + } + + static _states() { + return [ + class EnterUsername extends this { + $enter() { + this.tag('UsernameBox').texture = Lightning.Tools.getRoundRect(1273, 58, 0, 3, CONFIG.theme.hex, false) + } + _handleDown() { + this._setState("EnterPassword"); + } + _handleEnter() { + this._setState('Keyboard') + this.tag('UsernameText').text.text = this.textCollection['EnterUsername'] + this.tag('UsernameText').text.textColor = 0xffffffff + this.tag("Keyboard").visible = true + } + $exit() { + this.tag('UsernameBox').texture = Lightning.Tools.getRoundRect(1273, 58, 0, 3, 0xffffffff, false) + } + }, + class EnterPassword extends this { + $enter() { + this.tag('PasswordBox').texture = Lightning.Tools.getRoundRect(1273, 58, 0, 3, CONFIG.theme.hex, false) + } + _handleUp() { + this._setState("EnterUsername"); + } + _handleDown() { + this._setState("ExitButton"); + } + _handleRight() { + this._setState("PasswordSwitchState") + } + _handleEnter() { + this.tag("Keyboard").visible = true + this._setState('Keyboard') + this.tag('Pwd').text.text = this.hidePasswd ? this.star : this.textCollection['EnterPassword'] + this.tag('Pwd').text.textColor = 0xffffffff + } + $exit() { + this.tag('PasswordBox').texture = Lightning.Tools.getRoundRect(1273, 58, 0, 3, 0xffffffff, false); + } + }, + class PasswordSwitchState extends this { + $enter() { + this.tag("PasswordBox").texture = Lightning.Tools.getRoundRect(1273, 58, 0, 3, CONFIG.theme.hex, false) + this.tag('ShowPassword').text.textColor = CONFIG.theme.hex + } + _handleDown() { + this._setState("Keyboard"); + } + _handleUp() { + this._setState("EnterUsername"); + } + _handleLeft() { + this._setState("EnterPassword"); + } + _getFocused() { + return this.tag('PasswrdSwitch'); + } + + $handleEnter(bool) { + if (bool) { + this._updateText(this.textCollection['EnterPassword']) + this.hidePasswd = false; + } + else { + this._updateText(this.star); + this.hidePasswd = true; + } + this.isOn = bool; + } + + $exit() { + this.tag("PasswordBox").texture = Lightning.Tools.getRoundRect(1273, 58, 0, 3, 0xffffffff, false) + this.tag('ShowPassword').text.textColor = 0xffffffff + } + }, + class ExitButton extends this { + $enter() { + this.tag('ExitButton').color = CONFIG.theme.hex + } + $exit() { + this.tag('ExitButton').color = 0xff444444 + } + _handleUp() { + this._setState('EnterPassword') + } + _handleDown() { + this._setState('EnterUsername') + } + _handleEnter() { + if (!Router.isNavigating()) { + Router.back() + } + } + }, + class Keyboard extends this { + $enter(state) { + this.prevState = state.prevState + if (this.prevState === 'EnterUsername') { + this.element = 'UsernameText' + } + if (this.prevState === 'EnterPassword') { + this.element = 'Pwd' + } + } + _getFocused() { + return this.tag('Keyboard') + } + + $onSoftKey({ key }) { + if (this.prevState === 'PasswordSwitchState') { + this.prevState = "EnterPassword" + } + this.LOG("Prev state: " + JSON.stringify(this.prevState)) + if (key === 'Done') { + this.handleDone(); + } else if (key === 'Clear') { + this.textCollection[this.prevState] = this.textCollection[this.prevState].substring(0, this.textCollection[this.prevState].length - 1); + this.star = (this.prevState === "EnterPassword") ? this.star.substring(0, this.star.length - 1) : this.star + this.tag(this.element).text.text = this.encrypt() ? this.star : this.textCollection[this.prevState]; + } else if (key === '#@!' || key === 'abc' || key === 'áöû' || key === 'shift') { + this.LOG('no saving') + } else if (key === 'Space') { + this.textCollection[this.prevState] += ' ' + this.star += (this.prevState === "EnterPassword") ? '\u25CF' : this.star + this.tag(this.element).text.text = this.encrypt() ? this.star : this.textCollection[this.prevState]; + } else if (key === 'Delete') { + this.textCollection[this.prevState] = '' + this.star = (this.prevState === "EnterPassword") ? '' : this.star + this.tag(this.element).text.text = this.encrypt() ? this.star : this.textCollection[this.prevState]; + } else { + this.textCollection[this.prevState] += key + this.star += (this.prevState === "EnterPassword") ? '\u25CF' : this.star + this.tag(this.element).text.text = this.encrypt() ? this.star : this.textCollection[this.prevState]; + } + } + _handleUp() { + this._setState(this.prevState) + } + + _handleBack() { + this._setState(this.prevState) + } + } + ] + } + + _init() { + this.star = '' + this.textCollection = { 'EnterUsername': '', 'EnterPassword': '' } + this.tag("Pwd").text.text = this.textCollection['EnterPassword'] + this.tag("UsernameText").text.text = this.textCollection['EnterUsername'] + } +} diff --git a/accelerator-home-ui/src/screens/SettingsScreen.js b/accelerator-home-ui/src/screens/SettingsScreen.js index 9659e8f..3bd8f47 100644 --- a/accelerator-home-ui/src/screens/SettingsScreen.js +++ b/accelerator-home-ui/src/screens/SettingsScreen.js @@ -79,9 +79,33 @@ export default class SettingsScreen extends Lightning.Component { src: Utils.asset('images/settings/Arrow.png'), }, }, - Bluetooth: { + DacStore: { y: 90, type: SettingsMainItem, + Title: { + x: 10, + y: 45, + mountY: 0.5, + text: { + text: Language.translate('Connect to the Application Catalog'), + textColor: COLORS.titleColor, + fontFace: CONFIG.language.font, + fontSize: 25, + } + }, + Button: { + h: 45, + w: 45, + x: 1600, + mountX: 1, + y: 45, + mountY: 0.5, + src: Utils.asset('images/settings/Arrow.png'), + }, + }, + Bluetooth: { + y: 180, + type: SettingsMainItem, Title: { x: 10, y: 45, @@ -104,7 +128,7 @@ export default class SettingsScreen extends Lightning.Component { }, }, Video: { - y: 180, + y: 270, type: SettingsMainItem, Title: { x: 10, @@ -128,7 +152,7 @@ export default class SettingsScreen extends Lightning.Component { }, }, Audio: { - y: 270, + y: 360, type: SettingsMainItem, Title: { x: 10, @@ -152,7 +176,7 @@ export default class SettingsScreen extends Lightning.Component { }, }, OtherSettings: { - y: 360, + y: 450, type: SettingsMainItem, Title: { x: 10, @@ -177,7 +201,7 @@ export default class SettingsScreen extends Lightning.Component { }, NFRStatus: { - y: 450, + y: 540, type: SettingsMainItem, Title: { x: 10, @@ -204,7 +228,7 @@ export default class SettingsScreen extends Lightning.Component { DTVSettings: { alpha: 0.3, - y: 630, + y: 720, type: SettingsMainItem, Title: { x: 10, @@ -229,7 +253,7 @@ export default class SettingsScreen extends Lightning.Component { }, VoiceRemoteControl: { - y: 540, + y: 630, type: SettingsMainItem, Title: { x: 10, @@ -300,7 +324,7 @@ export default class SettingsScreen extends Lightning.Component { this.tag('NetworkConfiguration')._unfocus() } _handleDown() { - this._setState('Bluetooth') + this._setState('DacStore') } _handleEnter() { if (!Router.isNavigating()) { @@ -308,6 +332,25 @@ export default class SettingsScreen extends Lightning.Component { } } }, + class DacStore extends this { + $enter() { + this.tag('DacStore')._focus() + } + $exit() { + this.tag('DacStore')._unfocus() + } + _handleUp() { + this._setState('NetworkConfiguration') + } + _handleDown() { + this._setState('Bluetooth') + } + _handleEnter() { + if (!Router.isNavigating()) { + Router.navigate('settings/dacstore') + } + } + }, class Bluetooth extends this { $enter() { this.tag('Bluetooth')._focus() @@ -316,7 +359,7 @@ export default class SettingsScreen extends Lightning.Component { this.tag('Bluetooth')._unfocus() } _handleUp() { - this._setState('NetworkConfiguration') + this._setState('DacStore') } _handleDown() { this._setState('Video') From 73208ddefab21ae3ab533d33ab3443c6bf7d4547 Mon Sep 17 00:00:00 2001 From: suryag23 Date: Wed, 25 Mar 2026 15:01:48 +0530 Subject: [PATCH 10/35] renamed the file --- accelerator-home-ui/src/routes/networkRoutes.js | 4 ++-- ...acStoreLoginComponent.js => AppCatalogueLogicComponent.js} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename accelerator-home-ui/src/screens/{DacStoreLoginComponent.js => AppCatalogueLogicComponent.js} (99%) diff --git a/accelerator-home-ui/src/routes/networkRoutes.js b/accelerator-home-ui/src/routes/networkRoutes.js index 15386bb..410144e 100644 --- a/accelerator-home-ui/src/routes/networkRoutes.js +++ b/accelerator-home-ui/src/routes/networkRoutes.js @@ -26,7 +26,7 @@ import NetworkInterfaceScreen from "../screens/OtherSettingsScreens/NetworkInter import WifiPairingScreen from "../screens/WiFiPairingScreen" import WiFiScreen from "../screens/WifiScreen" import RCVolumeInfoScreen from '../screens/RcInformationScreen' -import DacStoreLoginComponent from '../screens/DacStoreLoginComponent' +import AppCatalogueLogicComponent from '../screens/AppCatalogueLogicComponent' const networkRoutes = [ { @@ -76,7 +76,7 @@ const networkRoutes = [ }, { path: 'settings/dacstore', - component: DacStoreLoginComponent, + component: AppCatalogueLogicComponent, widgets: ['Volume', 'AppCarousel'] } ] diff --git a/accelerator-home-ui/src/screens/DacStoreLoginComponent.js b/accelerator-home-ui/src/screens/AppCatalogueLogicComponent.js similarity index 99% rename from accelerator-home-ui/src/screens/DacStoreLoginComponent.js rename to accelerator-home-ui/src/screens/AppCatalogueLogicComponent.js index e6157b3..7d98466 100644 --- a/accelerator-home-ui/src/screens/DacStoreLoginComponent.js +++ b/accelerator-home-ui/src/screens/AppCatalogueLogicComponent.js @@ -22,7 +22,7 @@ import { Keyboard } from '../ui-components/index' import { KEYBOARD_FORMATS } from '../ui-components/components/Keyboard' import PasswordSwitch from './PasswordSwitch'; -export default class DacStoreLoginComponent extends Lightning.Component { +export default class AppCatalogueLogicComponent extends Lightning.Component { constructor(...args) { super(...args); From 1af047bf2cd7f24a3afade9dfa5d66e4d48d2c31 Mon Sep 17 00:00:00 2001 From: suryag23 Date: Wed, 25 Mar 2026 15:08:11 +0530 Subject: [PATCH 11/35] Update the filename correctly --- accelerator-home-ui/src/routes/networkRoutes.js | 6 +++--- ...talogueLogicComponent.js => AppCatalogLoginComponent.js} | 2 +- accelerator-home-ui/src/screens/SettingsScreen.js | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) rename accelerator-home-ui/src/screens/{AppCatalogueLogicComponent.js => AppCatalogLoginComponent.js} (99%) diff --git a/accelerator-home-ui/src/routes/networkRoutes.js b/accelerator-home-ui/src/routes/networkRoutes.js index 410144e..a262b47 100644 --- a/accelerator-home-ui/src/routes/networkRoutes.js +++ b/accelerator-home-ui/src/routes/networkRoutes.js @@ -26,7 +26,7 @@ import NetworkInterfaceScreen from "../screens/OtherSettingsScreens/NetworkInter import WifiPairingScreen from "../screens/WiFiPairingScreen" import WiFiScreen from "../screens/WifiScreen" import RCVolumeInfoScreen from '../screens/RcInformationScreen' -import AppCatalogueLogicComponent from '../screens/AppCatalogueLogicComponent' +import AppCatalogLoginComponent from '../screens/AppCatalogLoginComponent' const networkRoutes = [ { @@ -75,8 +75,8 @@ const networkRoutes = [ widgets: ["Menu",'Volume', "Fail","AppCarousel"] }, { - path: 'settings/dacstore', - component: AppCatalogueLogicComponent, + path: 'settings/appcataloglogin', + component: AppCatalogLoginComponent, widgets: ['Volume', 'AppCarousel'] } ] diff --git a/accelerator-home-ui/src/screens/AppCatalogueLogicComponent.js b/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js similarity index 99% rename from accelerator-home-ui/src/screens/AppCatalogueLogicComponent.js rename to accelerator-home-ui/src/screens/AppCatalogLoginComponent.js index 7d98466..36fa871 100644 --- a/accelerator-home-ui/src/screens/AppCatalogueLogicComponent.js +++ b/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js @@ -22,7 +22,7 @@ import { Keyboard } from '../ui-components/index' import { KEYBOARD_FORMATS } from '../ui-components/components/Keyboard' import PasswordSwitch from './PasswordSwitch'; -export default class AppCatalogueLogicComponent extends Lightning.Component { +export default class AppCatalogLoginComponent extends Lightning.Component { constructor(...args) { super(...args); diff --git a/accelerator-home-ui/src/screens/SettingsScreen.js b/accelerator-home-ui/src/screens/SettingsScreen.js index 3bd8f47..fe45b72 100644 --- a/accelerator-home-ui/src/screens/SettingsScreen.js +++ b/accelerator-home-ui/src/screens/SettingsScreen.js @@ -347,7 +347,7 @@ export default class SettingsScreen extends Lightning.Component { } _handleEnter() { if (!Router.isNavigating()) { - Router.navigate('settings/dacstore') + Router.navigate('settings/appcataloglogin') } } }, From e57704cebb8b492a4eca9b7e702d8748ab6efcec Mon Sep 17 00:00:00 2001 From: suryag23 Date: Wed, 25 Mar 2026 16:13:06 +0530 Subject: [PATCH 12/35] Addressed the review comments --- .../src/screens/AppCatalogLoginComponent.js | 10 +++++----- accelerator-home-ui/src/screens/SettingsScreen.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js b/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js index 36fa871..509f3dc 100644 --- a/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js +++ b/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -import { Language, Lightning, Router, Utils } from '@lightningjs/sdk' +import { Language, Lightning, Router } from '@lightningjs/sdk' import { CONFIG } from '../Config/Config'; import { Keyboard } from '../ui-components/index' import { KEYBOARD_FORMATS } from '../ui-components/components/Keyboard' @@ -51,7 +51,7 @@ export default class AppCatalogLoginComponent extends Lightning.Component { this._setState("EnterPassword"); } else { - this.LOG('DAC Store Login - Username: ' + this.textCollection['EnterUsername']) + this.LOG('App Catalog Login - credentials submitted') } } @@ -260,7 +260,7 @@ export default class AppCatalogLoginComponent extends Lightning.Component { this.tag('ShowPassword').text.textColor = CONFIG.theme.hex } _handleDown() { - this._setState("Keyboard"); + this._setState("ExitButton"); } _handleUp() { this._setState("EnterUsername"); @@ -337,7 +337,7 @@ export default class AppCatalogLoginComponent extends Lightning.Component { this.LOG('no saving') } else if (key === 'Space') { this.textCollection[this.prevState] += ' ' - this.star += (this.prevState === "EnterPassword") ? '\u25CF' : this.star + this.star += (this.prevState === "EnterPassword") ? '\u25CF' : '' this.tag(this.element).text.text = this.encrypt() ? this.star : this.textCollection[this.prevState]; } else if (key === 'Delete') { this.textCollection[this.prevState] = '' @@ -345,7 +345,7 @@ export default class AppCatalogLoginComponent extends Lightning.Component { this.tag(this.element).text.text = this.encrypt() ? this.star : this.textCollection[this.prevState]; } else { this.textCollection[this.prevState] += key - this.star += (this.prevState === "EnterPassword") ? '\u25CF' : this.star + this.star += (this.prevState === "EnterPassword") ? '\u25CF' : '' this.tag(this.element).text.text = this.encrypt() ? this.star : this.textCollection[this.prevState]; } } diff --git a/accelerator-home-ui/src/screens/SettingsScreen.js b/accelerator-home-ui/src/screens/SettingsScreen.js index fe45b72..207e8f3 100644 --- a/accelerator-home-ui/src/screens/SettingsScreen.js +++ b/accelerator-home-ui/src/screens/SettingsScreen.js @@ -487,7 +487,7 @@ export default class SettingsScreen extends Lightning.Component { this.tag('DTVSettings')._unfocus() } _handleUp() { - this._setState('NFRStatus') + this._setState('VoiceRemoteControl') } _handleEnter() { if (this.dtvPlugin) { From 361a48e22df2aedc29426debc830812c2297d40c Mon Sep 17 00:00:00 2001 From: suryag23 Date: Wed, 25 Mar 2026 16:48:19 +0530 Subject: [PATCH 13/35] Reneamed the DAC instance to Applicationcataloguelogin --- accelerator-home-ui/src/screens/SettingsScreen.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/accelerator-home-ui/src/screens/SettingsScreen.js b/accelerator-home-ui/src/screens/SettingsScreen.js index 207e8f3..34b766f 100644 --- a/accelerator-home-ui/src/screens/SettingsScreen.js +++ b/accelerator-home-ui/src/screens/SettingsScreen.js @@ -79,7 +79,7 @@ export default class SettingsScreen extends Lightning.Component { src: Utils.asset('images/settings/Arrow.png'), }, }, - DacStore: { + ApplicationCatalogueLogin: { y: 90, type: SettingsMainItem, Title: { @@ -324,7 +324,7 @@ export default class SettingsScreen extends Lightning.Component { this.tag('NetworkConfiguration')._unfocus() } _handleDown() { - this._setState('DacStore') + this._setState('ApplicationCatalogueLogin') } _handleEnter() { if (!Router.isNavigating()) { @@ -332,12 +332,12 @@ export default class SettingsScreen extends Lightning.Component { } } }, - class DacStore extends this { + class ApplicationCatalogueLogin extends this { $enter() { - this.tag('DacStore')._focus() + this.tag('ApplicationCatalogueLogin')._focus() } $exit() { - this.tag('DacStore')._unfocus() + this.tag('ApplicationCatalogueLogin')._unfocus() } _handleUp() { this._setState('NetworkConfiguration') @@ -359,7 +359,7 @@ export default class SettingsScreen extends Lightning.Component { this.tag('Bluetooth')._unfocus() } _handleUp() { - this._setState('DacStore') + this._setState('ApplicationCatalogueLogin') } _handleDown() { this._setState('Video') From 2605f2045f74e2e2386f25fb8c55af64f8aea1b0 Mon Sep 17 00:00:00 2001 From: suryag23 Date: Thu, 26 Mar 2026 16:41:56 +0530 Subject: [PATCH 14/35] RDKEAPPRT-621,606,648,644 --- accelerator-home-ui/src/App.js | 14 ++++++++++- .../OtherSettings/LanguageScreenOverlay.js | 25 +------------------ .../OtherSettingsScreens/LanguageScreen.js | 22 +--------------- .../screens/SplashScreens/LanguageScreen.js | 23 +---------------- accelerator-home-ui/src/views/AppStore.js | 1 + 5 files changed, 17 insertions(+), 68 deletions(-) diff --git a/accelerator-home-ui/src/App.js b/accelerator-home-ui/src/App.js index 86b06ea..dce4069 100644 --- a/accelerator-home-ui/src/App.js +++ b/accelerator-home-ui/src/App.js @@ -1676,6 +1676,10 @@ export default class App extends Router.App { } _PowerStateHandlingWhileReboot() { + if (this._oldPowerStateWhileReboot === PowerState.POWER_STATE_STANDBY) { + this.LOG("_PowerStateHandlingWhileReboot: oldPowerStateWhileReboot is STANDBY, setting it to ON"); + this._oldPowerStateWhileReboot = PowerState.POWER_STATE_ON; + } this.LOG("_PowerStateHandlingWhileReboot: this._oldPowerStateWhileReboot , " + JSON.stringify(this._oldPowerStateWhileReboot) + " this._powerStateWhileReboot, " + JSON.stringify(this._powerStateWhileReboot) + " "); if (this._oldPowerStateWhileReboot != this._powerStateWhileReboot) { this.LOG("_PowerStateHandlingWhileReboot: old power state is not equal to powerstate while reboot " + JSON.stringify(this._oldPowerStateWhileReboot) + " " + JSON.stringify(this._powerStateWhileReboot)); @@ -2138,7 +2142,15 @@ export default class App extends Router.App { appApi.exitApp(currentApp); //will suspend/destroy the app depending on the setting. } Router.navigate('menu'); - } else if (notification.newState === "ON" && notification.currentState !== "ON") { + } + else if(notification.newState === PowerState.POWER_STATE_LIGHT_SLEEP && notification.currentState === PowerState.POWER_STATE_DEEP_SLEEP){ + appApi.setPowerState("ON").then(res => { + this.LOG("Device woke up from DEEP_SLEEP to LIGHT_SLEEP . setPowerState result: " + JSON.stringify(res)) + }).catch(err => { + this.ERR("Failed to set power state to ON when device woke up from DEEP_SLEEP to LIGHT_SLEEP. Error: " + JSON.stringify(err)) + }) + } + else if (notification.newState === "ON" && notification.currentState !== "ON") { //TURNING ON THE DEVICE Storage.remove(SLEEP_STATE) } diff --git a/accelerator-home-ui/src/overlays/OtherSettings/LanguageScreenOverlay.js b/accelerator-home-ui/src/overlays/OtherSettings/LanguageScreenOverlay.js index 19bcf30..a4bee32 100644 --- a/accelerator-home-ui/src/overlays/OtherSettings/LanguageScreenOverlay.js +++ b/accelerator-home-ui/src/overlays/OtherSettings/LanguageScreenOverlay.js @@ -74,17 +74,6 @@ export default class LanguageScreen extends Lightning.Component { item: item, } }) - RDKShellApis.destroy(loader).catch(err => { - this.ERR("LanguageScreenOverlay: Error destroy loader: " + JSON.stringify(err)) - }); - RDKShellApis.setVisibility(GLOBALS.selfClientName, true); - RDKShellApis.moveToFront(GLOBALS.selfClientName); - RDKShellApis.setFocus(GLOBALS.selfClientName).then(() => { - this.LOG('LanguageScreenOverlay: ResidentApp moveToFront Success'); - }).catch(err => { - this.ERR('LanguageScreenOverlay: Error: ' + JSON.stringify(err)); - Metrics.error(Metrics.ErrorType.OTHER, "PluginError", "Thunder RDKShell Failed to moveToFront " + JSON.stringify(err), false, null) - }); } _focus() { @@ -109,20 +98,8 @@ export default class LanguageScreen extends Lightning.Component { //need to verify if (Language.get() !== availableLanguages[this._Languages.tag('List').index]) { let updatedLanguage = availableLanguageCodes[availableLanguages[this._Languages.tag('List').index]] - if ("ResidentApp" !== GLOBALS.selfClientName) { - FireBoltApi.get().localization.setlanguage(availableLanguages[this._Languages.tag('List').index]).then(res => this.LOG("language set successfully")) - } else { - appApi.setUILanguage(updatedLanguage) - } + appApi.setUILanguage(updatedLanguage) localStorage.setItem('Language',availableLanguages[this._Languages.tag('List').index]) - let path = location.pathname.split('index.html')[0] - let url = path.slice(-1) === '/' ? "static/loaderApp/index.html" : "/static/loaderApp/index.html" - let notification_url = location.origin + path + url - this.LOG(notification_url) - appApi.launchResident(notification_url, loader).catch(err => { - this.ERR("Error launchResident: " + JSON.stringify(err)) - }) - RDKShellApis.setVisibility(GLOBALS.selfClientName, false) location.reload(); } } diff --git a/accelerator-home-ui/src/screens/OtherSettingsScreens/LanguageScreen.js b/accelerator-home-ui/src/screens/OtherSettingsScreens/LanguageScreen.js index ed150d5..8cfeeab 100644 --- a/accelerator-home-ui/src/screens/OtherSettingsScreens/LanguageScreen.js +++ b/accelerator-home-ui/src/screens/OtherSettingsScreens/LanguageScreen.js @@ -94,17 +94,6 @@ export default class LanguageScreen extends Lightning.Component { item: item, } }) - appApi.deactivateResidentApp(loader) - RDKShellApis.moveToFront(GLOBALS.selfClientName) - RDKShellApis.setFocus(GLOBALS.selfClientName).then(result => { - this.LOG('LanguageScreen: ResidentApp moveToFront Success'); - RDKShellApis.getVisibility(GLOBALS.selfClientName).then(visible => { - if (!visible) RDKShellApis.setVisibility(GLOBALS.selfClientName, true); - }) - }).catch(err => { - this.ERR('LanguageScreen: Error' + JSON.stringify(err)); - Metrics.error(Metrics.ErrorType.OTHER, "AppLangugaeError", 'Thunder RDKShell setFocus Error' + JSON.stringify(err), false, null) - }); } _focus() { @@ -146,17 +135,8 @@ export default class LanguageScreen extends Lightning.Component { } }) } - if ("ResidentApp" === GLOBALS.selfClientName) { - appApi.setUILanguage(updatedLanguage) - } else { - FireBoltApi.get().localization.setlanguage(availableLanguages[this._Languages.tag('List').index]).then(res => this.LOG("sucess language set ::::" + JSON.stringify(res))) - } + appApi.setUILanguage(updatedLanguage) localStorage.setItem('Language',availableLanguages[this._Languages.tag('List').index]) - let path = location.pathname.split('index.html')[0] - let url = path.slice(-1) === '/' ? "static/loaderApp/index.html" : "/static/loaderApp/index.html" - let notification_url = location.origin + path + url - appApi.launchResident(notification_url, loader).catch(err => {this.ERR("error while launching loader url in resident app" + JSON.stringify(err)) }) - RDKShellApis.setVisibility(GLOBALS.selfClientName, false) location.reload(); } } diff --git a/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js b/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js index 697d63b..b1c0726 100644 --- a/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js +++ b/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js @@ -122,17 +122,6 @@ export default class LanguageScreen extends Lightning.Component { } }) - appApi.deactivateResidentApp(loader) - RDKShellApis.moveToFront(GLOBALS.selfClientName) - RDKShellApis.setFocus(GLOBALS.selfClientName).then(result => { - this.LOG('LanguageScreen: ResidentApp moveToFront Success') - RDKShellApis.getVisibility(GLOBALS.selfClientName).then(visible => { - if (!visible) RDKShellApis.setVisibility(GLOBALS.selfClientName, true) - }) - }).catch(err => { - this.ERR('LanguageScreen: Error' + JSON.stringify(err)) - Metrics.error(Metrics.ErrorType.OTHER, "AppLangugaeError", 'Thunder RDKShell setFocus Error' + JSON.stringify(err), false, null) - }); } pageTransition() { @@ -148,11 +137,7 @@ export default class LanguageScreen extends Lightning.Component { } updateUILanguage(index) { - if ("ResidentApp" === GLOBALS.selfClientName) { - appApi.setUILanguage(availableLanguageCodes[availableLanguages[index]]) - } else { - FireBoltApi.get().localization.setlanguage(availableLanguages[index]).then(res => this.LOG("sucess language set ::::" + JSON.stringify(res))) - } + appApi.setUILanguage(availableLanguageCodes[availableLanguages[index]]) localStorage.setItem('Language',availableLanguages[index]) } @@ -181,12 +166,6 @@ export default class LanguageScreen extends Lightning.Component { const index = this._Languages.tag('List').index localStorage.setItem('LanguageSelectedIndex', index) this.updateUILanguage(index) - let path = location.pathname.split('index.html')[0] - let url = path.slice(-1) === '/' ? "static/loaderApp/index.html" : "/static/loaderApp/index.html" - let notification_url = location.origin + path + url - this.LOG("LanguageScreen notification_url: " + JSON.stringify(notification_url)) - appApi.launchResident(notification_url, loader).catch(err => { }) - RDKShellApis.setVisibility(GLOBALS.selfClientName, false) location.reload(); } } diff --git a/accelerator-home-ui/src/views/AppStore.js b/accelerator-home-ui/src/views/AppStore.js index 5c621bc..774392a 100644 --- a/accelerator-home-ui/src/views/AppStore.js +++ b/accelerator-home-ui/src/views/AppStore.js @@ -51,6 +51,7 @@ export default class AppStore extends Lightning.Component { } catch (error) { this.ERR("Failed to get App Catalog Info:" + JSON.stringify(error)) } + Catalog.sort((a, b) => (a.name || '').localeCompare(b.name || '')) this.tag('Catalog').add(Catalog.map((element) => { return { h: AppCatalogItem.height + 90, w: AppCatalogItem.width, info: element } })); From 692365c8525f7cc309810fa8b8dd9ce7567cd705 Mon Sep 17 00:00:00 2001 From: suryag23 Date: Thu, 26 Mar 2026 17:15:33 +0530 Subject: [PATCH 15/35] Addressed the review comments --- accelerator-home-ui/src/App.js | 2 +- .../overlays/OtherSettings/LanguageScreenOverlay.js | 9 ++------- .../screens/OtherSettingsScreens/LanguageScreen.js | 11 +---------- .../src/screens/SplashScreens/LanguageScreen.js | 3 --- 4 files changed, 4 insertions(+), 21 deletions(-) diff --git a/accelerator-home-ui/src/App.js b/accelerator-home-ui/src/App.js index dce4069..9756e8f 100644 --- a/accelerator-home-ui/src/App.js +++ b/accelerator-home-ui/src/App.js @@ -2144,7 +2144,7 @@ export default class App extends Router.App { Router.navigate('menu'); } else if(notification.newState === PowerState.POWER_STATE_LIGHT_SLEEP && notification.currentState === PowerState.POWER_STATE_DEEP_SLEEP){ - appApi.setPowerState("ON").then(res => { + appApi.setPowerState(PowerState.POWER_STATE_ON).then(res => { this.LOG("Device woke up from DEEP_SLEEP to LIGHT_SLEEP . setPowerState result: " + JSON.stringify(res)) }).catch(err => { this.ERR("Failed to set power state to ON when device woke up from DEEP_SLEEP to LIGHT_SLEEP. Error: " + JSON.stringify(err)) diff --git a/accelerator-home-ui/src/overlays/OtherSettings/LanguageScreenOverlay.js b/accelerator-home-ui/src/overlays/OtherSettings/LanguageScreenOverlay.js index a4bee32..b44ebf0 100644 --- a/accelerator-home-ui/src/overlays/OtherSettings/LanguageScreenOverlay.js +++ b/accelerator-home-ui/src/overlays/OtherSettings/LanguageScreenOverlay.js @@ -20,15 +20,10 @@ import { Language, Lightning } from '@lightningjs/sdk' import LanguageItem from '../../items/LanguageItem' import { availableLanguages, availableLanguageCodes } from '../../Config/Config' import AppApi from '../../api/AppApi'; -import RDKShellApis from '../../api/RDKShellApis'; -import thunderJS from 'ThunderJS'; -import { CONFIG, GLOBALS } from '../../Config/Config' -import { Metrics } from '@firebolt-js/sdk'; -import FireBoltApi from '../../api/firebolt/FireBoltApi'; + + const appApi = new AppApi() -const thunder = thunderJS(CONFIG.thunderConfig) -const loader = 'Loader' export default class LanguageScreen extends Lightning.Component { constructor(...args) { diff --git a/accelerator-home-ui/src/screens/OtherSettingsScreens/LanguageScreen.js b/accelerator-home-ui/src/screens/OtherSettingsScreens/LanguageScreen.js index 8cfeeab..322ca3f 100644 --- a/accelerator-home-ui/src/screens/OtherSettingsScreens/LanguageScreen.js +++ b/accelerator-home-ui/src/screens/OtherSettingsScreens/LanguageScreen.js @@ -20,16 +20,12 @@ import { Language, Lightning, Router } from '@lightningjs/sdk' import LanguageItem from '../../items/LanguageItem' import { availableLanguages, availableLanguageCodes, CONFIG } from '../../Config/Config' import AppApi from '../../api/AppApi'; -import RDKShellApis from '../../api/RDKShellApis'; import AlexaApi from '../../api/AlexaApi'; import thunderJS from 'ThunderJS'; -import { GLOBALS } from '../../Config/Config' -import FireBoltApi from '../../api/firebolt/FireBoltApi'; -import { Metrics } from '@firebolt-js/manage-sdk'; + const appApi = new AppApi() const thunder = thunderJS(CONFIG.thunderConfig) -const loader = 'Loader' export default class LanguageScreen extends Lightning.Component { @@ -77,11 +73,6 @@ export default class LanguageScreen extends Lightning.Component { } _active() { - if ("ResidentApp" !== GLOBALS.selfClientName) { - this.OnLanguageChangedfirebolt = FireBoltApi.get().localization.listen("languageChanged", value => { - this.LOG('language changed successfully' + JSON.stringify(value)) - }) - } this._Languages = this.tag('LanguageScreenContents.Languages') this._Languages.h = availableLanguages.length * 90 this._Languages.tag('List').h = availableLanguages.length * 90 diff --git a/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js b/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js index b1c0726..ed43b85 100644 --- a/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js +++ b/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js @@ -22,11 +22,8 @@ import { CONFIG, GLOBALS } from '../../Config/Config' import LanguageItem from '../../items/LanguageItem' import { availableLanguages, availableLanguageCodes } from '../../Config/Config' import AppApi from '../../api/AppApi' -import RDKShellApis from '../../api/RDKShellApis' -import FireBoltApi from '../../api/firebolt/FireBoltApi' const appApi = new AppApi() -const loader = 'Loader' export default class LanguageScreen extends Lightning.Component { constructor(...args) { From ebd8a03c71d67f0e742253564cca579ef7da62f6 Mon Sep 17 00:00:00 2001 From: suryag23 Date: Thu, 26 Mar 2026 17:26:37 +0530 Subject: [PATCH 16/35] Addressed the review comments --- accelerator-home-ui/src/App.js | 8 ++++---- .../src/screens/SplashScreens/LanguageScreen.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/accelerator-home-ui/src/App.js b/accelerator-home-ui/src/App.js index 9756e8f..6a10881 100644 --- a/accelerator-home-ui/src/App.js +++ b/accelerator-home-ui/src/App.js @@ -255,8 +255,8 @@ export default class App extends Router.App { _captureKey(key) { this.LOG("Got keycode : " + JSON.stringify(key.keyCode)) this.LOG("powerState ===>" + JSON.stringify(GLOBALS.powerState)) - if (GLOBALS.powerState !== "ON") { - appApi.setPowerState("ON").then(res => { + if (GLOBALS.powerState !== PowerState.POWER_STATE_ON) { + appApi.setPowerState(PowerState.POWER_STATE_ON).then(res => { res ? this.LOG("successfully set the power state to ON from " + JSON.stringify(GLOBALS.powerState)) : this.LOG("Failure while turning ON the device") GLOBALS.powerState = PowerState.POWER_STATE_ON; this.LOG("powerState after ===>" + JSON.stringify(GLOBALS.powerState)) @@ -2132,7 +2132,7 @@ export default class App extends Router.App { appApi.getPowerState().then(res => { GLOBALS.powerState = res ? res.currentState : notification.newState }).catch(e => GLOBALS.powerState = notification.newState) - if (notification.newState !== "ON" && notification.currentState === "ON") { + if (notification.newState !== PowerState.POWER_STATE_ON && notification.currentState === PowerState.POWER_STATE_ON) { this.LOG("onPowerModeChanged Notification: power state was changed from ON to " + JSON.stringify(notification.newState)) //TURNING OFF THE DEVICE @@ -2150,7 +2150,7 @@ export default class App extends Router.App { this.ERR("Failed to set power state to ON when device woke up from DEEP_SLEEP to LIGHT_SLEEP. Error: " + JSON.stringify(err)) }) } - else if (notification.newState === "ON" && notification.currentState !== "ON") { + else if (notification.newState === PowerState.POWER_STATE_ON && notification.currentState !== PowerState.POWER_STATE_ON) { //TURNING ON THE DEVICE Storage.remove(SLEEP_STATE) } diff --git a/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js b/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js index ed43b85..f6cd056 100644 --- a/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js +++ b/accelerator-home-ui/src/screens/SplashScreens/LanguageScreen.js @@ -17,8 +17,8 @@ * limitations under the License. **/ -import { Lightning, Router, Language, Storage } from '@lightningjs/sdk' -import { CONFIG, GLOBALS } from '../../Config/Config' +import { Lightning, Router, Language } from '@lightningjs/sdk' +import { CONFIG } from '../../Config/Config' import LanguageItem from '../../items/LanguageItem' import { availableLanguages, availableLanguageCodes } from '../../Config/Config' import AppApi from '../../api/AppApi' From da695ef5bf5c1f2894faabba44aac9d8db055337 Mon Sep 17 00:00:00 2001 From: Adam Stolcenburg Date: Thu, 26 Mar 2026 20:14:30 +0100 Subject: [PATCH 17/35] RDKEAPPRT-661 Add support for new authorization in App Catalog --- accelerator-home-ui/src/api/AppCatalog.js | 449 ++++++++++++++++++ accelerator-home-ui/src/api/DACApi.js | 106 +---- .../src/screens/AppCatalogLoginComponent.js | 3 + 3 files changed, 457 insertions(+), 101 deletions(-) create mode 100644 accelerator-home-ui/src/api/AppCatalog.js diff --git a/accelerator-home-ui/src/api/AppCatalog.js b/accelerator-home-ui/src/api/AppCatalog.js new file mode 100644 index 0000000..0a65a5d --- /dev/null +++ b/accelerator-home-ui/src/api/AppCatalog.js @@ -0,0 +1,449 @@ +/** + * If not stated otherwise in this file or this component's LICENSE + * file the following copyright and licenses apply: + * + * Copyright 2026 RDK Management + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + **/ + +import PackageManager from './PackageManagerApi'; +import AppApi from './AppApi'; + +const APP_DEFAULT_ARCH = "arm"; +const APP_STORE_RFC_KEY = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.DAC.ConfigURL"; + +const debug = false; + +let appCatalogHandler = null; + +export const eventTarget = new EventTarget(); + +export class AuthNeeded extends Event { + static eventName = 'authNeeded'; + + constructor() { + super(AuthNeeded.eventName); + } +} + +export class RefreshNeeded extends Event { + static eventName = 'refreshNeeded'; + + constructor() { + super(RefreshNeeded.eventName); + } +} + +class AuthExpiredError extends Error { + constructor(url) { + super(`Authentication expired (${url})`); + this.name = 'AuthExpiredError'; + } +} + +class PromiseQueue { + constructor() { + this.next = Promise.resolve(); + } + + enqueue(fn) { + let unlock; + const next = new Promise(resolve => { unlock = resolve; }); + const result = this.next.then(fn); + result.then(unlock, unlock); + this.next = next; + return result; + } +} + +async function getConfigUrlFromRFC() { + try { + const appApi = new AppApi(); + console.log("Resolving config URL from RFC "); + const result = await appApi.getRFCConfig(APP_STORE_RFC_KEY); + const rfcUrl = result?.RFCConfig?.[APP_STORE_RFC_KEY]; + if (typeof rfcUrl === "string" && rfcUrl.trim().length > 0) { + const resolvedConfigUrl = rfcUrl.trim(); + console.log("Resolved config URL from RFC "); + return resolvedConfigUrl; + } + console.warn("Config RFC URL empty or invalid"); + return null; + } catch (err) { + console.error("Failed to get config URL from RFC", err); + return null; + } +} + +async function getConfigUrlFromPackageManager() { + try { + console.log("Resolving config URL from PackageManager..."); + const config = await PackageManager.get().configuration(); + console.log("Resolved server config URL from PackageManager: "); + if (typeof config?.configUrl !== "string" || config.configUrl.trim().length === 0) { + throw new Error("Invalid config: " + JSON.stringify(config)); + } + + return config.configUrl.trim(); + } catch (err) { + console.error("Failed to resolve config URL from PackageManager", err); + throw err; + } +} + +let serverURL = null; +let serverURLPromise = null; + +async function getServerURL() { + if (!serverURL) { + if (!serverURLPromise) { + async function resolve() { + let url = await getConfigUrlFromRFC(); + + if (!url) { + url = await getConfigUrlFromPackageManager(); + } + console.log(`Server URL: ${url}`); + return url; + } + + serverURLPromise = resolve(); + } + + try { + serverURL = await serverURLPromise; + } catch (err) { + serverURLPromise = null; + throw err; + } + } + + return serverURL; +} + +class StubAppCatalogHandler { + getApps(offset, limit) { + return { applications: [] }; + } + + getAppDetails(id, version) { + throw new Error('getAppDetails() is not supported'); + } + + makeDownloadURL(url) { + throw new Error('makeDownloadURL() is not supported'); + } +} + +class LegacyAppCatalogHandler { + constructor(configURL) { + this.configURL = configURL; + this.storeConfig = null; + } + + async getStoreConfig() { + if (!this.storeConfig) { + let resolvedConfigUrl = this.configURL; + + const fetchResponse = await fetch(resolvedConfigUrl); + if (!fetchResponse.ok) { + throw new Error(`Unexpected response: ${fetchResponse.status}: ${fetchResponse.statusText}`); + } + const responseObject = await fetchResponse.json(); + + if (typeof responseObject?.["appstore-catalog"]?.url !== "string") { + throw new Error("Invalid response object: " + JSON.stringify(responseObject)); + } + const catalog = responseObject["appstore-catalog"]; + this.storeConfig = { url: catalog.url }; + + if (typeof catalog?.authentication?.user === "string" && + typeof catalog?.authentication?.password === "string") { + this.storeConfig.authHeader = + "Basic " + btoa(catalog.authentication.user + ':' + catalog.authentication.password); + } + } + + return this.storeConfig; + } + + async fetchStoreObject(request) { + let config = await this.getStoreConfig(); + let headers = new Headers(); + + if (config.authHeader) { + headers.append("Authorization", config.authHeader); + } + + let requestOptions = { + method: 'GET', + headers, + redirect: 'follow', + }; + + const fetchResponse = await fetch(config.url + request, requestOptions); + if (!fetchResponse.ok) { + throw new Error(`Unexpected response: ${fetchResponse.status}: ${fetchResponse.statusText}`); + } + + return fetchResponse.json(); + } + + getAppDetails(id, version) { + return this.fetchStoreObject("/apps/" + id + ":" + version + "?arch=" + APP_DEFAULT_ARCH); + } + + async getApps(offset, limit) { + const request = "/apps?arch=" + APP_DEFAULT_ARCH + "&offset=" + offset + "&limit=" + limit; + + try { + return await this.fetchStoreObject(request); + } catch (err) { + console.error(`fetchStoreObject(${request}) ${err}`); + throw err; + } + } + + makeDownloadURL(url) { + return url; + } +} + +class AppCatalogHandler { + constructor(serverURL) { + this.serverURL = serverURL; + this.authURL = this.serverURL + '/auth'; + this.appCatalogURL = this.serverURL + '/appcatalog'; + this.timerId = null; + this.queue = new PromiseQueue(); + } + + async fetch(url, options) { + const response = await this.queue.enqueue(() => fetch(url, { credentials: 'include', ...options })); + if (response.status === 401 || response.status === 403) { + this.cancelRefresh(); + throw new AuthExpiredError(url); + } + if (!response.ok) { + throw new Error(`Unexpected response: ${response.status}: ${response.statusText} (${url})`); + } + return response; + } + + async postAuthObject(request, obj) { + let options = { + method: 'POST', + headers: { + 'Content-Type': 'application/json' + }, + redirect: 'follow', + body: JSON.stringify(obj), + }; + + const url = this.authURL + request; + const response = await this.fetch(url, options); + const responseObj = await response.json(); + if (debug) { + console.log(`Auth response: ${JSON.stringify(responseObj, null, 2)}`); + } + return responseObj; + } + + calculateTimeout(expiresIn) { + const MIN = 60; + const MAX = 4 * 60 * 60; // 4 hours + + let timeout = Math.min(Math.max(expiresIn / 2, MIN), MAX); + + if (debug) { + console.log(`Calculated timeout: ${timeout}`); + } + + return timeout * 1000; + } + + scheduleRefresh(response, onAuthExpired) { + if (typeof response.expiresIn !== "number") { + return; + } + const expiresIn = response.expiresIn; + + this.cancelRefresh(); + + this.timerId = setTimeout(async () => { + this.timerId = null; + try { + const refreshResponse = await this.refresh(); + this.scheduleRefresh(refreshResponse, onAuthExpired); + } catch (err) { + console.warn(`Refresh failed: ${err}`); + onAuthExpired(); + } + }, this.calculateTimeout(expiresIn)); + } + + cancelRefresh() { + if (this.timerId) { + clearTimeout(this.timerId); + this.timerId = null; + } + } + + async refresh() { + return this.postAuthObject('/refresh', {}); + } + + async login(user, pass) { + this.cancelRefresh(); + return this.postAuthObject('/login', { username: user, password: pass }); + } + + async fetchAppCatalogObject(request) { + const url = this.appCatalogURL + request; + const fetchResponse = await this.fetch(url, { method: 'GET', redirect: 'follow' }); + const result = await fetchResponse.json(); + if (debug) { + console.log(`${url} : ${JSON.stringify(result, null, 2)}`); + } + return result; + } + + async getAppDetails(id, version) { + return this.fetchAppCatalogObject("/apps/" + id + ":" + version + "?arch=" + APP_DEFAULT_ARCH); + } + + async getApps(offset, limit) { + const request = "/apps?arch=" + APP_DEFAULT_ARCH + "&offset=" + offset + "&limit=" + limit; + + try { + return await this.fetchAppCatalogObject(request); + } catch (err) { + console.error(`fetchAppCatalogObject(${request}) ${err}`); + throw err; + } + } + + async getServiceToken(token) { + const url = this.authURL + "/servicetokens/" + token; + const response = await this.fetch(url, { method: 'GET', redirect: 'follow' }); + const result = await response.json(); + if (debug) { + console.log(`${url}: ${JSON.stringify(result, null, 2)}`); + } + return result; + } + + async makeDownloadURL(url) { + const token = await this.getServiceToken('download-manager'); + const downloadURL = new URL(url); + downloadURL.searchParams.set('token', token.token); + return downloadURL.toString(); + } +} + +let initPromise = null; + +function handleAuthExpired(handler) { + if (appCatalogHandler === handler) { + appCatalogHandler = new StubAppCatalogHandler(); + eventTarget.dispatchEvent(new AuthNeeded()); + } +} + +async function callAndHandleAuthExpired(handler, fn) { + try { + return await fn(); + } catch (err) { + if (err instanceof AuthExpiredError) { + handleAuthExpired(handler); + } + throw err; + } +} + +async function initAppCatalogHandler() { + if (!initPromise) { + async function init() { + appCatalogHandler = new StubAppCatalogHandler(); + + try { + const url = await getServerURL(); + + if (url.endsWith('/cpe.json')) { + appCatalogHandler = new LegacyAppCatalogHandler(url); + return; + } + + const handler = new AppCatalogHandler(url); + const refreshResponse = await handler.refresh(); + handler.scheduleRefresh(refreshResponse, () => handleAuthExpired(handler)); + appCatalogHandler = handler; + } catch (err) { + console.log(`initAppCatalogHandler() ${err}`); + if (err instanceof AuthExpiredError) { + eventTarget.dispatchEvent(new AuthNeeded()); + } else { + throw err; + } + } + } + + initPromise = init().catch(() => { + initPromise = null; + }); + } + return initPromise; +} + +export async function isLoggedIn() { + await initAppCatalogHandler(); + return appCatalogHandler instanceof AppCatalogHandler; +} + +export async function login(user, pass) { + await initAppCatalogHandler(); + + const handler = appCatalogHandler instanceof AppCatalogHandler + ? appCatalogHandler + : new AppCatalogHandler(await getServerURL()); + + try { + const loginResponse = await handler.login(user, pass); + appCatalogHandler = handler; + handler.scheduleRefresh(loginResponse, () => handleAuthExpired(handler)); + eventTarget.dispatchEvent(new RefreshNeeded()); + return true; + } catch (err) { + console.warn(`Login failed: ${err}`); + return false; + } +} + +export async function getApps(offset, limit) { + await initAppCatalogHandler(); + const handler = appCatalogHandler; + return callAndHandleAuthExpired(handler, () => handler.getApps(offset, limit)); +} + +export async function getAppDetails(id, version) { + await initAppCatalogHandler(); + const handler = appCatalogHandler; + return callAndHandleAuthExpired(handler, () => handler.getAppDetails(id, version)); +} + +export async function makeDownloadURL(url) { + await initAppCatalogHandler(); + const handler = appCatalogHandler; + return callAndHandleAuthExpired(handler, () => handler.makeDownloadURL(url)); +} diff --git a/accelerator-home-ui/src/api/DACApi.js b/accelerator-home-ui/src/api/DACApi.js index 3ab198c..79766e0 100644 --- a/accelerator-home-ui/src/api/DACApi.js +++ b/accelerator-home-ui/src/api/DACApi.js @@ -20,11 +20,11 @@ import DownloadManager from './DownloadManagerApi'; import PackageManager from './PackageManagerApi'; import AppManager from './AppManagerApi'; -import AppApi from './AppApi'; import AppController from '../AppController'; import { ThunderError } from './ThunderError'; import { Metrics } from '@firebolt-js/sdk' import { SIDELOADED_APP_DEFAULT_ICON, deriveNameFromPackageId } from '../helpers/DACAppPresentation' +import { getApps, getAppDetails, makeDownloadURL } from './AppCatalog'; // the size that is assumed if it is not possible to retrieve package size // from the server, according to server API this should never happen @@ -37,10 +37,6 @@ const APPS_REQUESTS_MAX = 5; const APP_DETAILS_KEY = "refui.details"; -const APP_DEFAULT_ARCH = "arm"; - -const APP_STORE_RFC_KEY = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.DAC.ConfigURL"; - function makeLogMessage(call, err) { return err.toString() + " <=> " + call; } @@ -72,112 +68,23 @@ class OperationLock { }; let packageLock = new OperationLock(); -let storeConfig = null; - -async function getConfigUrlFromRFC() { - try { - const appApi = new AppApi(); - console.log("Resolving DAC Store URL from RFC "); - const result = await appApi.getRFCConfig(APP_STORE_RFC_KEY); - const rfcUrl = result?.RFCConfig?.[APP_STORE_RFC_KEY]; - if (typeof rfcUrl === "string" && rfcUrl.trim().length > 0) { - const resolvedConfigUrl = rfcUrl.trim(); - console.log("Resolved DAC Store URL from RFC "); - return resolvedConfigUrl; - } - console.warn("DAC Store RFC URL empty or invalid"); - return null; - } catch (err) { - console.error("Failed to get DAC Store URL from RFC", err); - return null; - } -} - -async function getConfigUrlFromPackageManager() { - try { - console.log("Resolving DAC Store URL from PackageManager..."); - const config = await PackageManager.get().configuration(); - console.log("Resolved DAC Store URL from PackageManager: "); - if (typeof config?.configUrl !== "string" || config.configUrl.trim().length === 0) { - throw new Error("Invalid config: " + JSON.stringify(config)); - } - - return config.configUrl.trim(); - } catch (err) { - console.error("Failed to resolve DAC Store URL from PackageManager", err); - throw err; - } -} - -async function getStoreConfig() { - if (!storeConfig) { - console.log("Resolving DAC Store config URL..."); - let resolvedConfigUrl = await getConfigUrlFromRFC(); - - if (!resolvedConfigUrl) { - resolvedConfigUrl = await getConfigUrlFromPackageManager(); - } - - console.log("Resolved DAC Store config URL "); - const fetchResponse = await fetch(resolvedConfigUrl); - if (!fetchResponse.ok) { - throw new Error(`Unexpected response: ${fetchResponse.status}: ${fetchResponse.statusText}`); - } - const responseObject = await fetchResponse.json(); - if (typeof responseObject?.["appstore-catalog"]?.url !== "string") { - throw new Error("Invalid response object: " + JSON.stringify(responseObject)); - } - storeConfig = responseObject["appstore-catalog"]; - } - - return storeConfig; -} - -async function fetchStoreObject(request) { - let config = await getStoreConfig(); - let headers = new Headers(); - - if (typeof config?.authentication?.user === "string" && - typeof config?.authentication?.password === "string") { - headers.append( - "Authorization", - "Basic " + btoa(config.authentication.user + ':' + config.authentication.password) - ); - } - - let requestOptions = { - method: 'GET', - headers, - redirect: 'follow', - }; - - const fetchResponse = await fetch(config.url + request, requestOptions); - if (!fetchResponse.ok) { - throw new Error(`Unexpected response: ${fetchResponse.status}: ${fetchResponse.statusText}`); - } - - return fetchResponse.json(); -} export async function getAppCatalogInfo() { let result = []; let offset = 0; for (let i = 0; i < APPS_REQUESTS_MAX; ++i) { - const request = "/apps?arch=" + APP_DEFAULT_ARCH + "&offset=" + offset + "&limit=" + APPS_REQUEST_LIMIT; - console.log(`Requesting: ${request}`); try { - const appsResponse = await fetchStoreObject(request); + const appsResponse = await getApps(offset, APPS_REQUEST_LIMIT); if (!Array.isArray(appsResponse?.applications)) { break; } result = result.concat(appsResponse.applications); - if (result.length >= appsResponse?.meta?.resultSet?.total ?? 0) { + if (result.length >= (appsResponse?.meta?.resultSet?.total ?? 0)) { break; } offset = result.length; } catch (err) { - console.error(`fetch(${request}) ${err}`); Metrics.error(Metrics.ErrorType.OTHER, "DACApiError", err.toString(), false, null); break; } @@ -186,10 +93,6 @@ export async function getAppCatalogInfo() { return result; } -function getAppDetails(id, version) { - return fetchStoreObject("/apps/" + id + ":" + version + "?arch=" + APP_DEFAULT_ARCH); -} - function retrieveURLAndSize(details) { if (typeof details?.header?.url === "string") { const url = details.header.url; @@ -223,7 +126,8 @@ async function downloadAndInstall(pkg, downloadedSize, totalSize, progress) { const downloadId = await new Promise(async (resolve, reject) => { try { - await DownloadManager.get().download(pkg.url, (downloadId, percent, failReason) => { + const downloadURL = await makeDownloadURL(pkg.url); + await DownloadManager.get().download(downloadURL, (downloadId, percent, failReason) => { if (!failReason) { if (percent !== 100) { progress((downloadedSize + pkg.size * percent / 100) / totalSize, "Downloading"); diff --git a/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js b/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js index 509f3dc..fb8697f 100644 --- a/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js +++ b/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js @@ -21,6 +21,7 @@ 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'; export default class AppCatalogLoginComponent extends Lightning.Component { @@ -52,6 +53,8 @@ export default class AppCatalogLoginComponent extends Lightning.Component { } else { this.LOG('App Catalog Login - credentials submitted') + login(this.textCollection['EnterUsername'], this.textCollection['EnterPassword']) + .then(result => console.log(result ? 'Login successful' : 'Login failed')) } } From e7726279d8fcc66ab9d76072394ba7df2afe9733 Mon Sep 17 00:00:00 2001 From: suryag23 Date: Fri, 27 Mar 2026 16:22:33 +0530 Subject: [PATCH 18/35] RDKEAPPRT-646 Reload app catalog data after login --- accelerator-home-ui/src/api/AppCatalog.js | 2 +- .../src/screens/AppCatalogLoginComponent.js | 12 +++++++++- accelerator-home-ui/src/views/AppStore.js | 23 ++++++++++++++++++- accelerator-home-ui/src/views/MainView.js | 11 +++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/accelerator-home-ui/src/api/AppCatalog.js b/accelerator-home-ui/src/api/AppCatalog.js index 0a65a5d..9256ae6 100644 --- a/accelerator-home-ui/src/api/AppCatalog.js +++ b/accelerator-home-ui/src/api/AppCatalog.js @@ -23,7 +23,7 @@ import AppApi from './AppApi'; const APP_DEFAULT_ARCH = "arm"; const APP_STORE_RFC_KEY = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.DAC.ConfigURL"; -const debug = false; +const debug = true; let appCatalogHandler = null; diff --git a/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js b/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js index fb8697f..a6e1fa0 100644 --- a/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js +++ b/accelerator-home-ui/src/screens/AppCatalogLoginComponent.js @@ -54,7 +54,17 @@ export default class AppCatalogLoginComponent extends Lightning.Component { else { this.LOG('App Catalog Login - credentials submitted') login(this.textCollection['EnterUsername'], this.textCollection['EnterPassword']) - .then(result => console.log(result ? 'Login successful' : 'Login failed')) + .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)) } } diff --git a/accelerator-home-ui/src/views/AppStore.js b/accelerator-home-ui/src/views/AppStore.js index 774392a..47608ec 100644 --- a/accelerator-home-ui/src/views/AppStore.js +++ b/accelerator-home-ui/src/views/AppStore.js @@ -3,6 +3,7 @@ import { Grid } from "@lightningjs/ui"; import { CONFIG } from "../Config/Config"; import AppCatalogItem from "../items/AppCatalogItem"; import { getAppCatalogInfo } from "../api/DACApi" +import { eventTarget, RefreshNeeded } from '../api/AppCatalog' export default class AppStore extends Lightning.Component { @@ -44,20 +45,39 @@ export default class AppStore extends Lightning.Component { } } - async _firstEnable() { + _firstEnable() { + this._onRefreshNeeded = () => { + this.LOG('RefreshNeeded event received - reloading catalog') + this._loadCatalog() + } + eventTarget.addEventListener(RefreshNeeded.eventName, this._onRefreshNeeded) + } + + async _loadCatalog() { let Catalog = [] try { Catalog = await getAppCatalogInfo() } catch (error) { this.ERR("Failed to get App Catalog Info:" + JSON.stringify(error)) } + if (!Array.isArray(Catalog) || Catalog.length === 0) { + this.LOG('No apps available in catalog') + return + } Catalog.sort((a, b) => (a.name || '').localeCompare(b.name || '')) + this.tag('Catalog').clear() this.tag('Catalog').add(Catalog.map((element) => { return { h: AppCatalogItem.height + 90, w: AppCatalogItem.width, info: element } })); this._setState('Catalog') } + _detach() { + if (this._onRefreshNeeded) { + eventTarget.removeEventListener(RefreshNeeded.eventName, this._onRefreshNeeded) + } + } + _handleLeft() { @@ -76,6 +96,7 @@ export default class AppStore extends Lightning.Component { } _focus() { + this._loadCatalog() this._setState('Catalog') } diff --git a/accelerator-home-ui/src/views/MainView.js b/accelerator-home-ui/src/views/MainView.js index b70b891..7f4393f 100644 --- a/accelerator-home-ui/src/views/MainView.js +++ b/accelerator-home-ui/src/views/MainView.js @@ -32,6 +32,7 @@ import NetworkManager from '../api/NetworkManagerAPI.js' import { getAppCatalogInfo, getInstalledDACApps, startDACApp } from '../api/DACApi.js' import { filterExcludedApps } from '../helpers/DACAppPresentation.js' import AppController from '../AppController.js' +import { eventTarget, RefreshNeeded } from '../api/AppCatalog.js' /** Class for main view component in home UI */ export default class MainView extends Lightning.Component { @@ -458,6 +459,13 @@ export default class MainView extends Lightning.Component { } AppController.get().addPackageChangedListener(this._onPackageChanged) + // Refresh DAC apps row when app catalog authentication changes + this._onCatalogRefreshNeeded = () => { + this.LOG('RefreshNeeded event received - refreshing DAC apps row') + this.refreshSecondRow() + } + eventTarget.addEventListener(RefreshNeeded.eventName, this._onCatalogRefreshNeeded) + this.dacApps = dacCatalog this.fireAncestors("$mountEventConstructor", registerListener.bind(this)) @@ -469,6 +477,9 @@ export default class MainView extends Lightning.Component { _detach() { // Unsubscribe to avoid stale references to this MainView instance AppController.get().removePackageChangedListener(this._onPackageChanged) + if (this._onCatalogRefreshNeeded) { + eventTarget.removeEventListener(RefreshNeeded.eventName, this._onCatalogRefreshNeeded) + } } _firstActive() { From 90f4f8cce30ccb2a2b9d65b9aaedaf74741e2d25 Mon Sep 17 00:00:00 2001 From: yashaswini-rk Date: Mon, 30 Mar 2026 16:43:51 -0400 Subject: [PATCH 19/35] RDKEAPPRT-646 Reload app catalog data after login - Disable debug logging --- accelerator-home-ui/src/api/AppCatalog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accelerator-home-ui/src/api/AppCatalog.js b/accelerator-home-ui/src/api/AppCatalog.js index 9256ae6..0a65a5d 100644 --- a/accelerator-home-ui/src/api/AppCatalog.js +++ b/accelerator-home-ui/src/api/AppCatalog.js @@ -23,7 +23,7 @@ import AppApi from './AppApi'; const APP_DEFAULT_ARCH = "arm"; const APP_STORE_RFC_KEY = "Device.DeviceInfo.X_RDKCENTRAL-COM_RFC.DAC.ConfigURL"; -const debug = true; +const debug = false; let appCatalogHandler = null; From 629ff83e2338e233c40492d4153107cdd4b41156 Mon Sep 17 00:00:00 2001 From: yashaswini-rk Date: Tue, 31 Mar 2026 16:05:51 -0400 Subject: [PATCH 20/35] RDKEAPPRT-677 Changelog and package config/version updates for 6.0.0 Signed-off-by: yashaswini-rk --- CHANGELOG.md | 21 +++++++++++++++++++ accelerator-home-ui/settings.json | 2 +- .../package-configs/com.rdkcentral.refui.json | 8 +++---- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index de3f7df..3158b91 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,33 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [6.0.0](https://github.com/rdkcentral/rdke-refui/compare/5.0.24...6.0.0) + +- To refresh the App store and main view when the authentication done [`#166`](https://github.com/rdkcentral/rdke-refui/pull/166) +- RDKEAPPRT-661 Add support for new authorization in App Catalog [`#165`](https://github.com/rdkcentral/rdke-refui/pull/165) +- RDKEAPPRT-621,606,648,644 fix for Language screen and powerstate issue [`#164`](https://github.com/rdkcentral/rdke-refui/pull/164) +- RDKEAPPRT-646 Create the Username, Password page and add it inside the settings route [`#163`](https://github.com/rdkcentral/rdke-refui/pull/163) +- RDKEAPPRT-645 Add default error overlay when user tries to enter VOD content [`#162`](https://github.com/rdkcentral/rdke-refui/pull/162) +- RDKEAPPRT-612 :Add dac store details via RFC [`#160`](https://github.com/rdkcentral/rdke-refui/pull/160) +- RDKEAPPRT-626,627,628,605,608,622 Fix error and uninstall overlay screen with bug fixes [`#161`](https://github.com/rdkcentral/rdke-refui/pull/161) +- RDKEAPPRT-601,602 App side loading and App side loading and closeApp() function [`#158`](https://github.com/rdkcentral/rdke-refui/pull/158) +- To merge the changes from Feature/app managers to develop [`#157`](https://github.com/rdkcentral/rdke-refui/pull/157) +- RDKEAPPRT-576 Improve focus management [`#155`](https://github.com/rdkcentral/rdke-refui/pull/155) +- RDKEAPPRT-341 App managers intake: abstractions, API migration and YouTube Launch Support [`#146`](https://github.com/rdkcentral/rdke-refui/pull/146) +- RDKEAPPRT-571 Create UI prototype with My Apps, Recommended Apps, VOD Rows and Appinfo (#156) [`eff1a86`](https://github.com/rdkcentral/rdke-refui/commit/eff1a864e55c28ed1c542e26f818d20f082a6dca) +- RDKEAPPRT-538 Add basic integration with the RDK Reference DAC 2.0 App Store (#152) [`82eda3d`](https://github.com/rdkcentral/rdke-refui/commit/82eda3d7b34b80be63bdf3d0cb39d6c3f7f1f681) +- Changes for the error and uninstall overlay screen then some bug fixes also part of this [`749f89d`](https://github.com/rdkcentral/rdke-refui/commit/749f89d0af61e7aab7d96cb70a392e4efb8f8020) + #### [5.0.24](https://github.com/rdkcentral/rdke-refui/compare/5.0.20...5.0.24) +> 12 February 2026 + +- RDKEAPPRT-575 [RDKUI] 5.0.24 Merge latest changes from develop to main, create release tag, and publish release. [`#154`](https://github.com/rdkcentral/rdke-refui/pull/154) - RDKEAPPRT-268 [RDK UI] Replace deprecated APIs for USB Media Device [`#153`](https://github.com/rdkcentral/rdke-refui/pull/153) - RDKEAPPRT-394 Adopt to New APIs for deprecated ones if not yet [`#151`](https://github.com/rdkcentral/rdke-refui/pull/151) - RDKEAPPRT-533-[RDK UI] Device is not discovered via DIAL after re-enabling Local Device Discovery option [`#150`](https://github.com/rdkcentral/rdke-refui/pull/150) - RDKEAPPRT-518 All SSIDs are not visible in FTI SSID selection screen [`#149`](https://github.com/rdkcentral/rdke-refui/pull/149) +- RDKEAPPRT-575 Changelog updates for 5.0.24 [`59d8252`](https://github.com/rdkcentral/rdke-refui/commit/59d8252ac9401f7882716fc5c055346653004996) - Merge tag '5.0.20' into develop [`4413c1c`](https://github.com/rdkcentral/rdke-refui/commit/4413c1cf7d14b54c8952299b291a44f311d7033e) #### [5.0.20](https://github.com/rdkcentral/rdke-refui/compare/5.0.17...5.0.20) diff --git a/accelerator-home-ui/settings.json b/accelerator-home-ui/settings.json index b73ffb3..2c24f86 100644 --- a/accelerator-home-ui/settings.json +++ b/accelerator-home-ui/settings.json @@ -13,6 +13,6 @@ "log": true, "enableAppSuspended": true, "showVersion": false, - "version": "5.0.24" + "version": "6.0.0" } } diff --git a/bolt/package-configs/com.rdkcentral.refui.json b/bolt/package-configs/com.rdkcentral.refui.json index 6e1a209..1ae1208 100644 --- a/bolt/package-configs/com.rdkcentral.refui.json +++ b/bolt/package-configs/com.rdkcentral.refui.json @@ -1,12 +1,12 @@ { "id": "com.rdkcentral.refui", - "version": "0.0.1", - "versionName": "develop", + "version": "6.0.0", + "versionName": "6.0.0", "name": "RDK Ref UI Home Screen", "packageType": "application", - "entryPoint": "file:///usr/share/refui/index.html", + "entryPoint": "--lightning --dev file:///usr/share/refui/index.html", "dependencies": { - "com.rdkcentral.wpe-develop": "0.0.1" + "com.rdkcentral.wpe": "0.2.0" }, "permissions": [ "urn:rdk:permission:home-app", From c2b261ff1ea9e4e72a8750f77652d6f4261775ce Mon Sep 17 00:00:00 2001 From: yashaswini Date: Tue, 31 Mar 2026 21:29:39 +0000 Subject: [PATCH 21/35] RDKEAPPRT-680:Update the new logo files --- accelerator-home-ui/static/images/RDKLogo.png | Bin 16213 -> 10347 bytes .../static/images/splash/RDKLogo.png | Bin 14231 -> 10347 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/accelerator-home-ui/static/images/RDKLogo.png b/accelerator-home-ui/static/images/RDKLogo.png index 566bb3ee71f576811d964ae5fe382abddca2d22c..045d6147da790f393134e3d4e6f767d39070c230 100644 GIT binary patch literal 10347 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

D@giENVuig7^WtvF)kAS!CL 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 diff --git a/accelerator-home-ui/static/images/splash/RDKLogo.png b/accelerator-home-ui/static/images/splash/RDKLogo.png index 63669f85ef69ac61b06c0617fa09a0463cf0f09a..045d6147da790f393134e3d4e6f767d39070c230 100644 GIT binary patch literal 10347 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

D@giENVuig7^WtvF)kAS!CL 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 From 83513d8d0566d994927583ed7891c655660af97f Mon Sep 17 00:00:00 2001 From: yashaswini Date: Wed, 1 Apr 2026 02:28:41 +0000 Subject: [PATCH 22/35] RDKEAPPRT-680 :Update new logo --- accelerator-home-ui/static/images/RDKLogo.png | Bin 10347 -> 10835 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/accelerator-home-ui/static/images/RDKLogo.png b/accelerator-home-ui/static/images/RDKLogo.png index 045d6147da790f393134e3d4e6f767d39070c230..d73e15226a4981f76a520e2a68f61e3383eb48b3 100644 GIT binary patch literal 10835 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

D@giENVuig7^WtvF)kAS!CL zesGST=s0o+bQ*!8A@%SgcR_Uq+2%@r7G@cSSo4#ZSvj)Pb~^z{h5)CFRO#g9Dfsvf z3UlV5Xk2}g8R^Vv4+7>D;Bf71Hss8Lzq8-;7P}0kRjsb{caFc^$hsRk zfI#=SrSOnV5dT^hy#Hg%+qai!&i5-0Mpz!fi|-G%r^iVS7y;AEe}m7@4-o2m4Nl6d zz#cC+atJsC;);MMCg;9Mkrx1BcYfCMIIJh< zp-1MqZGDFqE+iTOv*FVU&f)(AXr6=~;d@ay;scnu;6z*I^xH+Cpr9Fbb?*b-Re-Ly zs!Ua&G76#er*X(Kv+cKhq0c$~FOYD@L?O^M^$L4!gEyCRxb1ot@Mdd?Y$@E@55D{q zF`2{>fRHs^PH<-t*vkBQ3-Hchg?s`&3q6dYQOjWd*{!pZ-TkS9KuZH}(a{R`uVeTL%U5tNizUdc@h9HkBdB8rK5pF;dAAov$JZfDu}Uhw1@%w9FZIeyDX zJMo=DpljT03iv;t{urKjIuo>xY>yOSC<+ixy9IMA2HI29O(hE&09giLHgV=0txiF+ z48wqov4}LBjY$48Zd#kn`4Fs~fuFPe{HkKQcWDwY`UQ@G#|Xe$Dy zaX2ye4fxGJ<1L%W_DCTRJ>>rZ00960PNmy<00006Nkl Date: Tue, 31 Mar 2026 22:55:20 -0400 Subject: [PATCH 23/35] RDKEAPPRT-682 Changelog and package config version updates for 6.0.1 Signed-off-by: yashaswini-rk --- CHANGELOG.md | 11 ++++++++++- accelerator-home-ui/settings.json | 2 +- bolt/package-configs/com.rdkcentral.refui.json | 4 ++-- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3158b91..6afee9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,16 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). -#### [6.0.0](https://github.com/rdkcentral/rdke-refui/compare/5.0.24...6.0.0) +#### [6.0.1](https://github.com/rdkcentral/rdke-refui/compare/6.0.0...6.0.1) + +- Feature/rdkeapprt 680 :Update to new RDK logos [`#168`](https://github.com/rdkcentral/rdke-refui/pull/168) +- RDKEAPPRT-680 :Update new logo [`83513d8`](https://github.com/rdkcentral/rdke-refui/commit/83513d8d0566d994927583ed7891c655660af97f) +- RDKEAPPRT-680:Update the new logo files [`c2b261f`](https://github.com/rdkcentral/rdke-refui/commit/c2b261ff1ea9e4e72a8750f77652d6f4261775ce) +- Merge tag '6.0.0' into develop [`ff076c2`](https://github.com/rdkcentral/rdke-refui/commit/ff076c212491ba05e68f118666581d41d474f8d3) + +### [6.0.0](https://github.com/rdkcentral/rdke-refui/compare/5.0.24...6.0.0) + +> 31 March 2026 - To refresh the App store and main view when the authentication done [`#166`](https://github.com/rdkcentral/rdke-refui/pull/166) - RDKEAPPRT-661 Add support for new authorization in App Catalog [`#165`](https://github.com/rdkcentral/rdke-refui/pull/165) diff --git a/accelerator-home-ui/settings.json b/accelerator-home-ui/settings.json index 2c24f86..768f608 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.0" + "version": "6.0.1" } } diff --git a/bolt/package-configs/com.rdkcentral.refui.json b/bolt/package-configs/com.rdkcentral.refui.json index 1ae1208..b414e0e 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.0", - "versionName": "6.0.0", + "version": "6.0.1", + "versionName": "6.0.1", "name": "RDK Ref UI Home Screen", "packageType": "application", "entryPoint": "--lightning --dev file:///usr/share/refui/index.html", From 5520ae8dcd7d309d172b00fe131707bf3afe1b9b Mon Sep 17 00:00:00 2001 From: Arun Madhavan Date: Thu, 2 Apr 2026 14:32:01 -0400 Subject: [PATCH 24/35] RDKEAPPRT-683: RemoteControl plugin API align with MW APIv3.4.2 --- accelerator-home-ui/settings.json | 2 +- accelerator-home-ui/src/api/RemoteControl.js | 42 +++++++++++++++---- .../FactoryResetConfirmationScreen.js | 2 +- .../src/screens/RcInformationScreen.js | 16 +++---- .../screens/SplashScreens/BluetoothScreen.js | 16 +++---- 5 files changed, 53 insertions(+), 25 deletions(-) diff --git a/accelerator-home-ui/settings.json b/accelerator-home-ui/settings.json index 768f608..624fba0 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.1" + "version": "6.0.2" } } diff --git a/accelerator-home-ui/src/api/RemoteControl.js b/accelerator-home-ui/src/api/RemoteControl.js index 1caf9f1..158419e 100644 --- a/accelerator-home-ui/src/api/RemoteControl.js +++ b/accelerator-home-ui/src/api/RemoteControl.js @@ -92,10 +92,9 @@ export default class RCApi { }) } - startPairing(timeout = 30, netType ) { + startPairing(timeout = 30) { return new Promise((resolve, reject) => { - //this.INFO("RCApi: startPairing netType " + netType + " timeout " + timeout); - this.thunder.call('org.rdk.RemoteControl', 'startPairing', { netType: netType, timeout: timeout }).then(result => { + this.thunder.call('org.rdk.RemoteControl', 'startPairing', { timeout: timeout, screenBindEnable:false }).then(result => { //this.INFO("RCApi: startPairing result: ", JSON.stringify(result)) resolve(result.success); }).catch(err => { @@ -103,10 +102,23 @@ export default class RCApi { Metrics.error(Metrics.ErrorType.OTHER,"RemoteControlApiError", "Error in Thunder RemoteControl startPairing "+JSON.stringify(err), false, null) reject(err); }); - resolve(true); }) } + stopPairing() { + return new Promise((resolve, reject) => { + this.INFO("RCApi: stopPairing"); + this.thunder.call('org.rdk.RemoteControl', 'stopPairing', {scanDisable: true}).then(result => { + this.INFO("RCApi: stopPairing result: " + JSON.stringify(result)) + resolve(result.success); + }).catch(err => { + this.ERR("RCApi: stopPairing error: " + JSON.stringify(err)); + Metrics.error(Metrics.ErrorType.OTHER, "RemoteControlApiError", "Error in Thunder RemoteControl stopPairing " + JSON.stringify(err), false, null) + reject(err); + }); + }); + } + initializeIRDB() { return new Promise((resolve, reject) => { /*TODO: implement when requirement comes.*/ @@ -186,10 +198,10 @@ export default class RCApi { }) } - findMyRemote(netType = 1, level = "mid") { + findMyRemote(level = "mid") { return new Promise((resolve, reject) => { - this.INFO("RCApi: findMyRemote netType:" + JSON.stringify(netType) + " level:" + JSON.stringify(level)); - this.thunder.call('org.rdk.RemoteControl', 'findMyRemote', { netType: netType, level: level }).then(result => { + this.INFO("RCApi: findMyRemote level:" + JSON.stringify(level)); + this.thunder.call('org.rdk.RemoteControl', 'findMyRemote', { level: level }).then(result => { this.INFO("RCApi: findMyRemote result: " + JSON.stringify(result)) resolve(result.success); }).catch(err => { @@ -200,6 +212,8 @@ export default class RCApi { }) } + // This is to reset the remote control firmware; not to be confused with factory reset of the device. + // This will not erase user data or settings on the device. factoryReset() { return new Promise((resolve, reject) => { this.INFO("RCApi: factoryReset"); @@ -213,4 +227,18 @@ export default class RCApi { }); }) } + + unpair(macAddressList) { + return new Promise((resolve, reject) => { + this.INFO("RCApi: unpair macAddressList:" + JSON.stringify(macAddressList)); + this.thunder.call('org.rdk.RemoteControl', 'unpair', { macAddressList: macAddressList }).then(result => { + this.INFO("RCApi: unpair result: " + JSON.stringify(result)) + resolve(result.success); + }).catch(err => { + this.ERR("RCApi: unpair error: " + JSON.stringify(err)); + Metrics.error(Metrics.ErrorType.OTHER, "RemoteControlApiError", "Error in Thunder RemoteControl unpair " + JSON.stringify(err), false, null) + reject(err); + }); + }); + } } diff --git a/accelerator-home-ui/src/screens/OtherSettingsScreens/FactoryResetConfirmationScreen.js b/accelerator-home-ui/src/screens/OtherSettingsScreens/FactoryResetConfirmationScreen.js index 730d7fb..fa94a09 100644 --- a/accelerator-home-ui/src/screens/OtherSettingsScreens/FactoryResetConfirmationScreen.js +++ b/accelerator-home-ui/src/screens/OtherSettingsScreens/FactoryResetConfirmationScreen.js @@ -211,7 +211,7 @@ export default class RebootConfirmationScreen extends Lightning.Component { try { localStorage.clear(); this.LOG("localStorage cleared successfully"); - } + } catch (err) { this.ERR("Error clearing localStorage: " + JSON.stringify(err)); } diff --git a/accelerator-home-ui/src/screens/RcInformationScreen.js b/accelerator-home-ui/src/screens/RcInformationScreen.js index 03fe522..d382a48 100644 --- a/accelerator-home-ui/src/screens/RcInformationScreen.js +++ b/accelerator-home-ui/src/screens/RcInformationScreen.js @@ -244,16 +244,16 @@ export default class RCInformationScreen extends Lightning.Component { this.tag("SwVersion.Value").text.text = `N/A` this.tag("BatteryPercent.Value").text.text = `N/A` this.tag("RCUName.Value").text.text = `N/A` - //RCApi.get().deactivate().catch(err=> { console.error("RCInformationScreen error:", err)}); } onStatusCB(cbData) { // getStatus response has 'success' property; notification payload does not have that. + // this.LOG("RCInformationScreen onStatusCB cbData:" + JSON.stringify(cbData)); if ((cbData !== undefined) && ("success" in cbData ? cbData.success : true)) { let cbDatastatus if (Array.isArray(cbData.status)) { cbDatastatus = cbData.status[0] || {}; - } + } else if (cbData.status && typeof cbData.status === 'object') { cbDatastatus = cbData.status; } @@ -283,14 +283,14 @@ export default class RCInformationScreen extends Lightning.Component { this.tag("BatteryPercent.Value").text.text = BatteryPercent this.tag("RCUName.Value").text.text = RemoteName } else { - if(cbDatastatus.pairingState != "SEARCHING" && cbDatastatus.pairingState != "PAIRING" ) { - for(let i=0;i { + if (cbDatastatus.pairingState === "IDLE" || cbDatastatus.pairingState === "FAILED") { + // after 2 seconds, initiate pairing flow if status is IDLE, as there is no paired device. + this.scanTrigger && Registry.clearTimeout(this.scanTrigger); + this.scanTrigger = Registry.setTimeout(() => { + RCApi.get().startPairing().catch(err => { this.ERR("RCInformationScreen startPairing error: " + JSON.stringify(err)); }); - } + }, 2000); } } } diff --git a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js index 847e366..afbb7b2 100644 --- a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js +++ b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js @@ -196,13 +196,13 @@ export default class BluetoothScreen extends Lightning.Component { } onStatusCB(cbData) { - //console.log("BluetoothScreen cbData:", JSON.stringify(cbData)); + //console.log("BluetoothScreen cbData:" + JSON.stringify(cbData)); // getStatus response has 'success' property; notification payload does not have that. if ((cbData !== undefined) && (cbData.hasOwnProperty("success") ? cbData.success : true)) { let cbDatastatus if (Array.isArray(cbData.status)) { cbDatastatus = cbData.status[0] || {}; - } + } else if (cbData.status && typeof cbData.status === 'object') { cbDatastatus = cbData.status; } @@ -226,14 +226,14 @@ export default class BluetoothScreen extends Lightning.Component { } }) } else { - if(cbDatastatus.pairingState != "SEARCHING" && cbDatastatus.pairingState != "PAIRING" ) { - for(let i=0;i { + if (cbDatastatus.pairingState === "IDLE" || cbDatastatus.pairingState === "FAILED") { + // after 2 seconds, initiate pairing flow if status is IDLE, as there is no paired device. + this.scanTrigger && Registry.clearTimeout(this.scanTrigger); + this.scanTrigger = Registry.setTimeout(() => { + RCApi.get().startPairing().catch(err => { this.ERR("RCInformationScreen startPairing error: " + JSON.stringify(err)); }); - } + }, 2000); } } } From 47df6367819c67c9bcab0a5ed99fa3007e976d99 Mon Sep 17 00:00:00 2001 From: Arun Madhavan Date: Thu, 2 Apr 2026 15:53:36 -0400 Subject: [PATCH 25/35] RDKEAPPRT-683: Fix the RCU pairing trigger timers --- accelerator-home-ui/src/api/RemoteControl.js | 6 +-- accelerator-home-ui/src/routes/routes.js | 2 +- .../src/screens/RcInformationScreen.js | 23 ++++++++---- .../screens/SplashScreens/BluetoothScreen.js | 37 +++++++++++-------- 4 files changed, 41 insertions(+), 27 deletions(-) diff --git a/accelerator-home-ui/src/api/RemoteControl.js b/accelerator-home-ui/src/api/RemoteControl.js index 158419e..0cb6978 100644 --- a/accelerator-home-ui/src/api/RemoteControl.js +++ b/accelerator-home-ui/src/api/RemoteControl.js @@ -94,8 +94,8 @@ export default class RCApi { startPairing(timeout = 30) { return new Promise((resolve, reject) => { - this.thunder.call('org.rdk.RemoteControl', 'startPairing', { timeout: timeout, screenBindEnable:false }).then(result => { - //this.INFO("RCApi: startPairing result: ", JSON.stringify(result)) + this.thunder.call('org.rdk.RemoteControl', 'startPairing', { timeout: timeout, screenBindEnable: false }).then(result => { + this.INFO("RCApi: startPairing result: " + JSON.stringify(result)) resolve(result.success); }).catch(err => { this.ERR("RCApi: startPairing error: " + JSON.stringify(err)); @@ -231,7 +231,7 @@ export default class RCApi { unpair(macAddressList) { return new Promise((resolve, reject) => { this.INFO("RCApi: unpair macAddressList:" + JSON.stringify(macAddressList)); - this.thunder.call('org.rdk.RemoteControl', 'unpair', { macAddressList: macAddressList }).then(result => { + this.thunder.call('org.rdk.RemoteControl', 'unpair', { macAddressList: macAddressList }).then(result => { this.INFO("RCApi: unpair result: " + JSON.stringify(result)) resolve(result.success); }).catch(err => { diff --git a/accelerator-home-ui/src/routes/routes.js b/accelerator-home-ui/src/routes/routes.js index 7f99815..dd67e76 100644 --- a/accelerator-home-ui/src/routes/routes.js +++ b/accelerator-home-ui/src/routes/routes.js @@ -207,7 +207,7 @@ export default { if ("ResidentApp" !== GLOBALS.selfClientName) { Metrics.page(request.hash) .then(success => { - console.log("successfully routed to page ==>", request.hash) + console.log("successfully routed to page ==>" + JSON.stringify(request.hash)) }) .catch(err => console.log("error in metrics.page", err)) } diff --git a/accelerator-home-ui/src/screens/RcInformationScreen.js b/accelerator-home-ui/src/screens/RcInformationScreen.js index d382a48..5b28250 100644 --- a/accelerator-home-ui/src/screens/RcInformationScreen.js +++ b/accelerator-home-ui/src/screens/RcInformationScreen.js @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. **/ -import { Lightning, Language, Router } from '@lightningjs/sdk' +import { Lightning, Language, Registry, Router } from '@lightningjs/sdk' import { COLORS } from './../colors/Colors' import { CONFIG } from '../Config/Config' import ThunderJS from 'ThunderJS' @@ -228,6 +228,7 @@ export default class RCInformationScreen extends Lightning.Component { } async _active() { + this.scanTrigger = null; await RCApi.get().activate().catch(err => { this.ERR("RCInformationScreen error: " + JSON.stringify(err)) }); await RCApi.get().getNetStatus().then(result => { this.INFO("RCInformationScreen getNetStatus: " + JSON.stringify(result)) @@ -244,6 +245,9 @@ export default class RCInformationScreen extends Lightning.Component { this.tag("SwVersion.Value").text.text = `N/A` this.tag("BatteryPercent.Value").text.text = `N/A` this.tag("RCUName.Value").text.text = `N/A` + if (this.scanTrigger) { + Registry.clearTimeout(this.scanTrigger); + } } onStatusCB(cbData) { @@ -282,15 +286,20 @@ export default class RCInformationScreen extends Lightning.Component { this.tag("SwVersion.Value").text.text = swVersion this.tag("BatteryPercent.Value").text.text = BatteryPercent this.tag("RCUName.Value").text.text = RemoteName + RCApi.get().findMyRemote().catch(err => { + this.ERR("RCInformationScreen findMyRemote error: " + JSON.stringify(err)) + }); } else { if (cbDatastatus.pairingState === "IDLE" || cbDatastatus.pairingState === "FAILED") { // after 2 seconds, initiate pairing flow if status is IDLE, as there is no paired device. - this.scanTrigger && Registry.clearTimeout(this.scanTrigger); - this.scanTrigger = Registry.setTimeout(() => { - RCApi.get().startPairing().catch(err => { - this.ERR("RCInformationScreen startPairing error: " + JSON.stringify(err)); - }); - }, 2000); + if (!this.scanTrigger) { + this.scanTrigger = Registry.setTimeout(() => { + RCApi.get().startPairing().catch(err => { + this.ERR("RCInformationScreen startPairing error: " + JSON.stringify(err)); + }); + this.scanTrigger = null; + }, 2000); + } } } } diff --git a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js index afbb7b2..c85d5b1 100644 --- a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js +++ b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js @@ -169,23 +169,22 @@ export default class BluetoothScreen extends Lightning.Component { Router.navigate('splash/language') } }) - }) - .catch(err => { - this.ERR(`SplashBluetoothScreen cant stopscan device : ${JSON.stringify(err)}`) - }) - }) .catch(err => { - this.ERR("SplashBluetoothScreen cant stopscan device : " + JSON.stringify(err)) + this.ERR(`SplashBluetoothScreen cant stopscan device : ${JSON.stringify(err)}`) }) }) .catch(err => { - this.ERR("SplashBluetoothScreen cant getpaired device : " + JSON.stringify(err)) + this.ERR("SplashBluetoothScreen cant stopscan device : " + JSON.stringify(err)) }) }) .catch(err => { - this.ERR(`SplashBluetoothScreen Can't pair device : ${JSON.stringify(err)}`) + this.ERR("SplashBluetoothScreen cant getpaired device : " + JSON.stringify(err)) }) + }) + .catch(err => { + this.ERR(`SplashBluetoothScreen Can't pair device : ${JSON.stringify(err)}`) + }) }) }) }) @@ -202,10 +201,10 @@ export default class BluetoothScreen extends Lightning.Component { let cbDatastatus if (Array.isArray(cbData.status)) { cbDatastatus = cbData.status[0] || {}; - } + } else if (cbData.status && typeof cbData.status === 'object') { cbDatastatus = cbData.status; - } + } if (cbDatastatus.remoteData.length) { //console.log("BluetoothScreen rcPairingApis RemoteData Length ", cbData.status.remoteData.length) cbDatastatus.remoteData.map(item => { @@ -228,12 +227,14 @@ export default class BluetoothScreen extends Lightning.Component { } else { if (cbDatastatus.pairingState === "IDLE" || cbDatastatus.pairingState === "FAILED") { // after 2 seconds, initiate pairing flow if status is IDLE, as there is no paired device. - this.scanTrigger && Registry.clearTimeout(this.scanTrigger); - this.scanTrigger = Registry.setTimeout(() => { - RCApi.get().startPairing().catch(err => { - this.ERR("RCInformationScreen startPairing error: " + JSON.stringify(err)); - }); - }, 2000); + if (!this.scanTrigger) { + this.scanTrigger = Registry.setTimeout(() => { + RCApi.get().startPairing().catch(err => { + this.ERR("SplashBluetoothScreen startPairing error: " + JSON.stringify(err)); + }); + this.scanTrigger = null; + }, 2000); + } } } } @@ -280,6 +281,7 @@ export default class BluetoothScreen extends Lightning.Component { _active() { this.initTimer() + this.scanTrigger = null; } pageTransition() { @@ -302,6 +304,9 @@ export default class BluetoothScreen extends Lightning.Component { if (this.RCTimeout) { Registry.clearTimeout(this.RCTimeout) } + if (this.scanTrigger) { + Registry.clearTimeout(this.scanTrigger) + } } static _states() { From 34ee6bea00a1aba71dcbc2e969ef5a6d22f2e94c Mon Sep 17 00:00:00 2001 From: Arun Madhavan Date: Thu, 2 Apr 2026 16:12:46 -0400 Subject: [PATCH 26/35] /RDKEAPPRT-683: stop the scan triggers after RCU pairing --- .../src/screens/RcInformationScreen.js | 17 ++++++++++++++--- .../screens/SplashScreens/BluetoothScreen.js | 14 ++++++++------ 2 files changed, 22 insertions(+), 9 deletions(-) diff --git a/accelerator-home-ui/src/screens/RcInformationScreen.js b/accelerator-home-ui/src/screens/RcInformationScreen.js index 5b28250..e1afd8e 100644 --- a/accelerator-home-ui/src/screens/RcInformationScreen.js +++ b/accelerator-home-ui/src/screens/RcInformationScreen.js @@ -235,6 +235,7 @@ export default class RCInformationScreen extends Lightning.Component { onStatusCBhandle = _thunder.on('org.rdk.RemoteControl', 'onStatus', data => { this.onStatusCB(data) }); this.onStatusCB(result); }).catch(err => this.ERR("RCInformationScreen error: " + JSON.stringify(err))); + this.findRemoteTrigger = true; } _inactive() { @@ -247,7 +248,9 @@ export default class RCInformationScreen extends Lightning.Component { this.tag("RCUName.Value").text.text = `N/A` if (this.scanTrigger) { Registry.clearTimeout(this.scanTrigger); + this.scanTrigger = null; } + this.findRemoteTrigger = false; } onStatusCB(cbData) { @@ -286,9 +289,12 @@ export default class RCInformationScreen extends Lightning.Component { this.tag("SwVersion.Value").text.text = swVersion this.tag("BatteryPercent.Value").text.text = BatteryPercent this.tag("RCUName.Value").text.text = RemoteName - RCApi.get().findMyRemote().catch(err => { - this.ERR("RCInformationScreen findMyRemote error: " + JSON.stringify(err)) - }); + if (this.findRemoteTrigger) { + this.findRemoteTrigger = false; + RCApi.get().findMyRemote().catch(err => { + this.ERR("RCInformationScreen findMyRemote error: " + JSON.stringify(err)) + }); + } } else { if (cbDatastatus.pairingState === "IDLE" || cbDatastatus.pairingState === "FAILED") { // after 2 seconds, initiate pairing flow if status is IDLE, as there is no paired device. @@ -300,6 +306,11 @@ export default class RCInformationScreen extends Lightning.Component { this.scanTrigger = null; }, 2000); } + } else if (cbDatastatus.pairingState === "COMPLETE") { + if (this.scanTrigger) { + Registry.clearTimeout(this.scanTrigger); + this.scanTrigger = null; + } } } } diff --git a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js index c85d5b1..79d3021 100644 --- a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js +++ b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js @@ -135,10 +135,6 @@ export default class BluetoothScreen extends Lightning.Component { } } - _active() { - this.timeout = 30; - } - _PairingApis() { //bluetoothApi.btactivate().then(enableResult =>{ // console.log('1') @@ -175,11 +171,11 @@ export default class BluetoothScreen extends Lightning.Component { }) }) .catch(err => { - this.ERR("SplashBluetoothScreen cant stopscan device : " + JSON.stringify(err)) + this.ERR("SplashBluetoothScreen getpairedDevices failed : " + JSON.stringify(err)) }) }) .catch(err => { - this.ERR("SplashBluetoothScreen cant getpaired device : " + JSON.stringify(err)) + this.ERR("SplashBluetoothScreen getConnectedDevices failed : " + JSON.stringify(err)) }) }) .catch(err => { @@ -235,6 +231,11 @@ export default class BluetoothScreen extends Lightning.Component { this.scanTrigger = null; }, 2000); } + } else if (cbDatastatus.pairingState === "COMPLETE") { + if (this.scanTrigger) { + Registry.clearTimeout(this.scanTrigger); + this.scanTrigger = null; + } } } } @@ -280,6 +281,7 @@ export default class BluetoothScreen extends Lightning.Component { } _active() { + this.timeout = 30; this.initTimer() this.scanTrigger = null; } From 2610642a37e0d975cfb59ac9d5d4aa498ae4a115 Mon Sep 17 00:00:00 2001 From: Arun Madhavan Date: Thu, 2 Apr 2026 19:20:30 -0400 Subject: [PATCH 27/35] RDKEAPPRT-683: fix the RCU re scanning logic leak. --- accelerator-home-ui/src/App.js | 8 ++++- .../src/screens/RcInformationScreen.js | 29 ++++++++++++++++--- .../screens/SplashScreens/BluetoothScreen.js | 27 ++++++++++++++--- 3 files changed, 55 insertions(+), 9 deletions(-) diff --git a/accelerator-home-ui/src/App.js b/accelerator-home-ui/src/App.js index 6a10881..c39a543 100644 --- a/accelerator-home-ui/src/App.js +++ b/accelerator-home-ui/src/App.js @@ -276,6 +276,12 @@ export default class App extends Router.App { if(GLOBALS.MiracastNotificationstatus && key.keyCode !== Keymap.Power && key.keyCode !== Keymap.Home ){ return false } else if ((key.keyCode == Keymap.Home || key.keyCode == Keymap.Escape) && !Router.isNavigating()) { + if (Router.getActiveHash().startsWith("splash")) { + if (Router.getActiveHash() !== "splash/language") { + Router.navigate("splash/language"); + } + return true; + } if (GLOBALS.topmostApp.includes("dac.native")) { this.jumpToRoute("apps"); } else if (GLOBALS.Miracastclientdevicedetails.state === "INITIATED" || GLOBALS.Miracastclientdevicedetails.state === "INPROGRESS ") { @@ -2868,4 +2874,4 @@ export default class App extends Router.App { } } } -} \ No newline at end of file +} diff --git a/accelerator-home-ui/src/screens/RcInformationScreen.js b/accelerator-home-ui/src/screens/RcInformationScreen.js index e1afd8e..ef9b666 100644 --- a/accelerator-home-ui/src/screens/RcInformationScreen.js +++ b/accelerator-home-ui/src/screens/RcInformationScreen.js @@ -269,6 +269,11 @@ export default class RCInformationScreen extends Lightning.Component { let RemoteName = []; let connectedStatus = []; let MacAddress = []; let swVersion = []; let BatteryPercent = []; + if (this.scanTrigger) { + Registry.clearTimeout(this.scanTrigger); + this.scanTrigger = null; + } + cbDatastatus.remoteData.map(item => { RemoteName.push(item.name) }) @@ -300,13 +305,29 @@ export default class RCInformationScreen extends Lightning.Component { // after 2 seconds, initiate pairing flow if status is IDLE, as there is no paired device. if (!this.scanTrigger) { this.scanTrigger = Registry.setTimeout(() => { - RCApi.get().startPairing().catch(err => { - this.ERR("RCInformationScreen startPairing error: " + JSON.stringify(err)); - }); this.scanTrigger = null; + RCApi.get().getNetStatus().then(result => { + let latestStatus = {}; + if (Array.isArray(result.status)) { + latestStatus = result.status[0] || {}; + } else if (result.status && typeof result.status === 'object') { + latestStatus = result.status; + } + + const latestHasRemoteData = Array.isArray(latestStatus.remoteData) && latestStatus.remoteData.length; + const latestInRetryState = latestStatus.pairingState === "IDLE" || latestStatus.pairingState === "FAILED"; + + if (!latestHasRemoteData && latestInRetryState) { + RCApi.get().startPairing().catch(err => { + this.ERR("RCInformationScreen startPairing error: " + JSON.stringify(err)); + }); + } + }).catch(err => { + this.ERR("RCInformationScreen getNetStatus before startPairing error: " + JSON.stringify(err)); + }); }, 2000); } - } else if (cbDatastatus.pairingState === "COMPLETE") { + } else { if (this.scanTrigger) { Registry.clearTimeout(this.scanTrigger); this.scanTrigger = null; diff --git a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js index 79d3021..6ae14c5 100644 --- a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js +++ b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js @@ -203,6 +203,10 @@ export default class BluetoothScreen extends Lightning.Component { } if (cbDatastatus.remoteData.length) { //console.log("BluetoothScreen rcPairingApis RemoteData Length ", cbData.status.remoteData.length) + if (this.scanTrigger) { + Registry.clearTimeout(this.scanTrigger); + this.scanTrigger = null; + } cbDatastatus.remoteData.map(item => { this.tag('Info').text.text = `paired with device ${item.name}` // Do not clear this.RCTimeout if need to run this in background to reconnect on loss. @@ -225,13 +229,28 @@ export default class BluetoothScreen extends Lightning.Component { // after 2 seconds, initiate pairing flow if status is IDLE, as there is no paired device. if (!this.scanTrigger) { this.scanTrigger = Registry.setTimeout(() => { - RCApi.get().startPairing().catch(err => { - this.ERR("SplashBluetoothScreen startPairing error: " + JSON.stringify(err)); - }); this.scanTrigger = null; + RCApi.get().getNetStatus().then(result => { + let latestStatus = {}; + if (Array.isArray(result.status)) { + latestStatus = result.status[0] || {}; + } else if (result.status && typeof result.status === 'object') { + latestStatus = result.status; + } + + const latestHasRemoteData = Array.isArray(latestStatus.remoteData) && latestStatus.remoteData.length; + const latestInRetryState = latestStatus.pairingState === "IDLE" || latestStatus.pairingState === "FAILED"; + if (!latestHasRemoteData && latestInRetryState) { + RCApi.get().startPairing().catch(err => { + this.ERR("SplashBluetoothScreen startPairing error: " + JSON.stringify(err)); + }); + } + }).catch(err => { + this.ERR("SplashBluetoothScreen getNetStatus before startPairing error: " + JSON.stringify(err)); + }); }, 2000); } - } else if (cbDatastatus.pairingState === "COMPLETE") { + } else { if (this.scanTrigger) { Registry.clearTimeout(this.scanTrigger); this.scanTrigger = null; From 791331733db5b5f9876c86bd2f2ab324f7254060 Mon Sep 17 00:00:00 2001 From: Arun Madhavan Date: Thu, 2 Apr 2026 19:30:00 -0400 Subject: [PATCH 28/35] RDKEAPPRT-683: fix the alignment issue - this change is introduced to fix the accidental route happening to menu page when RCU key is received from FTU --- accelerator-home-ui/src/App.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/accelerator-home-ui/src/App.js b/accelerator-home-ui/src/App.js index c39a543..2bac5cd 100644 --- a/accelerator-home-ui/src/App.js +++ b/accelerator-home-ui/src/App.js @@ -276,12 +276,12 @@ export default class App extends Router.App { if(GLOBALS.MiracastNotificationstatus && key.keyCode !== Keymap.Power && key.keyCode !== Keymap.Home ){ return false } else if ((key.keyCode == Keymap.Home || key.keyCode == Keymap.Escape) && !Router.isNavigating()) { - if (Router.getActiveHash().startsWith("splash")) { - if (Router.getActiveHash() !== "splash/language") { - Router.navigate("splash/language"); - } - return true; - } + if (Router.getActiveHash().startsWith("splash")) { + if (Router.getActiveHash() !== "splash/language") { + Router.navigate("splash/language"); + } + return true; + } if (GLOBALS.topmostApp.includes("dac.native")) { this.jumpToRoute("apps"); } else if (GLOBALS.Miracastclientdevicedetails.state === "INITIATED" || GLOBALS.Miracastclientdevicedetails.state === "INPROGRESS ") { From 8add25c150df64f3f9a749d40fe25bbd37466336 Mon Sep 17 00:00:00 2001 From: Arun Madhavan Date: Thu, 2 Apr 2026 19:35:26 -0400 Subject: [PATCH 29/35] RDKEAPPRT-683: fix typos and cleanup sequence --- accelerator-home-ui/src/screens/RcInformationScreen.js | 2 +- .../src/screens/SplashScreens/BluetoothScreen.js | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/accelerator-home-ui/src/screens/RcInformationScreen.js b/accelerator-home-ui/src/screens/RcInformationScreen.js index ef9b666..565303b 100644 --- a/accelerator-home-ui/src/screens/RcInformationScreen.js +++ b/accelerator-home-ui/src/screens/RcInformationScreen.js @@ -229,13 +229,13 @@ export default class RCInformationScreen extends Lightning.Component { async _active() { this.scanTrigger = null; + this.findRemoteTrigger = true; await RCApi.get().activate().catch(err => { this.ERR("RCInformationScreen error: " + JSON.stringify(err)) }); await RCApi.get().getNetStatus().then(result => { this.INFO("RCInformationScreen getNetStatus: " + JSON.stringify(result)) onStatusCBhandle = _thunder.on('org.rdk.RemoteControl', 'onStatus', data => { this.onStatusCB(data) }); this.onStatusCB(result); }).catch(err => this.ERR("RCInformationScreen error: " + JSON.stringify(err))); - this.findRemoteTrigger = true; } _inactive() { diff --git a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js index 6ae14c5..7f466e9 100644 --- a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js +++ b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js @@ -167,7 +167,7 @@ export default class BluetoothScreen extends Lightning.Component { }) }) .catch(err => { - this.ERR(`SplashBluetoothScreen cant stopscan device : ${JSON.stringify(err)}`) + this.ERR(`SplashBluetoothScreen can't stop scan device : ${JSON.stringify(err)}`) }) }) .catch(err => { @@ -327,6 +327,7 @@ export default class BluetoothScreen extends Lightning.Component { } if (this.scanTrigger) { Registry.clearTimeout(this.scanTrigger) + this.scanTrigger = null; } } From 65ec43f96a03810de3254fe283819d5a692d01b9 Mon Sep 17 00:00:00 2001 From: Arun Madhavan Date: Thu, 2 Apr 2026 19:42:16 -0400 Subject: [PATCH 30/35] RDKEAPPRT-683: initialize the var declared --- .../src/screens/SplashScreens/BluetoothScreen.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js index 7f466e9..1672f6d 100644 --- a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js +++ b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js @@ -194,7 +194,7 @@ export default class BluetoothScreen extends Lightning.Component { //console.log("BluetoothScreen cbData:" + JSON.stringify(cbData)); // getStatus response has 'success' property; notification payload does not have that. if ((cbData !== undefined) && (cbData.hasOwnProperty("success") ? cbData.success : true)) { - let cbDatastatus + let cbDatastatus = {}; if (Array.isArray(cbData.status)) { cbDatastatus = cbData.status[0] || {}; } From 641dae2c82efa4a64bbc7e54ddb61db6d54236c9 Mon Sep 17 00:00:00 2001 From: Arun Madhavan Date: Thu, 2 Apr 2026 20:05:40 -0400 Subject: [PATCH 31/35] fix(bluetooth-splash): prevent scanTrigger timer race across init/active lifecycle --- .../src/screens/SplashScreens/BluetoothScreen.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js index 1672f6d..bafc50e 100644 --- a/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js +++ b/accelerator-home-ui/src/screens/SplashScreens/BluetoothScreen.js @@ -35,6 +35,7 @@ export default class BluetoothScreen extends Lightning.Component { this.LOG = console.log; this.ERR = console.error; this.WARN = console.warn; + this.scanTrigger = null; } static _template() { @@ -201,13 +202,14 @@ export default class BluetoothScreen extends Lightning.Component { else if (cbData.status && typeof cbData.status === 'object') { cbDatastatus = cbData.status; } - if (cbDatastatus.remoteData.length) { + const remoteData = Array.isArray(cbDatastatus.remoteData) ? cbDatastatus.remoteData : []; + if (remoteData.length > 0) { //console.log("BluetoothScreen rcPairingApis RemoteData Length ", cbData.status.remoteData.length) if (this.scanTrigger) { Registry.clearTimeout(this.scanTrigger); this.scanTrigger = null; } - cbDatastatus.remoteData.map(item => { + remoteData.map(item => { this.tag('Info').text.text = `paired with device ${item.name}` // Do not clear this.RCTimeout if need to run this in background to reconnect on loss. // if (this.RCTimeout) { @@ -302,7 +304,9 @@ export default class BluetoothScreen extends Lightning.Component { _active() { this.timeout = 30; this.initTimer() - this.scanTrigger = null; + if (typeof this.scanTrigger === 'undefined') { + this.scanTrigger = null; + } } pageTransition() { From ad290b1fe7f3dbb1754be2dfaf085afeb3db47d3 Mon Sep 17 00:00:00 2001 From: suryag23 Date: Tue, 7 Apr 2026 12:37:44 +0530 Subject: [PATCH 32/35] RDKEAPPRT-687 Changelog updates for 6.0.2 Signed-off-by: suryag23 --- CHANGELOG.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6afee9f..5951c6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,21 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [6.0.2](https://github.com/rdkcentral/rdke-refui/compare/6.0.1...6.0.2) + +- RDKEAPPRT-683: RemoteControl plugin API align with MW APIv3.4.2 [`#171`](https://github.com/rdkcentral/rdke-refui/pull/171) +- RDKEAPPRT-683: Fix the RCU pairing trigger timers [`47df636`](https://github.com/rdkcentral/rdke-refui/commit/47df6367819c67c9bcab0a5ed99fa3007e976d99) +- RDKEAPPRT-683: fix the RCU re scanning logic leak. [`2610642`](https://github.com/rdkcentral/rdke-refui/commit/2610642a37e0d975cfb59ac9d5d4aa498ae4a115) +- /RDKEAPPRT-683: stop the scan triggers after RCU pairing [`34ee6be`](https://github.com/rdkcentral/rdke-refui/commit/34ee6bea00a1aba71dcbc2e969ef5a6d22f2e94c) + #### [6.0.1](https://github.com/rdkcentral/rdke-refui/compare/6.0.0...6.0.1) +> 31 March 2026 + - Feature/rdkeapprt 680 :Update to new RDK logos [`#168`](https://github.com/rdkcentral/rdke-refui/pull/168) +- RDKEAPPRT-682 Changelog and package config version updates for 6.0.1 [`32bbba6`](https://github.com/rdkcentral/rdke-refui/commit/32bbba6f7cde97607cac613f80240a174073c6bf) - RDKEAPPRT-680 :Update new logo [`83513d8`](https://github.com/rdkcentral/rdke-refui/commit/83513d8d0566d994927583ed7891c655660af97f) - RDKEAPPRT-680:Update the new logo files [`c2b261f`](https://github.com/rdkcentral/rdke-refui/commit/c2b261ff1ea9e4e72a8750f77652d6f4261775ce) -- Merge tag '6.0.0' into develop [`ff076c2`](https://github.com/rdkcentral/rdke-refui/commit/ff076c212491ba05e68f118666581d41d474f8d3) ### [6.0.0](https://github.com/rdkcentral/rdke-refui/compare/5.0.24...6.0.0) From 416c1b35a9b459a6766870964a15de49ad0d246b Mon Sep 17 00:00:00 2001 From: suryag23 <141610966+suryag23@users.noreply.github.com> Date: Tue, 7 Apr 2026 16:18:34 +0530 Subject: [PATCH 33/35] Updated the version for refui boltpackage (#175) * Updated the version for refui boltpackage * Updated the version as 6.0.3 --- accelerator-home-ui/settings.json | 2 +- bolt/package-configs/com.rdkcentral.refui.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/accelerator-home-ui/settings.json b/accelerator-home-ui/settings.json index 624fba0..4c683aa 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.2" + "version": "6.0.3" } } diff --git a/bolt/package-configs/com.rdkcentral.refui.json b/bolt/package-configs/com.rdkcentral.refui.json index b414e0e..0dc94e8 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.1", - "versionName": "6.0.1", + "version": "6.0.3", + "versionName": "6.0.3", "name": "RDK Ref UI Home Screen", "packageType": "application", "entryPoint": "--lightning --dev file:///usr/share/refui/index.html", From a64ad5142fef9c1341028d211ade283bb8d58f5b Mon Sep 17 00:00:00 2001 From: suryag23 Date: Tue, 7 Apr 2026 16:41:30 +0530 Subject: [PATCH 34/35] RDKEAPPRT-688 Changelog updates for 6.0.3 Signed-off-by: suryag23 --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5951c6e..6b35ff0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,8 +4,15 @@ All notable changes to this project will be documented in this file. Dates are d Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +#### [6.0.3](https://github.com/rdkcentral/rdke-refui/compare/6.0.2...6.0.3) + +- Updated the version for refui boltpackage [`#175`](https://github.com/rdkcentral/rdke-refui/pull/175) +- Merge tag '6.0.2' into develop [`7d4582c`](https://github.com/rdkcentral/rdke-refui/commit/7d4582c752991e63442df51fecbaf152e355e4c5) + #### [6.0.2](https://github.com/rdkcentral/rdke-refui/compare/6.0.1...6.0.2) +> 7 April 2026 + - RDKEAPPRT-683: RemoteControl plugin API align with MW APIv3.4.2 [`#171`](https://github.com/rdkcentral/rdke-refui/pull/171) - RDKEAPPRT-683: Fix the RCU pairing trigger timers [`47df636`](https://github.com/rdkcentral/rdke-refui/commit/47df6367819c67c9bcab0a5ed99fa3007e976d99) - RDKEAPPRT-683: fix the RCU re scanning logic leak. [`2610642`](https://github.com/rdkcentral/rdke-refui/commit/2610642a37e0d975cfb59ac9d5d4aa498ae4a115) From c638591de6b2761d28262843ceee2416e8a55943 Mon Sep 17 00:00:00 2001 From: suryag23 <141610966+suryag23@users.noreply.github.com> Date: Thu, 9 Apr 2026 17:17:24 +0530 Subject: [PATCH 35/35] RDKMVE-2127 From Ref UI Home screen, Pressing Volume +/- leads to UI blank in the display (#180) --- accelerator-home-ui/settings.json | 2 +- accelerator-home-ui/src/App.js | 42 +++---------------------------- 2 files changed, 4 insertions(+), 40 deletions(-) diff --git a/accelerator-home-ui/settings.json b/accelerator-home-ui/settings.json index 4c683aa..90202c2 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.3" + "version": "6.0.4" } } diff --git a/accelerator-home-ui/src/App.js b/accelerator-home-ui/src/App.js index 2bac5cd..9058ae4 100644 --- a/accelerator-home-ui/src/App.js +++ b/accelerator-home-ui/src/App.js @@ -395,60 +395,24 @@ export default class App extends Router.App { // Remote power key and keyboard F1 key used for STANDBY and POWER_ON return this._powerKeyPressed() } else if (key.keyCode === Keymap.AudioVolumeMute && !Router.isNavigating()) { - if (GLOBALS.topmostApp === GLOBALS.selfClientName) { + if (GLOBALS.topmostApp === GLOBALS.selfclientAppName) { this.tag("Volume").onVolumeMute(); } else { this.LOG("muting on some app") - if (Router.getActiveHash() === "applauncher") { - this.LOG("muting on some app while route is app launcher") - RDKShellApis.moveToFront(GLOBALS.selfClientName) - RDKShellApis.setVisibility(GLOBALS.selfClientName, true) - this.tag("Volume").onVolumeMute(); - } else { - this.LOG("muting on some app while route is NOT app launcher") - RDKShellApis.moveToFront(GLOBALS.selfClientName) - RDKShellApis.setVisibility(GLOBALS.selfClientName, true) - Router.navigate("applauncher"); - this.tag("Volume").onVolumeMute(); - } } return true } else if (key.keyCode == Keymap.AudioVolumeUp && !Router.isNavigating()) { - if (GLOBALS.topmostApp === GLOBALS.selfClientName) { + if (GLOBALS.topmostApp === GLOBALS.selfclientAppName) { this.tag("Volume").onVolumeKeyUp(); } else { this.LOG("muting on some app") - if (Router.getActiveHash() === "applauncher") { - this.LOG("muting on some app while route is app launcher") - RDKShellApis.moveToFront(GLOBALS.selfClientName) - RDKShellApis.setVisibility(GLOBALS.selfClientName, true) - this.tag("Volume").onVolumeKeyUp(); - } else { - this.LOG("muting on some app while route is NOT app launcher") - RDKShellApis.moveToFront(GLOBALS.selfClientName) - RDKShellApis.setVisibility(GLOBALS.selfClientName, true) - Router.navigate("applauncher"); - this.tag("Volume").onVolumeKeyUp(); - } } return true } else if (key.keyCode == Keymap.AudioVolumeDown && !Router.isNavigating()) { - if (GLOBALS.topmostApp === GLOBALS.selfClientName) { + if (GLOBALS.topmostApp === GLOBALS.selfclientAppName) { this.tag("Volume").onVolumeKeyDown(); } else { this.LOG("muting on some app") - if (Router.getActiveHash() === "applauncher") { - this.LOG("muting on some app while route is app launcher") - RDKShellApis.moveToFront(GLOBALS.selfClientName) - RDKShellApis.setVisibility(GLOBALS.selfClientName, true) - this.tag("Volume").onVolumeKeyDown(); - } else { - this.LOG("muting on some app while route is NOT app launcher") - RDKShellApis.moveToFront(GLOBALS.selfClientName) - RDKShellApis.setVisibility(GLOBALS.selfClientName, true) - Router.navigate("applauncher"); - this.tag("Volume").onVolumeKeyDown(); - } } return true } else {